go 언어에서 interface의 의미.
By SeukWon Kang
go를 사용하다보면 처음에는 channel과 goroutine에 감동^^ 하고 나중에는 interface에 감탄하게 됩니다.
C++ 에 pure abstract class 나 java의 interface를 접한 분들은 의외로 헛갈리기 좋은것이 이 go언어의 interface입니다.
실제로 go 프로그래밍을 하다보면 처음에는 C++ 에서 header로 분리 하듯이 interface를 정의한 패키지를 분리하게 되는 데 작업을 하다보면 약간 이상한 느낌이 들기 시작합니다.
여러 패키지에서 공유하기 위해 interface 파일을 만들었는데 나중에 확인해보면 처음에 쓰려고 만든 그 패키지 말고는 아무곳에서도 사용하지 않는다는 것을 알게 되지요.
이것은 프로그램 설계를 잘못해서가 아니고 go 언어의 interface가 C++/java의 interface와는 설계사상이 다르기 때문입니다.
굳이 비교를 한다면 python의 duck typing 과 더 유사한 개념이라고 봐야 합니다. 즉 동일한 function에 대해 동일한 결과를 돌려준다면 (사용하는 쪽에선 ) 내용물을 신경쓸필요가 없다. 는 거지요.
무슨 뜻이냐 하면 interface는 사용하는 쪽에서만 알고 있으면 됩니다. 사용 당하는 object는 자신이 무슨 interface를 통해서 사용되는지 알지도 못하고 알필요도 없습니다. ( 그래서 class 가 자신이 implement하는 interface를 정의하는 과정이 없습니다. )
이것이 가지는 의미는 엄청난데 두개의 비교적 tight bound 된 package간에 decoupling 을 하려고 할때 아주 유용하게 사용할수 있기 때문입니다.
별 생각없이 각각의 package에서 상대방을 import하면 컴파일이 안됩니다. 순환 import는 금지되어 있으니까요.
보통 이경우는 설계가 어딘가 잘못되어 있는 경우가 많겠지만 어쩔수 없는 경우도 있게 됩니다.
이것의 해결은 서로 상대방 struct 에서 필요한 기능들만을 정의한 interface로 만들어 local로 정의해서 사용하면 됩니다. 그리고 그 interface는 자신만이 필요하기때문에 ( 다른 곳에선 또 자신 만이 필요한 interface를 정의해 쓰면 되기 때문에 ) global로 정의 할필요도 없이 local 로 정의해 사용하면 됩니다.
이것을 통해서 상대방을 import할 필요가 아예 없게됩니다. 물론 이 두개의 package간의 최초 data 설정은 외부에서 해줘야 하긴합니다만 이런 경우 이미 그역할을 맡고 있는 것이 존재하기 마련이지요.
goguelike의 경우는 activeobj와 AI가 이경우에 해당 됩니다. activeobj는 AI를 소유하고 AI는 activeobj의 정보가 필요한니 상호 참조가 일어나게 되더군요. 이문제의 해결을 위해 이리 저리 고민하다가 interface로 간단히 해결되는 것을 깨닿고 go언어의 설계자들을 존경하게 됬습니다. ( 애초에 그분들은 프로그래밍 언어의 guru들이지요. ^^) 실제로는 거기에 factory function obj를 추가 하여 구현 되어 있습니다.
다만 runstep의 경우는 runstepi라고 하는 interface가 정의된 package를 분리해 두었는데 이는 interface의 embedding을 위해서 분리해둔 것입니다.
적당한지는 모르겠지만 interface 를 사용하는 비교적 짧은 라이브러이인 frametask 패키지를 github에 올려 두었습니다. ( 이것도 goguelike에서 분리해낸 것입니다. ) 사용 용도는 프레임 단위로 작동하는 시스템에서 미래의 프레임에 작업을 예약하는 용도 입니다. ( 버프가 종료 된다거나 , 일정시간후 마을에서 되살아난다거나 하는 일들을 관리하는 거지요. ) https://github.com/kasworld/frametask
주의 할점은 go언어에서 interface이름의 권장사항은 er을 붙이는 것입니다. 저는 이게 영 어색해서 i또는 I 를 붙이고 있는데(java에서 붙은 버릇이지요) 이는 공식적인 go언어의 이름 규칙에 어긋나는 것입니다.