사실 너무 바빠서, 그리고 중간에 다른 책을 읽느라(디지로그, 책 읽어주는 남자), 셤공부하느라 몇장 걷어보지는 못했지만 인상 깊은 구절을 소개할까 합니다.
Let Ruby be Ruby.
이 책의 저자는 독일어를 배우던 중에 detusch 라는 단어는 고유명사(언어를 나타내는 명사니까)임에도 불구하고 왜 소문자로 기록하는가를 그의 선생님에게 묻습니다. 너무 이해가 안가서요. 그 선생님이 그러자 싱긋 웃으면서 이렇게 말했다고 합니다. “Don’t fight it.” 언어는 비록 많은 불규칙성을 갖고 있고 그들 중 일부는 이해가 안가보이지만 그대로 바라보라는 것이죠.
루비도 마찬가지입니다. 루비에서는 size가 있으면 length가 있습니다. 둘의 기능은 같죠. 또, collect/map 이 같습니다. 이것은 orthogonality에 문제되지 않는가? 왜 다른 언어처럼 표현방식을 최소화하지 않는가? 왜 private은 같은 클래스의 인스턴스끼리 접근할 수 없는가. 모두 Ruby를 Ruby이게 놔두란 말로 대답할 수 있습니다.
또한가지 저를 괴롭혔던 문제중에 하나인데, 예를들어 루비의 array는 다음과 같이 동작합니다.
irb(main):001:0> ary = %w{A B C D E} => ["A", "B", "C", "D", "E"] irb(main):002:0> ary.shift => "A" irb(main):003:0> ary => ["B", "C", "D", "E"]
그러나 우리는 분명히 Ruby에서의 파괴적인 동작을 하는 메소드에는 ! 가 붙어있음을 알고 있습니다. 따라서 shift에는 !가 있어야 할텐데 왜 그렇지 않은가. 이에 대한 대답은 어떤 메소드는 항상 파괴적이다란 것입니다. 이런 메소드에는 read가 있죠. 어떤 스트림에서 무언가를 read한다면 그것은 현재의 상태 – file descriptor라던가 – 를 무효화해버립니다. 하지만 이런 메소드들은 본질적으로 파괴적입니다. 따라서 별도로 !를 사용해 이 메소드가 파괴적임을 표시하지 않습니다. 이것이 루비에서 파괴적인 모든 메소드에 !가 붙지 않는 이유입니다. 그렇지 않다면 이 저자가 말한대로 프로그램이 마치 다단계 판매의 카달로그처럼 보여버리게 될테니까요.
그러면 어떤 메소드에는 !가 있어야하고 어떤 메소드에는 없어도 되는가. 여기에 Matz는 이렇게 대답합니다. “Follow your heart.”
이 외에 이 책의 1장은 SamKong님 말마따나 잘 쓰여진 OOP 에 대한 설명을 담고 있습니다. 예를들어, interface inheritance와 implementation inheritance의 구별이 그것입니다. 첫번째는 자바로 치면 implements 를 사용해 공통된 인터페이스를 제공하는 경우를 들 수 있습니다. 만약 C++이라면 typename T 를 받은뒤 T::some_method() 와 같이 메소드를 호출하는 경우를 들 수 있습니다. 물론 C++은 완전 추상 메소드를 사용해 인터페이스를 구현해서 쓸 수도 있습니다. implementation inheritance는 구현상속인데요, 이것은 우리가 흔히 알고 있는 자바의 extends, C++의 class Child: public Parent, Ruby의 class Child < Parent 가 그것입니다. 사실 읽어보면 다들 아시는 내용이겠지만, 한곳에 모아서 보는 것은 정말 오랜만인듯. 나머지 부분들은 대부분 howto 입니다. 또, 그 howto는 역색인 형태입니다. 예를들어 보통의 reference는 String의 메소드들을 줄줄이 나열하면서 이건 이렇고 저건 저렇고를 말하지만 이 책은 어떤 작업을 먼저 소개하고, 그 뒤 그 작업에 필요한 메소드들을 모아서 보여주는 식이죠. 이 책의 한가지 흥미로운 부분은 class instance variable에 대한 저자의 견해인데요. 그는 한마디로 딱 잘라, "이걸 어디다 쓰는지 모르겠다" 라더군요. ㅎㅎ (저도 모름)