#2: 이번이 제 첫번째 토크인데요.. 오늘 뭐에 대해서 예기를 할지 많은 고민을 했습니다.
그런데, 아무리 많은 생각을 해 봐도 **NEXT**
#4: WWDC 2015에서 발표된 유명한 Introduction to pop 토크에서 Swift STL 만드시는 분이 스위프트는 첫번쩨 POP이다.. 라는 발언을 하는 장면입니다. 일단 *POP이 너무 길어서 그냥 "팝"이라고 부르겠습니다.*
뭐 Go 같은 언어들도 있기 때문에 이거에 100% 동의는 못하갰지만 그 당시에는 매우 큰 화제였죠.
이 토크가 나왔을때 회사에서 다른 iOS 개발자들이랑 이 영상을 봤는데, 다 보고나서 만들고 있는 어플의 코드를 갈아 엎을 정도였습니다.
그러면, 토크의 주제가 Protocol인 만큼 Protocol이 뭔지 설명을 해야되는데요.. 여기 계신 분들은 protocol이 뭔지 잘 아시갰지만 만약 모르시는 분들을 위해 매운 간단하게 Protocol이 뭔지 설명하겠습니다.
#5: X 가 어디서 뭐를 상속하고 super가 뭔지 걱정하는 대신 X 가 뭐를 할 수 있는가에 집중하는 건데요...
그러면 이 아이디어를 어떻게 프로그래밍 언어 안에서 표현을 할까요?
뭐, 그거는 언어마다 다르겠죠...
Haskell에서는 type class를 사용하고 C++에서는 어설픈 virtual을 쓰겠죠. 그런데 대부분의 언어들은 Interface라는 거를 사용하죠. Swift도 interface랑 비슷한 것을 사용하는데 이름을 protocol이라고 붇친겁니다.
그러면 이 아이디어를 조금더 자세하게 표현을 하면... **NEXT**
#6: 프로토콜은 함수/정수를 제공한다는 약속이라고 말 할 수 있는데요...
정의만 보고 이해하기는 어려우니까 예제를 한번 보겠습니다 **NEXT**
#7: OOP에서 Charizard (또는 리자몽)을 만들라면 이런 상속관계를 만들어야되는죠.
엄청 큰 Pokemon 클레스를 parent로 하고 여러 종족들이 거기서 상속을 받는 경우인데..
OOP에서는 한 개의 클레스에서만 상속을 받을 수 있기 때문에 갑작이 디자이너가 와서 Charizard 한테 물 Pokemon의 기능도 추가 해달라고 하면 골치가 아프겠죠
그런데 Charizard가 할 수 있는 능력만을 생각하면서 Protocol을 사용하면 보기 쉽고 또한 사용하기도 쉬운 구조를 구축할수가 있습니다.
#8: 그리고 나중에 디자이너가 와서 Charizard를 희귀 Pokemon으로 만들고 싶다 해도 쉽게 코드로 반영을 할 수 있구요 **NEXT**
#11: 뭐 지금까진 말한거만 보면 protocol이 엄청 대단하고 몇 10년 동안 사용해왔던 OOP의 생각 구조를 완전희 구 시대 상상처럼 만들 수 있는거 처럼 들리죠.
그리고 사실상 그랬죠…
Swift를 3-4년간 POP이라는 가능을 간판으로 만들어 놓면서 엄청 성공을 했죠
#12: 인터넷에 POP을 검색하면 "Protocol oriented " 어쩌고 저쩌고 라고 하는 튜토리얼들이 거의 Haskell Monad 튜토리얼 처럼 엄청나게 많죠.
#13: 그리고 나중에는 Github에 POP을 라이버리의 기능 중 하나라고 내새우는 경우도 생겼죠...
#14: 그런데 갑작히 이런 코드가 Github에 나타났는데요...
여기서 protocol을 사용하면서 얻는 이득이 뭘까요?
Protocol을 없세고 `urlString`을 parameter로 직접 주는거랑 차이가 거이 없잫아요.
그런데.. 이렇게 이해가 않가는 코드들도 있지만 애매한 코드들도 있습니다.
#15: 함수가 딱 하나있는 protocol인데요... 여기에서도 protocol을 없세고 함수를 직접 넘겨주면 더 간단하겠죠.
다만 class-only protocol일 경우 weak reference를 쉽게 할 수 있게 protocol를 사용하는 나쁘지 않은 방법이지만....
이런 케이스가 아니먼 간단하게 type 대신 value를 넘겨 주는게 더 간단한데 왜 이런 코드들이 많이 나타나는 걸까요??
#16: 블로그들에서 많이 나타나는 문장인데요..
이런 글들이 많아 지면서 신선한 방법들도 많이 나왔지만 사람들에게 POP 대세이기 때문에 protocol을 사용하면 뭔가 스위프트 다운 코딩을 하고 있다는 느낌을 들게 하죠.
예를 들어볼깨요. UI를 쉽게 만들 수 있는 엄청 간단한 library를 반들어보겠습니다.
그리고 swift니까 protocol을 먼저 만들어 보겠습니다.
#17: `setHeader`에 `Content`를 주면 이 protocol를 구현한 UI에 정보를 쉽게 입력 할 수 있는 라이버리인데요…
associtedtype은 스위프트에서 generic protocol을 만드는 방법인데요
#18: 3가지 UI에 반영하면 다음과 같은데요
이제 `UICollectionView`에 방금 만든 UI를 넣기 위해서 배열을 만들어 보겠습니다 **NEXT**
#19: Swift의 강점인 type safety가 없어졌네요...
여기서 당황하지 않고 제가 원하는 것은 `HeaderViewProtocol` 배열이라는 것을 표현해주는데요...
#20: 이 에러 엄청 많이 보셨을겁니다.
말하는 대로 `associatedtype`이 있는 protocol은 generic 함수의 constraint로만 사용될 수 있어서 에러가 나는거입니다.
Swift 4 에서는 & 사인을 사용해서 타입을 만들때 클래스와 프로토콜을 썩어서 사용할 수 있지만 swift 3에서는 Type Eraser을 만들어야되는데요…
코드로 보면…
#21: 간단하게 type을 감싸주는 type입니다. **ELABOTREATE**
이런 케이스는 스위프트의 naming convention에 때라 `AnyHeaderView` 라는 타입을 만들고 `MyLabel`의 `setHeader`을 이렇게 capture만 해주면 됩니다.
코드로 쓰면 다음과 같은데요 **NEXT**
#22: 타입 세이프티를 위한 노력들이 조금 보이실텐대요...
보시다 시피 아까 컴파일러가 말한데로 protocol을 generic 함수의 constraint으로 사용하고 있구요 `where`은 protocol의 `associatedtype`을 위한 type check 입니다.
마지막으로 `AnyHeaderView`는 이 모든것을 만족 시키는 타입의 `setHeader`을 `self`에 저장하죠.
간단한 컨셉이지만 매우 수동적인 작업입니다.
Xcode가 이런거를 자동적으로 해주는게 있으면 좋겠는데 에플이 해줄리는 없으니까 심심하시면 오픈 소스 프로젝트로 해도 나쁘지 않을거같습니다.
#23: 결과물은 type safety를 보장 하면서 컴파일이 되지만 너무나 지저분하고 쓸때없는 코드를 작석한 느낌이들게 하는 코드죠.
또한 protocol과 associatedtype을 쓰면 어쩔수 없이 항상 이런 type eraser을 어쩔 수 없이 만들어야 될수도 있다는 생각이 들기도 하죠.
#24: 그러면 여기 쯤에서 아까 말하던 컨셉을 다르게 포장해서 말해보겠습니다. **NEXT**
프로토콜은 악속들의 모임인데... 약속을 했다는 증거 대신 약속한 것들을 직접 주면 더 간단하지 않을까요??
associatedtype을 generic으로 바꾸고 함수에 대한 약속을 변수 안에 저장을 하면서 타입 대신 발류를 제공하는 방식으로 가보겠습니다.
이렇게 간단한 방법이 있었는데 protocol을 만들면서 고생했다는게 황당할 정도죠.
#25: Generic을 사용했기 때문에 type eraser을 안 사용해도 되고 `where`과 꺽쇄들이 많이 들어가는 코드를 간단하게 바꿀수 있었습니다.
#26: 프로토콜 없에고 generic struct을 사용헤서 왼쪽 버전에한 오른쪽 버전으로 바꿨는데요..
뭐 프로토콜을 사용하지 말라는거는 아닙니다. 프로토콜은 엄청 좋은 도구이지만 언제 어떻게 사용하는지에 대해서 생각을 해볼 필요가있다고 생각합니다.
그러면 이쯤에서 언제 프로토콜을 사용하고 언제 사용하면 안 되는지를 정리해볼까요??
#27: 무조건 따라야 하는 법칙들은 아니지만 나중에 "아 이런 것도 있었지" 라고 생각하시면 될거 같은데요...
그런데 1개의 함수만 있는 protocol 중에서도 훌륭한 것들이 있죠; 예를 들어 STL에 `Equatable`이라는 protocol이 있는데요 이 프로토콜은 중요한 grammar 가치가 있기 때문에 유용한 프로토콜로 사용되지만 그러지 않는 프로토콜들은 함수로 대체하는게 낳을 거라고 생각합니다.
함수 2-3개를 함수 변수로 넘겨주면 복잡헤지니까 프로토콜에 감싸서 넣는게 더 편하겠죠.
callback 아니면 completionhandler 처럼 한번만 함수를 호출 시키면 함수 그 자체로만 사용해도 나쁘지 않을것같고요.
datasource / delegate 처럼 계속 사용 될 꺼면 프로토콜이 낳을거 같습니다.
그러면 조금더 실용적인 예를 들어보겠습니다.
#35: 그래서 시작 부터 syntax가 엄청 복잡헤지고 컴파일러에서 이상한 에러가 계속나오면 스위트프라고 무조건 프로토콜을 사용해야 된다는 생각은 잠시 버리고 refactoring을 하면서 여러가지 옵션들을 시도하면 좋을거 같습니다.
마지막으로 이런 토크들을 인터넷에서 보면, 멋있는 문구 하나로 마무리를 하더라구요.
그래서 제꺼는 그다지 멋있지는 않지만