독중감-폴리글랏 프로그래밍

서평

이 책은 정말 요약할 수 없이 다양한 분야의 내용이 섞여있다. 마치 프로그래밍에 대한 한 편의 다큐멘터리를 보는 것 같았다. 특히, 개발자이지만 업무와 개발언어 그리고 시간에 쫒겨 IT분야에 있으면서 IT분야를 모르는 사람들에게는 저자가 들려주는 여러 옛날이야기난 open JDK가 왜 따로 있어서 사람 헷갈리게 하는가? 하고 고민했었었다는 많은 개발자들에게 동기부여와 에너지가 될 것 같고, 실제로 나에게도 그랬다. 다음은 독중감 컨셉에 맞게 독서 중 필요한 내용을 정리한 막돼먹은 요약본이다.

Functional Programming

많은 내용이 있었지만 이 중에서도 ‘함수’자체의 정의를 내리는 부분이 기억에 남는다.

1
F(x) = x + 1

함수F가 x를 받아서 x + 1의 결과를 반환한다. 여기서 함수와 값을 동치다 라는 표현을 쓰는데, 함수 이고, 함수 다. 라는 말과도 같다. 문제는 이렇게 되기 위해서,

  1. 함수는 반드시 값을 반환해야 한다
  2. 함수는 값을 반환하기 위해서 어떠한 부수효과도 만들지 말아야한다.
    함수가 부수효과(side-effect)를 가지면 1번항목에 위배되기 때문이다. 값은 어떠한 부수효과도 만들어낼 수 없다

위와 같은 상황이 전제되어야 한다. 사실 Functional Programming에 관심을 가지고 살펴보면서 side-effect와 immutable에 대해서 굉장히 많이 들어봤지만 왜 그런지에 대해서 이해할 수 있었던 매우매우 중요한 대목이 아니였나 싶다. 개인적으로는 이 내용으로만 가지고도 난 이 책을 보길 정말 잘 했다는 생각을 했다.

추가적으로 Scala에서 함수를 표현할 때 x => x + 1이라고 표현 했는데, 이 부분에 대한 해석도 흥미롭다.

1
F(x) = x + 1

이런 함수가 있을 때, 가변적인(아무이름이나 붙일 수 있기에 지울수도있는) 이름을 없애보면

1
(x) = x + 1

와 같은 식이 되며, 위에서 언급한 바와 같이 함수는 값과 동치이기 때문에

1
(x) => x + 1

(x)는 x + 1이다라고 읽거나 영어로는 x goes to x plus one으로 읽을 수 있게 된다.

Lazy value

lazy value에 대한 개인적인 기억은 lazy val x = a와 같은 코드를 Scala의 온라인숙제에 막혀 구글링으로 찾을 답을 베껴 적다가 처음보는 문법에 놀랐지만 그냥 넘겼던 창피한 기억속에서 찾을 수 있다. 위에서 a가 계산하기 정말 정말 오래걸리는 값이라면 어떨까? 이 내용은 책에서 Scala에 대해서 특징(traits, pattern matching, immutable, actor 등)들을 설명하면서 같이 설명되었는데, 개인적으로는 Functional Programming Principles에서 난생처음본 call by name에서 본 내용이 접목되었다는 생각을 했다. 요지는 a가 계산하기 정말정말 오래 걸리는 어떤 값이라면, 일반적인 프로그램이 진행하는 것과는 다르게, 정말정말 a라는 계산결과가 필요할 때 까지 계산을 미뤄두다가 필요할 때 계산을 하는 것과 같다.

Tail Recursion

분명 이 단어를 마틴 오더스키님의 Functional Programming Principles에서 봤었고 연습문제까지 풀었고 알았다고 생각했지만, 사실 뭔지 몰랐었다는 사실이 충격적이였다. 완벽한 공부법에서 읽었던 대로 난 강의를 들었지 이해한게 아니였다는 슬픈 사실을 알게해준 대목이였고 알고리즘 인터뷰를 준비하는 나로서는 다시 한번 정신을 가다듬는 전환점이 되었다. 이와 같은 레벨의 깨달음은 Higher-order function에서도 드러났다.

Exception

예외처리에 대한 제임스 고슬링과 하일스버그라는 두 명의 거장의 의견대립으로 풀어쓰고 있는데, 필자는 평소 예외처리에 관심이 많았던 관계로 굉장히 재미있게 본 내용이다. 필자의 경우에는 제임스 고슬링과 같은 의견으로 최대한 발생한 곳에서 예외를 처리하며 최대한 실패를 회복할 수 있어야 한다고 생각한다.그렇게 개발하는지는 잘… 현재 개발하고 있는 모듈의 경우에는 Daemon에서 발생한 exception을 Library단까지 끌어올려서 전달하고 있는데, 하일스버그의 주장처럼 try-finally 정도를 유지하고, finally가 없는 C++에서는 deconstructor에서 처리하면된다는 내용은 조금 이상적이지 않았나 싶은 생각이 들었다. 언젠가는 할 수 있을까?

Trait와 Interface

임작가님은 Scala의 trait를 설명하면서 C#, Java의 interface에 대한 문제는 어떤 클래스가 이것을 구현하는 순간, interface에 포함된 모든 API를 받아들여야 한다는 것이라고 표현했다. 우리가 원하는 것은 Person이라는 클래스에 eat이란 특질만 빼서 Car에게 주고 싶은 것이지 (Car도 기름을 먹으니까), Car가 Person 자체가 되는 것을 원하지 않는다는 점을 들어서 설명했다. 필자는 OOS에 능통하지 않지만 가끔 이런 딜레마에 빠졌던 경험이 있었던 만큼 mix-in이라고 하는 이런 특정한 특질을 어떤 클래스에게 주입하는 방법에 대해서 큰 매력을 느꼈다.

우리는 어떤 존재의 표현, 형태를 interface로 정의하고, 내부에 살을 입히기 위해서 클래스를 정의한다. Person은 interface이고 singer, developer는 구체적인 클래스이다. Person은 sleep(), eat(), work()라는 껍데기 API를 가지며 각각의 구체적인 클래스는 껍데기 API에 살을 입힌다.

Person은 영혼이고
Developer는 육신이다.
Person은 색깔이 없고 형태만 존재하는 그림자와도 같다.

일반적으로 Type system 내부에서 구체적인 클래스는 interface로 대체되어 처리되며, 모든 구체적인 클래스는 interface라는 그림자로 보면 똑같은 형태로 보인다. interface는 더 이상 쪼개질 수 없는 단위로 취급되며, 이 것이 interface의 한계이다.

Scala의 trait는 interface가 아니라 type으로 되어있다고 한다.

1
2
3
trait Sleeper # 자는
trait Eater # 먹는
trait Worker # 일하는

이렇게 어떤 특질을 trait로 표현할 수 있는데, 책에서는 다음 예제가 기억에 남았다.

1
2
3
class SmartPhone extends Phone with Eater
class SamsungPhone extends SmartPhone with SBeam with ShareShot
class IPhone extends SmartPhone with VideoPlay with Siri

삼성폰은 스마트폰이란 클래스를 상속하며, SBeam, ShareShot이라는 기능(특질)을 가진다. 아이폰은 스마트폰이란 클래스를 상속하며, VideoPlay, Siri이라는 기능(특질)을 가진다. 굉장히 이해하기 쉬운데, 만약에 삼성폰이 Siri를 가져야 한다면 어떨까?

1
class SamsungGalaxy10Phone extends SamsungPhone with Siri

Siri라는 기능을 삼성갤럭시10이 탑재했다고 해서 아이폰이 아님을 굉장히 쉽게, 그리고 부연적인 설명이 전혀 없이 선언이 가능함을 볼 수 있다.

또 다른 예로는, Logging이란 기능(특질)을 가지고 싶지만, 그렇다고 Logger를 상속받고 싶지는 않다. 왜냐하면 난 logging하는 능력이 가지고 싶은거지 내가 logger로 다뤄지고 싶지 않기 때문이다. 이런 상황에서도 with Logging을 사용할 수 있다면 어떻겠는가?

필자는 Scala에 무한한 호기심을 가지고 있으며, 조금씩 아주 조금씩 알아보고 있다. trait의 전부를 알지 못하지만 위와 같은 모습은 호기심과 매력을 느끼기에 충분하다.

Share