Elixir와 실용주의 프로그래밍
이번에 엘릭서의 특장점에 관한 발표 준비를 하면서 엘릭서를 쓰는 이유를 실용주의 프로그래밍과 연결시켜보았다. 평소에 가지고 있던 생각이기도 하면서 실용주의 프로그래머를 쓴 데이브 토마스가 또 엘릭서 신봉자(?)이기도 하니 좋은 연결 포인트라고 생각했다. 하지만 역시 날것의 내 생각을 다듬어서 남들에게 보기 좋게 만드는 건 쉬운 일이 아니었다. 발표는 끝났지만, 일정에 맞춰 자료를 준비하고 다듬으면서 방대하게 발산하며 어지럽혀진 생각을 다시 한 번 글로 다듬는 과정을 통해 정리하고자 한다.
먼저 실용주의 프로그래밍에 대해 내 관점으로 설명해보겠다.
실용주의 프로그래밍
데이브 토마스와 앤드류 헌트의 실용주의 프로그래머는 명실상부 개발자의 필독 도서 중 하나이다. 얼핏 보기에는 그저 시니어의 개발자 팁 모음 같은 느낌의 책이 20년 동안 변함 없이 개발자들에게 깊은 가르침을 주고, 심지어 20년동안의 피드백을 바탕으로 다시 한 번 다듬어진 개정판은 더욱 현실적이고 와닿는 가르침이 되었다.
1판 서문에서 말하듯이 이 책은 이론적인 책이 아니다. 수많은 팁을 주지만 그것을 완벽히 증명하려고 애쓰진 않는다. 그저 경험많은 시니어의 조언처럼 주관적으로 더 나은 방향을 제시할 뿐이다. 이 때문에 더 와닿지 않고 독단적이라 느끼는 사람들도 있을 것이다. 심지어 이 책의 제목에 있는 “Pragmatic” 용어가 가지는 의미 때문에 더 그렇게 느껴질 수 있다.
“실용적인(Pragmatic)” 것은 무엇일까? 단어로 떠오르는 느낌은 “이상적인(Idealistic)”의 반대가 아닐까 싶다. 즉 현실에 따라 유동적이고, 상황에 따라 다른, 영어로는 “It Depends,” 정도의 느낌. 그런데 이것을 극단화하면 결국 이 책 자체가 모순이 된다. 각 개인의 상황이 모두 다르고 심지어 한 개인의 상황도 시간에 따라 시시각각 달라지는데, “그냥 알아서 판단해라” 말고 어떤 유의미한 조언을 할 수 있겠는가? 따라서 독자는 책의 조언들을 나름대로 받아들이되, 신중하고 비판적인 자세를 견지해야 한다. 사실 책에서도 몇 번 강조하는 부분이다. “비판적인 시각을 가져라” 와 관련된 몇 가지 조언들이 들어 있고, “신봉자들을 조심해라” 같은 경고도 있다. 결국 그 내용은 이 책에도 적용될 수 있는 것이다.
그럼에도 불구하고 책의 내용들은 많은 사람들에게 강한 인상을 남겼고, 몇 번이고 다시 읽을 가치가 있으며 다시 읽을 때마다 새로운 부분들을 발견할 수 있을 것이라 여겨진다. 대개의 좋은 책들이 그렇듯이, 실용주의 프로그래머도 읽을 때마다 자신의 상황에 따라 다른 부분이 보여질 것이다.
그 중 내가 이번 발표에서 이용하려고 주목한 부분은 ‘적당히 괜찮은 소프트웨어’와 ‘변경하기 쉬운 설계’부분이다. 즉 애자일한 개발 프로세스와 유지보수하기 쉬운 코드 디자인에 대해 강조하고자 했다. 그리고 책에 직접적으로 언급되진 않았지만 개발자 경험도 중요하게 다뤘다. 조금 단순하게 표현하자면 내가 이번에 해석한 실용주의 프로그래밍은 ‘개발자 생산성’을 올리는 철학이다. 하지만 그냥 단순히 코드를 빨리 찍어내자 라는 생산성은 아니다. 그보다는 조금 더 장기적인 관점이고 책임있는 전문가로써의 느낌이다.
그리고 이번 발표에서 나는 이것을 프로그래밍 언어라는 도구와 연결시켰다.
Elixir와 실용주의 프로그래밍
실용주의 프로그래머 책에서는 특정한 도구를 사용하라, 라고 지시하지 않는다. 하지만 사실 책에서는 은근히 저자의 주관들이 특정한 초점을 맞추고 있는것이 보여진다. 특히 다음 맥락을 알고 보면 더 그렇다. 저자 중 한명인 데이브 토마스는 ‘Elixir’ 언어에 (적어도 최근 몇 년간은) 푹 빠진듯 하다. Elixir가 처음 나왔을 때부터 열렬히 찬사를 보낸 덕분에 Erlang의 창시자 조 암스트롱 마저 궁금증이 생겨 Elixir 탐색 후기를 남겼을 정도다. 결국 Programming Elixir라는 책도 냈으며 저자가 설립한 “The Pragmatic Programmers” 출판사는 시판된 Elixir 책들의 거의 대부분을 출판하며 Elixir 전파에 큰 기여를 하는 중이다.
물론 저자가 처음 책을 쓴 1999년에는 Elixir라는 언어는 아예 존재하지도 않았고 따라서 그와 관련된 내용도 일체 없었다. 하지만 개정판에서는 책의 예제 코드 상당수가 Elixir로 되어있고 심지어 몇몇 주제는 Elixir와 굉장히 밀접한 관련이 있다. 즉 아무튼 간에 저자는 Elixir에서 깊은 감명을 받고 개발 가치관에 많은 영향을 받은것만은 틀림없어 보인다.
책의 내용 중 이를 뒷받침하는 좀 더 구체적인 예를 들어보겠다.
Topic 24. 죽은 프로그램은 거짓말을 하지 않는다의 “망치지 말고 멈춰라(CRASH, DON’T TRASH)” 에서는 erlang과 elixir의 철학을 그대로 드러낸다. erlang의 Let it Crash는 ‘Actor Model+@’인 거의 erlang만의 독보적인 철학이며, 30년이 지났지만 오히려 현대에 들어서 점점 더 복잡해지는 분산처리 환경에서 더 강한 힘을 발휘하는 것으로 보인다.
Topic 30. 변환 프로그래밍 은 함수형 프로그래밍과 밀접한 관련이 있다. 이것을 위해 꼭 함수형이 필요한 건 아니지만, 함수형 프로그래밍의 관점은 결국 데이터 변환 관점으로 연결될 수밖에 없다. 특히 대부분의 함수형 언어들이 파이프라인 연산자를 지원하며 이런 언어들에서 파이프라인은 정말 코드를 깔끔하게 만들어준다. 즉 함수형 언어가 변환 프로그래밍 관점에 필수는 아니지만 함수형 언어를 하면 자연스럽게 변환 프로그래밍으로 생각하게 되는 것이다. 하지만 여기서 ‘모든’ 함수형 언어가 파이프라인을 기준으로 생각하진 않는다. 함수형 언어에서 사실 중요한 것은 함수들의 조합인데, Elixir 같은 언어들은 함수 조합을 표현할 때 파이프라인으로 구성하기 쉽게 되어있을 뿐이고, Haskell 같은 언어들은 파이프라인이라고 부를 수 있는 것 자체가 여러 타입이 있어 처음 접했을 때 바로 이해하기가 쉽지 않다. 즉 변환 프로그래밍이 모든 함수형 언어에 필수적인 개념은 아니지만, Elixir처럼 단순한 파이프라인 문법을 가진 언어는 이 강점을 극대화 시킬 수 있는 것이다.
6장은 개정판에서 새로 추가된 챕터로 동시성과 병렬성에 대해 이야기한다. 그리고 여기서 중요한 토픽 중 하나는 Topic 35. 액터와 프로세스 이다. 액터를 이용한 동시성에서는 공유 상태가 아예 없기 때문에, 동시성을 제어하기 위한 별도의 코드 작성 없이도, 동시성을 좀 더 단순하게 다룰 수 있다는 장점을 강조한다. 그리고 이러한 액터 모델의 대표격은 역시 erlang이다. 재밌는 건 erlang을 만든 사람들은 actor model에 관한 논문을 읽지 않고 만들었다는 것인데, 그럼에도 actor model의 대표처럼 된 것은 prolog를 비롯한 actor model을 구현한 몇몇 언어들이 erlang의 조상격이기 때문이다. erlang을 만든 사람들은 순전히 현실적인 이유로 필요에 의해서 언어를 만들었으며 따라서 actor model을 이론적으로 정확히 구현해 내고자 하는 열망은 없었던 것 같다. 따라서 actor model이 곧 erlang 자체다 라고 할 수는 없지만, erlang(그리고 elixir)에서 실용적으로 actor model의 특징들을 잘 이용한 것으로 보인다.
중요한 점은 이런 erlang, elixir와 관련된 내용들이 대부분 개정판에서 추가된 것이란 점이다. 그리고 이러한 내용들은 개정판 이전의 내용들을 부정한다기보단 시대에 맞춰서 조금 더 발전된 형태가 된 느낌이다. 그리고 한 가지 더 개인적인 느낌은 변환 프로그래밍이나 액터와 프로세스 모두 복잡한 것들을 조금 더 단순화해서 생각하도록 하는 느낌이다. 상태 관리를 중요하게 생각하는 객체지향 설계나 스레드 간의 공유 상태를 고려해야 하는 스레드 기반 동시성 설계 모두 복잡한 사고흐름을 요구한다고 느낀다. 함수형 프로그래밍에서도 타입을 수학적으로(대수적으로) 표현하기 위해 복잡한(코드로는 간단해지지만) 생각을 거치거나 동시성 프로그래밍에서도 Software Transactional Memory(STM) 같은것을 알아야 할수도 있다. Elixir에서는 파이프라인 구조와 액터 모델을 이용해 보다 생각을 단순하게 가져갈 수 있도록 해준다. 저자는 이러한 부분을 실용주의라 강조하고 싶었던게 아닐까 싶다.
개발자는 수학자가 될 필요가 없으며, 함수형 프로그래밍의 이론적인 부분에 집착할 필요도 없다. 실제로 erlang은 액터 모델과 결합하여 동시성에 큰 강점을 가지게 되었지만 정작 프로세스간 메시지 통신이 사이드 이펙트가 됨으로써 순수한 함수형 언어에서는 멀어졌다. 내생각에 erlang이 함수형을 채택한 건 그저 불변형 데이터 자료구조가 격리된 프로세스들의 상태관리를 단순화해주는 것처럼 동시성에서 장점을 얻기 위해서가 아닌가 싶다. 즉 erlang은 지극히 실용적인 이유로 지금의 특징들을 갖게 되었다고 생각되며 elixir는 그러한 erlang의 철학은 그대로 계승하고 거기에 파이프라인과 매크로, 프로토콜 같은것을 또 지극히 실용적인 이유로 덧붙여 정말 실용주의적인 언어가 완성된 것이다.
Conclusion
이번 발표 준비를 하면서 사실 처음에는 그냥 Elixir가 왜 좋은지 장점들을 나열하면서 3년간의 운영 경험을 바탕으로 적당히 설명하고자 했었다. 그런데 어느 순간 갑자기 실용주의를 발표에 집어넣어야 겠다는 생각이 들었다. 넣고나서도 한동안, 아니 거의 막판까지 왜 실용주의를 굳이 넣어야 하는가를 잘 설명하지 못하고 그냥 개발자 생산성과 동일한 느낌으로 얘기했었는데, 지금은 elixir가 왜 언어 자체가 실용주의를 잘 나타낸 언어인가를 조금이나마 설명할 수 있을 것 같아 이렇게 글로 다시 한 번 정리해 보았다.
앞으로도 나는 남들에게 elixir를 실용주의 언어라고 소개할 것이며 내가 느끼는 실용주의에 대해서 그들에게도 이해시키고자 노력할 것이다.