[iOS] Swift - 프로토콜 지향 프로그래밍

2021. 11. 1. 22:06iOS

들어가기에 앞서,

https://lawrey.medium.com/swift-protocol-oriented-programming-pop-ceef8e2b7cca 를 번역한 것임을 밝힙니다.

의역이나 오역이 있을 수 있습니다.

 

Swift Protocol Oriented Programming (POP) #1

Swift have come a long way coming out with great syntax that allows us to make our code very readable. In our day-to-day development…

lawrey.medium.com

 

스위프트는 가독성 좋은 코드를 쉽게 만들 수 있게 나온 언어입니다.

하지만 오늘날 우리들은 촉박한 개발일정에 있어서 두 가지 선택지 사이의 딜레마를 경험하게 됩니다.

 

1. 리팩토링을 통해서 가독성을 높이느냐

2. 아니면, 코드를 추가해서 시간내에 프로젝트를 출시하느냐

 

첫번째 옵션은 여러분들의 매니저에게 더 많은 개발시간을 요청하게 만들겠지만 나중에 혜택을 누릴수 있겠지요.

두번째 옵션은 지금 당장 개발일정을 맞출 수 있어 좋은 평판을 받을 수는 있겠지만 아주 가까운 미래에 욕을 얻어먹을수 있습니다.

 

유명한 책인 클린아키텍쳐에서는 "코드 품질을 저하시키지 않고 항상 기능을 제공해야 한다"는 원칙을 제시합니다.

마치 우리가 아이들에게 위생관념을 가르치는 것처럼, 우리도 코드베이스에서의 위생관념을 길러야 합니다.

 

바로 프로토콜 지향 프로그래밍(Protocol Oriented Programing) 을 통해서 말이죠!

 

이제 프로토콜 지향 프로그래밍을 통해서 우리의 코드를 더욱 가독성 있고 재사용 가능하고 깔끔하게 만들 수 있는지 간단한 예제를 통해서 설명해보도록 하겠습니다.

 

클래스들만이 프로토콜 지향 프로그래밍을 활용할 수 있는데, 왜냐하면 클래스는 모든 프로토콜들의 부모클래스인 NSObjectProtocol 을 준수하기 때문이죠.

 

Developer 클래스가 있습니다.

class Developer {
    var name: String?
    
    init(name: String) {
        self.name = name
    }
}

 

그리고

DevelopableInSwift 프로토콜이 있습니다.

protocol DevelopableInSwift { }

 

그 다음,

Developer의 자식 클래스 iOSDeveloper 를 만들고 역할을 부여해봅시다.

class iOSDeveloper:Developer, DevelopableInSwift { }

 

그리고

extension을 이용해 프로토콜의 함수를 생성합시다.

 

where Self: iOSDeveloper 은 제네릭 특수화로,

iOSDeveloper 클래스만 extension DevelopableInSwift 프로토콜을 구현할 수 있다는 의미입니다.

extension DevelopableInSwift where Self: iOSDeveloper {
    func useGuard() { }
}

 

그러면 다음과 같이 사용할 수 있게 됩니다.

class ViewController: UIViewController {
    var developer: Developer {
        return iOSDeveloper(name: "Lawrey")
    }
    
    override func viewDidLoad() {
        if developer is DevelopableInSwift,
           let iOSDev = developer as? iOSDeveloper {
               
            print("I am an iOS Developer!")
            iOSDev.useGuard()
        }
    }
}

let viewController = ViewController()
viewController.viewDidLoad()

이제 위 코드를 보면 코드의 의도를 쉽게 파악할 수 있습니다. iOSDeveloper 인스턴스가 생성되면 이를 통해 DevelopableInSwift 프로토콜의 재사용가능한 메소드들을 프로젝트 전체에서 사용가능하게 됩니다.

 

만약에 갑자기 여러분의 매니저가 AndroidDeveloper에 대한 기능도 필요하다고 해도 문제없습니다. 

 

새로운 프로토콜을 정의하고

Developer의 새로운 자식클래스가 이를 상속하게 만든다음,

protocol DevelopableInKotlin { }
class AndroidDeveloper:Developer, DevelopableInKotlin { }

 

제네릭 특수화를 이용해서 이 프로토콜의 함수를 아까 만든 자식클래스만이 사용하게 구현합시다.

extension DevelopableInKotlin where Self: AndroidDeveloper {
    func isNullSafe() -> Bool { return true }
}

 

전체코드는 다음과 같습니다.

import UIKit

class Developer {
    var name: String?
    
    init(name: String) {
        self.name = name
    }
}

protocol DevelopableInSwift { }
protocol DevelopableInKotlin { }

class iOSDeveloper:Developer, DevelopableInSwift { }
class AndroidDeveloper:Developer, DevelopableInKotlin { }

extension DevelopableInSwift where Self: iOSDeveloper {
    func useGuard() { }
}

extension DevelopableInKotlin where Self: AndroidDeveloper {
    func isNullSafe() -> Bool { return true }
}

class ViewController: UIViewController {
    
    var developer: Developer {
        return AndroidDeveloper(name: "Lawrey")
    }
    
    override func viewDidLoad() {
        if developer is DevelopableInSwift,
            let iOSDev = developer as? iOSDeveloper {
            print("I am an iOS Developer!")
            iOSDev.useGuard()
        } else if developer is DevelopableInKotlin,
            let androidDev = developer as? AndroidDeveloper {
            print("I am an Android Developer!")
            androidDev.isNullSafe()
        }
    }
}

let viewController = ViewController()
viewController.viewDidLoad()

 

결론적으로 프로토콜 지향 프로그래밍은 우리 코드를 더욱 가독성 좋고 작성하기 재미있게 만듭니다. 

 

위의 예제들은 프로토콜 지향 프로그래밍을 구현하는 수많은 방법중의 하나일 뿐입니다. 이러한 접근방법으로 시작하는 여러분들은 프로젝트가 확장되면서 필연적으로 따라오는 유지보수 비용을 보다 원활하고 편리하게 할 수 있을 것입니다.

 

 

 

-