/home/caml-shaving

Doom Emacs

2023-02-25

태그: dev

오랜만의 이맥스 글이다. 둠 이맥스를 각잡고 쓰기 시작한지 이제 한달이 조금 넘었는데, 이 좋은 걸 나만 알고 있기 아깝다는 생각에 글로 남겨본다.

둠 이맥스로 넘어온 이유

예전 글에서도 몇 번 얘기한 적이 있지만, 내 이맥스 설정은 부팅(?)이 느리다. 이맥스를 쓰는 사람이 백만명이면 백만개의 이맥스 설정이 가능하기 때문에 모두가 각자의 이맥스를 가지게 된다. 그래서 정확히 말하자면 이맥스 가 느린게 아니라 내 이맥스 가 느렸다. 특히 이맥스를 emacs & 로 처음 실행하고 GUI가 전부 로딩된 후 입력이 가능하기 까지 굉장히 오랜 시간이 걸렸는데 (이 시간을 보통 startup time, launch time 등으로 부르는데 나는 부팅 시간이라고 하겠다), 심한 경우에는 3분 가까이 걸리기도 했다. 수많은 패키지를 로딩하고 있는 이맥스를 보며 하염없이 기다리기만 하는 것이다.

그래서 이맥스를 한번 실행하면 잘 안끄는 버릇이 생겼다. 이맥스를 OS라고도 부르기도 할 만큼 거의 모든 작업을 이맥스 위에서 하니 이 자체는 꽤 괜찮은 프랙티스라고 생각한다. 하지만 종종 재택근무를 할 때에는 윈도우에서 리눅스에 원격으로 붙은 뒤에 작업을 해야 했는데, 이때는 어쩔 수 없이 이맥스를 새로 켜야 했다. 그리고 그때마다 부팅 시간을 낭비하게 되었다.

그래서 작년 말에 대체 왜 내 이맥스는 부팅이 이렇게 느린건지 한번 토끼 굴을 파보기로 했다. 일단 내 설정에서 use-package 로 사용 중인 패키지를 세어보니 63개였다. 각 패키지마다 의존성이 있는 패키지까지 합치면 더 많을 거라 생각했고 eln-cache 에서 컴파일된 패키지 수를 세어보니 과연 400개가 넘었다. 이맥스를 켜면 상태창에 뭔가 잔뜩 로딩하는 메시지가 지나갔기 때문에, 패키지를 로딩하는 작업 자체가 병목이라는 생각이 들었다. 사실 예전에 네이티브 컴파일 이맥스를 시도했던 가장 큰 이유도, 거대한 리습 인터프리터라고 불리는 이맥스가 내 패키지 설정을 로딩하는 속도 자체를 빠르게 해주지 않을까 하는 기대에서였다. 아무튼, 이맥스의 패키지 로딩 속도와 관련한 키워드로 검색하다 보니 또 계시처럼 이런 글을 만나게 되었고, 마침 너무나도 갈망하던 흥미로운 주제라서 그 자리에서 각잡고 정독하였다.

사실 다양한 이맥스 변종이 있다는 것은 예전부터 알고 있었다. 스페이스맥스라던가. 둠 이맥스도 어렴풋이 들어는 봤었고, 그냥 또 이맥스에 예쁜 껍데기를 입힌 거라고 생각했다. 하지만, 둠 이맥스 개발자가 정성스럽게 작성한 문서를 읽다보니 둠 이맥스만의 철학에 크게 공감하게 되었고, 살짝 테스트만 해보고 “아 이거다” 싶은 생각이 들자마자 일말의 망설임도 없이 내 모든 설정을 둠 이맥스로 옮기기로 결심했다. 그 결과 지금은 마이그레이션 완료한지 한달이 조금 넘었고 아주 만족스럽게 사용하고 있다.

내가 이해한 둠 이맥스의 철학

둠 이맥스의 철학은 깃허브에서 직접 문서를 읽어보는 것이 가장 좋다. 내가 이해한 내용과 그에 대한 나의 멘탈 모델을 정리하자면 다음과 같다.

둠 이맥스는:

  1. 모던 패키지 매니저 이다. 이맥스의 기본 패키지 로더를 최적화하고 적극적인 Lazy Loading을 통해 빠른 부팅 속도를 제공한다. 그리고 다양한 매크로를 통해 패키지 설정을 편리하게 해준다. 둠 패키지 관리 시스템의 목표 문서에 좀더 자세히 나와있다.
  2. 이맥스 패키지 생태계의 메이저를 모아둔 큐레이터 이다. 둠에서는 그 목표 중 하나인 Reproducibility 를 달성하기 위해서 많이 쓰이는 패키지의 커밋을 고정시키고 이를 모듈 이라는 이름으로 관리하고 있다. 덕분에 나도 잘 모르던 메이저 패키지를 많이 알게 되었고 덕분에 지금 내 이맥스는 엄청나게 진화했다.
  3. 최첨단 이맥스 프레임워크 이다. 이는 두 가지를 내포하고 있는데: 최첨단 이라는 뜻은 개발 중 이라는 뜻이다(…) 실제로 그렇기도 하고. 입맛에 맞게 커스터마이징 하다보면 종종 이슈에 맞닥뜨리게 되고 그때마다 직접 해결해야 한다. 실제로 마이그레이션 도중 몇 번 이맥스가 먹통이 되어서 캐시를 날리고 다시 설치하기도 했다. 그래도 (숙련된 이맥스 사용자에게는) 트러블슈팅이 어렵지 않은 편인 것 같아 다행이다. 그리고 프레임워크 라서, .emacs.d 의 관리는 온전히 둠에게 맡기고, 우리는 우리에게 주어진 새로운 땅인 .doom.d 에서 둠 이맥스를 위한 설정 을 해야 한다. 이는 그동안 .emacs.d 에서 많은 것을 할 수 있었던 자유를 빼앗기는 기분도 들지만, 또 한편으로 많은 것을 대신해주고 기존의 너무나도 자유롭던 .emacs.d 설정에서 벗어나게 해줘서 마음이 홀가분 하기도 하다.

아쉬운 점

세상에 완벽한 물건은 없다. 아쉬운 점을 꼽자면 다음과 같다.

  1. eyebrowse 의 대용품으로 persp-mode 를 내장하고 있는데 이게 좀 아쉽다. 예를 들면 키 바인딩은 0번 작업 공간인데 UI 넘버링은 #1 로 되어 있다거나, 반드시 작업 공간을 생성해야 넘어간다거나 하는 등 소소한 부분에서 eyebrowse 보다 애매하게 불편하다. 그래서 eyebrowse 를 직접 써봤는데 아쉽게도 .emacs.d 를 둠이 관리하다 보니 이전 작업 공간이 제대로 복구가 안된다. 둠이 관리하는 경로를 가져와서 설정하면 잘 동작하긴 하겠지만, 그렇다고 또 그렇게까지 할 정도로 기본 작업 공간이 크게 불편하진 않아서 그냥저냥 쓰고 있다. 그리고 무엇보다 원작자의 계획도 추후에는 eyebrowse 로 넘어가는 것이라고 하니 기다려 보려고 한다.
  2. 아무래도 오픈소스 프로젝트이다 보니 개발 진행 사항이나 이슈 처리 속도가 아쉬운 것은 어쩔 수 없다. 이 글을 쓰는 시점에서도 이미 이슈가 500개 넘게 쌓여 있다. 오히려 그동안 3500개 가까이를 (거의) 혼자서 소화한 게 신기할 정도이다. 컨트리뷰터가 많긴 한데 사실상 원작자인 Henrik Lissner가 거의 다 혼자 개발 중이다. 그래서 패키지마자 메인테이너를 구한다는 짤막한 글이 있다 (…). 나도 언젠가 기여해보고 싶지만 이게 원작자가 2014년부터 혼자서 깎아오던 방망이라서 거대한 흐름을 파악하는데는 시간이 좀더 걸릴 것 같다. 게다가 엄청 급한 이슈가 아니면 리뷰에도 시간이 꽤 걸리기 때문에.. 아직 열린 PR이 88개나 있다…

좋은 점

사실 위의 두 가지 아쉬운 점 빼고는 모든 것이 만족스럽다. 왜 진작 둠 이맥스를 안썼을까 하는 생각이 들 정도로.

일단 이맥스 부팅 속도가 너무너무 만족스럽다. 과장 좀 보태서 아무런 설정없는 바닐라 이맥스를 켜는 것과 다름없는 속도다. “프로그램 켜는 속도가 대체 뭐가 중요해?” 라고 생각할 수도 있겠지만, 앞에서 말했듯 나는 이맥스를 다양한 환경에서 사용하고 있어서 이맥스가 켜지는 속도는 생산성에 큰 영향을 미치기 때문에 이 최적화는 너무 원하던 것이다. 지금은 그냥 켜면 곧바로 뜨고, 마지막 세션 로딩하면 필요한 패키지만 로딩이 되고, 작업하고 싶은 파일을 열면 또 거기에 맞는 패키지만 로딩이 되어서 속도가 엄청나게 쾌적해졌다.

몰랐던 패키지들도 많이 알게되었다. 예를 들면 예전에는 OCaml 개발에 필요한 기능을 직접 개발해서 모듈로 관리하고 있는데, merlin-company 라던가 이런 패키지들이 있는지 몰랐다. 나는 마음 편히 그걸 가져다 쓰면 된다. 심지어 원래 내 세팅이랑 거의 유사해서 적응조차 필요 없었다… 역시 이맥스 유저들은 다 비슷한가 보다. 거기다 각 언어 별 패키지 중 “가장 메이저(= 기능이 많고 안정성이 높은)” 들을 모아두다 보니 예전보다 훨씬 쾌적하다. 예를 들어 파이썬의 경우 원래는 elpy 를 쓰고 있었는데, 둠이 채택한 anaconda-mode 를 (아나콘다 없이) 쓰는 게 훨씬 쾌적할 줄은 정말 몰랐다.

무엇보다 둠 이맥스의 코드를 보면서 이맥스 리습 코드를 잘 짜는 방법을 배울 수 있었다. 항상 lexical-binding 을 한다거나, 네이밍으로 네임스페이스를 관리한다거나.. 이런 프랙티스를 코드를 읽으면서 엿볼 수 있어서 좋았다. 마이그레이션할 때 요긴하게 잘 써먹었다.

그리고 둠이 제공하는 .doom.d 의 구조를 통해서 에디터의 설정 파일을 어떻게 관리할지에 대해서도 멘탈 모델을 좀더 단단하게 굳힐 수 있었다. .doom.d 는 기본적으로 둠 모듈(패키지)를 구성하는 init.el 파일과 써드파티 패키지를 기술하는 packages.el 파일, 그리고 그 외 모든 모듈에 대한 설정을 기술하는 config.el 파일로 구성된다. 이때까지 나는 기능 단위로 리습 모듈을 작성했었는데, 예를 들어 OCaml 과 관련된 모든 패키지/설정/단축키/함수를 ocaml.el 에 작성하는 식이다. 그런데 이렇게하면 기능이 추가될 때마다 계속 파일이 늘어나게 되고, 또 기능마다 공통적인 의존성이 생기면 기능 단위가 아닌 공통 함수를 담은 패키지를 만들게 되는 등의 부차적인 귀찮음이 있었다. 하지만 이제 둠의 방식을 따르게 되면서 더 이상 이런 것을 고민하지 않게 되었다. 공식 모듈은 init.el 에, 추가적인 모듈은 packages.el 에, 나머지는 모두 config.el 에. 기존에 쓰던 패키지 대부분은 이미 공식 모듈의 부분집합이었고, 기능 단위로 작성했던 커스텀 함수들을 모두 config.el 에 때려박고 보니 600 라인 정도의 설정이 탄생하였다. 이 중 200 라인 정도는 패키지 별로 자주 사용하는 키 바인딩에 대한 주석이라서, 실제 함수는 400 라인 정도 밖에 안된다. 마음에 든다.

솔직히 예전에는 주변에서 이맥스에 관심이 있거나 혹은 이맥스를 시작하려고 하는 사람이 있다면 여러 가지 이유로 말릴 생각이 더 컸다. 에디터를 대하는 멘탈 모델이 일반적인 에디터와 조금 다른 탓에 흉흉한(?) 소문이 많아서 이기도 했지만, 다른 에디터에는 있는 화려한 기능을 “어떻게” 잘 찾아서 적용할 수 있는지 설명하는 것이 너무 어려웠기 때문이다. 원하는 기능마다 “공식”이라고 부를 만한 게 없기도 하고, 패키지도 GNU 랑 non-gnu 로 파편화되어 있어서 딱 “이거 쓰세요”라고 하기가 어려웠다. 하지만 둠 이맥스를 만난 지금은 help-with-tutorial 로 기본적인 컨셉과 키 바인딩만 익히게 한 다음 곧바로 둠 이맥스를 설치하게 알려주면 좋을 것 같다. 그만큼 둠에 포함된 모듈들은 여타 메이저 에디터들과 비교해도 손색이 없고 모양도 모던하다.

물론 요즘 누가 이맥스를 쓰냐고 물어보면 사실 할 말이 없다. 🥲