오랫동안 고민해 온 microdiagrams DSL을 여러 언어로 시도하다가, Haskell에서 단 3일 만에 전례 없이 빠르게 진척하며 느낀 즐거움과 언어 선택의 중요성을 기록한 글.
2025-10-17
한동안 특정 아이디어에 매달려 있었다 — microdiagrams DSL. 핵심 개념은 꽤 단순하다: 모든 다이어그램에 하나의 언어를 쓰는 대신, 용도별로 여러 언어를 두자는 것이다. 예를 들어, 이 다이어그램은 서로 다른 건반들 사이의 관계를 시각화해 피아노 학습을 돕도록 설계됐다.
이 아이디어로 여러 프로토타입을 만들었다. 왜 그렇게 되었는지는 자세히 말하지 않겠다(언젠가 이걸로 돈도 좀 벌었으면 하니까!), 하지만 꽤 오랫동안 같은 아이디어를 붙잡고 있었다. 누군가는 기술은 중요하지 않다고 말하겠지만, 나는 동의하지 않는다. 사이드 프로젝트(혹은 대작이라 하더라도)에는 지루한 기술을 써서는 안 된다고 생각한다.
프로젝트가 실패하더라도 즐거움과 자기 성장을 가져다주는 것이 중요하므로, 구현은 여러 기술로 시도했다: Clojure, Elixir, OCaml, Go, Prolog. 기본적인 부분만 봐도 순진한 설계는 아니고, 움직이는 부품이 아주 많다. 왜냐면, 내 완벽한 시스템을 내가 설계할 수 있으니까, 그렇지?
Elixir는 서서히 늘어나는 복잡성 때문에 포기했다. 결국 린트가 오류를 잡아주지 못했고, 메시지가 어디로 전달되는지 알 수 없었으며, 문제를 일으키는 그 한 메시지를 고치려고 수십 개의(관용적으로 쪼개진) 파일 사이를 오가고 있었다. 어느 순간, 모든 스펙과 문서 문자열로 정교하게 다듬어 놓은 내 해결책 속에서 내가 길을 잃었다. Clojure는 좋았지만, 한편 내가 다루던 몇몇 구성은 내게 지나치게 어려웠다. 아이디어는 정말 훌륭했지만, 종종 _원래는 쉬워야 할 그 일_을 동작시키려고 허리가 휘어지도록 무리하는 기분이었다.
Prolog는 따로 언급할 가치가 있다. 내가 하려는 레이아웃의 일부는 백트래킹에 의존한다. 그래서 거기서 제대로 동작하는 해법을 구현하려고 정말, 정말 애썼다. 하지만 매번 이 기능 저 기능에 발이 묶여 큰 진전을 내지 못했다. 마치 신기루(Fata Morgana) 같았다. 휴식과 안식을 약속하는 듯하다가, 결국엔 메마른 사막일 뿐이었다.
OCaml은 흥미로운 여정이었다. 시스템 전반을 흐르는 이벤트에 특정한 제약을 두어 보려 했기 때문이다. 그걸 구현하느라 3주를 들였지만, 어떤 접근이든 해키하거나 지나치게 장황하게 느껴졌다. 경험이 충분했다면 결국 해냈을지도 모르겠다. 하지만 어느 순간 짜증이 임계점을 넘었고, 그냥 넘어갔다.
그러다 Go를 봤다. Go로 하는 일은 잘 굴러갔지만, 그래도 Go다. 오해하진 말길, Go에 악감정은 없다. 다만 일하기에 그리 흥분되는 언어는 아니다. 게다가 Ichiban Prolog와 CGo를 번거롭지 않게 붙이는 방법을 궁리하는 소용돌이로 날 밀어 넣었고(그게 Zig와의 로맨스를 시작하게 했다). 어느 순간 나는 소용돌이에서 튕겨 나와, 애초의 프로젝트를 잊어버렸다.
그러고는 개인사에 안 좋은 일들이 있었고, 프로젝트는 뒷전으로 밀려났다.
이 글을 쓰는 지금, 나는 Haskell 코드베이스를 들여다보고 있다. 알다시피, 수학 박사 학위와 중학교 수학 올림피아드 수상 경력쯤은 있어야 건드릴 수 있다고들 놀리는 바로 그 언어. 짜증과 절망 끝에, DSL에 강하고, 안정적인 라이브러리가 있으며, 성능이 좋고, 논리 프로그래밍 능력도 좀 있는 무언가를 구글의 Gemini에 물었다. “Haskell을 고려해 본 적 있나요?”라는 답이 돌아왔고, 나는 피식 웃었다. 그래, 물론. 내가 그 정도로 마조히스트는 아니니까. 예전에 Haskell을 시도해 봤지만, 수많은 확장과 잡설정 때문에 너무 번거롭다고 느꼈다. 다만 그건 OCaml을 하기 전의 일이었다. 이제는 Monad에 대해서도 어느 정도 알고 OCaml 경험도 쌓였으니, ‘야, 한번 더 가 보자’ 하는 마음이 들었다.
이 글을 쓰는 지금의 Haskell 코드베이스는, 다른 어떤 언어로도 도달하지 못했던 지점에 와 있다.
…단 3일 만에…
정말 충격적이다. 너무나도 즐거운 경험이라 일에서 떨어져 나오기가 무서울 만큼 힘들다. ‘이제 이걸 하자’ 하고 생각하면, 알록달록한 오류 메시지의 비를 맞으며 밀어붙이는 사이에 그 ‘이것’을 해낸다. 그리고 ‘좋아, 이제 저걸 할 시간’이라고 생각하면, 또다시 해낸다.
타입 시스템 덕분이라고 할 수도 있겠지만, 나는 Rust 같은 계열에도 익숙하다. 그들과는 다르다. 보통은 여기저기 성가신 요소, 날카로운 모서리들이 있기 마련이다. 그런데 지금은 내가 시력을 잃은 건가 싶을 정도로 그런 게 보이지 않는다. 내가 싫어하던 것들이 전부 해결된 듯하다. 완전히 매끈한 여정은 아니다. 애초에 그럴 거라 기대하지도 않았다. 아직도 Applicative로 호출들을 엮는다든가, 새 Monad를 구현해야 하는 게 아닌가를 고민하느라 머리를 굽히곤 한다. 하지만 사실은, 나는 내내 앞으로 나아간다.
우리가 쓰는 기술은 중요하다. 손에 착 맞거나, 아니면 아닌 것이다. 우리를 앞으로 밀거나, 뒤로 끌어당기거나. 이제의 PHP가 20여 년 전 내가 기억하는 그 지옥 같은 언어는 아닐 거라고 장담할 수 있다. 그래도 비즈니스 요구를 맞추려 애쓰며 씨름하던 기억은 남아 있다. 언어랑 씨름하는 건 싫다. 옆자리에 얌전히 앉아 그 ‘알지, 브로!’ 하는 눈빛으로 미소 지어 주는 걸 좋아한다.
어찌된 일인지, Haskell이 딱 그렇게 해 주는 느낌이다.
이게 언제까지 계속될까? 모른다. 다만 세상에서 가장 어렵기로 유명한 언어 중 하나에서, 내가 어떻게 가장 쉽게 일하게 되었는지 계속 놀라울 뿐이다.