글
오리 인터페이스(Duck Interface)
2006/소프트웨어 설계
2006/09/16 03:09
내가 너무 순진했던 것 같다. 그렇지만, Humane Interface 에 그렇게 많은 의견이 따를 줄은 전혀 생각하지 못했다. 아쉽게도 대부분의 의견은 Ruby 의 Array 와 Java 의 List 의 우위 비교를 논하고 있어 원문에서 다루고자 했던 핵심을 벗어났다. 그렇다고 하더라도 연이은 의견이 있었던 점은 바람직한 일이다.
(비록 내가 Ruby 의 Array 나 Ruby 가 더 좋다고 말하려는 의도가 아니었음을 분명히 해야 한다고 느끼지만, 어떠한 상황을 가정하지 않고는 Ruby 와 Java 가운데 어떤 것이 났다고 생각하지도 않는다. Ruby 의 Array 와 Java 의 List 는 전혀 다른 관점으로 설계되었고, 나는 이들을 모두 좋아한다. 핵심은 나는 Java 와 Ruby 는 모두 유용하며 나는 이들을 매우 자주 사용한다는 점이다. 이러한 이유로 이들을 예로 들었던 것이다.)
이들 의견 중 하나는 humane/minimal 접근 관점을 벗어나서 Array 와 List 사이의 차이가 발생하는 다른 이유들이 있음을 제시했다. 그 중 하나는 이들은 유사한 기능을 제공하지만, 두 언어에서 서로 다른 역할을 하고 있다는 점이다.
Ruby 의 Array 는 일부 사람들에게는 혼동을 줄 여지가 있는 메소드를 다수 포함하고 있다. push 와 pop 메소드가 그렇다. Elliotte 이 "누군가 List 에 스택을 집어 넣었다." 라고 표현한 것에서 이러한 혼란을 엿볼 수 있다. Array 에는 또한 shift 와 unshift 메소드를 갖고 있는데 이들은 Elliotte 가 지적한 다음의 말에서 드러나는 적절해 보이지 않는다:
"Queue 나 Stack 을 사용하길 원한다면 List 클래스를 쓰는 것보다는 Queue 나 Stack 클래스를 써야 하지 않는가?"
이들을 읽으면서 잊혀졌던 기억이 떠올랐다. (비록 문법은 우습지만) 객체 지향의 진수를 이해하려면 반드시 읽어야 하는 환상적인 책, Smalltalk Best Practice Patterns
"Smalltlak 에 입문해서 많은 사람들이 가장 처음 작성하는 객체 중 하나가 Stack 이다. Stack 은 기본적인 자료 구조이며, 노래와 이야기에서도 회자되었고,이론적인 프로그래밍 언어에 관한 수많은 논문에서 다뤄졌다. 어떠한 기본 이미지에서도 Stack 클래스가 기본적으로 제공되지는 않는다. 나는 Stack 클래스가 작성되는 것을 여러 차례 보았지만, 이들을 결코 오래 지속되지 않는다." - Kent Beck
Smalltalk 에서 Ruby 의 Array 에 해당하는 것이
OrderedCollection 이지만, 여기에서도 push 나 pop 은 없다. 대신 Kent 는 addLast: 와 removeLast: 를 사용했다.Kent 는 Stack 이나 Queue 의 부족하다고 보지 않았다. - "왜 Smalltalk 에 Stack 이 없느냐? 글쎄. 단지 그건 OrderedCollection 을 이용해서 Stack 을 역할을 하게 하는 문화는 일부다."
여기에 대해서 내 생각이 어떤지는 확실하지 않고, Kent 의 글에서 보이는 불확실성을 분명하게 느낀다. 만일 당신이 Queue 와 같은 것을 사용하기를 원한다면 OrderedCollection new (자바의 new OrderedCollection() 에 해당) 로 객체를 생성하고 addLast 와
removeLast 메소드를 사용하기 보다는 Stack new 와 pop, push 를 쓰는 것이 적절하다고 여길 것이다. 이러한 상황은 정적인 언어와 동적인 언어 사이의 차이점을 포착하게 해준다. 정적인 언어는 엄격한 타입에 근거한 인터페이스를 통해 객체 사이의 메시지를 주고 받지만, 동적 언어의 경우는 이른바 Duck Typing 에 의해 다양한 역할을 수행할 수 있는 클래스를 갖는다. Java 역시 LinkedList 와 같이 Queue 역할을 하는 List 를 갖고 있지만, 대개는 구분되는 인터페이스를 통해서 쓰게 될 것이다. Smalltalk 사용자 입장에서는OrderedCollection 을 통해서 구현할 수 있는데 왜 또 다른 객체를 만들어야 하는지 의문을 갖게 된다. Ruby 사용자의 경우에도 비슷한 반응을 보일 것이고, 그러한 상황에 맞추서 사용할 수 있도록 적절한 이름을 가진 메소드를 추가하려 할 것이다. (사실 Ruby 사용자들이 실제로 Array 가 stack 기능을 수행하는 것에 만족할지 혹은 어쩔 수 없이 남겨진 것으로 여길지는 알 수 없다.)
Charles Miller 가 다음과 같이 말했다. "Java 의 설계는 Small Interface(꼭 필요한 인터페이스) 를 제공하며, Static 메소드 형태로 제공되는 헬퍼 클래스의 유틸리티 함수로 이를 보완해준다. Ruby 의 설계는 유틸리티 메소드가 혼합된 상대적으로 덩치가 큰 클래스를 허용한다."
여기서 얻을 수 있는 결론은 특정 언어의 클래스를 다른 언어에서 통용되는 가치로 평가하는 것을 경계해야 한다는 점이다. Array 가 List 또는 List 와 collection 패키지의 다른 구현 클래스나 인터페이스를 합친 것과 같은가? 아니면 그 보다 더 복잡한 무엇인가? 어떤 이들은 List 클래스에 78 개의 메소드를 추가하는 것을 거부할 것이다. Ruby 의 Array 는 불필요해 보이는 것들을 포함하고 있다고 볼 수 있지만 나는 자바의 collection 으로 작업을 하는 것보다 Array 를 사용하는 것을 더 좋아한다. 그것이 Array 가 Humane interface 지침을 따른데에서 기인한 것인지, Ruby 의 문법의 특성인지는 확실하지 않다.
대체로 어떠한 의견에 동의하는지는 말하기 어렵지만 분명한 것은 다양한 관점을 모두 이해하려고 노력해야 한다는 점이다.
원문: DuckInterface
(이 글에서도 다소 해석하기 어려웠던 부분이나 오히려 빼는 것이 나을 듯한 문구는 제거하였고, 저처럼 Smalltalk 를 잘 모르시는 분을 위해 약간의 주석을 추가하였습니다.)
추가적으로 참조할 만한 글: Java does Duck Typing