Elixir + Phoenix LiveView + Svelte, Why?

요즘 누군가에 의하면 기술 하나에 꽂혀서 다른 기술은 다 천대하고 있다고 하니, 용기를 갖고 좀 더 꽂혀보도록 하겠다.

Elixir

너무나 아름다운 파이프라인 오퍼레이터...

Elixir 를 좋아하게 된 건 순전히 pipeline 오퍼레이터 때문이었다. 한참 FP 를 해보겠다고 lodash/fp 를 많이 사용할 때였는데, 함수 하나에 여러가지 행동을 하는 코드를 작성하는 곳에 주로 사용하였다. 말하니 복잡한데 다음 코드라고 생각하면 쉽다.

const doSomething = flow( 
  split(‘,’),
  map((x) => x.toUpperCase()),
  filter((x) => x.startsWith(‘A’)),
);

한두개 쓸때는 괜찮았는데, 쓰다보니까 flow 를 매번 쓰는게 귀찮았고, 이것저건 관련 자료를 읽다보니 여기까지 도달했다. ES Next 제안 중 하나로, 위 코드와 같은 function chain 에서 |> 를 사용하자는 것이다.

const doSomething = (str) => str
  |> split(‘,’)
  |> map((x) => x.toUpperCase())
  |> filter((x) => x.startsWith(‘A’))

flow 는 기본적으로 higher-order function 이라 즉시 사용하려면 const value = flow(a(), b((x) => x), c())(x) 와 같은 구조를 택해야 해서 못생겼다 종종 실수를 했는데 pipeline operator  |>  는 꽤 괜찮은 표현식이라고 생각했다.

This proposal introduces a new operator |> similar to  F# ,  OCaml ,  Elixir ,  Elm ,  Julia ,  Hack , and  LiveScript , as well as UNIX pipes and  Haskell ’s &. It’s a backwards-compatible way of streamlining chained function calls in a readable, functional manner, and provides a practical alternative to extending built-in prototypes.

해당 제안 글에서 |> 를 사용하는 언어가 몇가지 소개되었는데 Node.js 말고 새로운 백엔드 언어를 공부해봐야지 하는 와중에 체인파트너스 암호화폐 거래소에 Elixir 를 사용했다는걸 알게되었고, “오?” 하는 마음에 둘러봤더니 패턴 매칭에서 무릎꿇었다 재밌어 보여서 관심을 갖게 되었다. 지금은 언어적인 면에서 패턴 매칭,가드, Atom 등과 같은 Feature 도 매력적이라고 생각하지만, 시작은 어쨋든 |> 이었다.

Phoenix

언어 자체를 공부하는건 나한테는 항상 관심 외의 일이었고, 뭐라도 만들어 보는 것이 Done by doing 이라고 쓰고 맨땅에서 헤딩한다고 읽음 빠른 길이라 생각해 웹 프레임웍을 찾아보게 되었다.

Phoenix Framework 는 Erlang Cowboy 를 기반으로 한 웹 프레임워크

피닉스는 Elixir 의 Ruby on Rails 라고 생각하면 된다. Opinionated framework 고, Elixir 의 개발자 José Valim 은 Ruby 개발자 였고, Phoenix framework 를 만든 Crhis McCord 또한 Ruby on Rails 개발자였기 때문에 여러모로 유사한 아키텍쳐를 가지고 있다. ORM 도 Ruby on Rails 의 그것과 상당히 유사하다. 실제로 Ruby on Rails 에서 LiveView 같은걸 만들다가 concurrency 이슈로 Elixir 로 전향했다 하니  어느정도 그럴만도 하다.

당시에 쓰려다가 포기한 점은 Phoenix 의 ORM 은 Ecto 라는 모듈을 사용하는데 Postgres 가 기본이고 MySQL 도 사용 가능하다. Phoenix 는 새로운 프로젝트를 생성할때 $ mix new [APP] 를 사용하는데, --no-ecto 라는 옵션을 주지 않으면 Postgres 설정 없이 기본 상태에서 서버를 실행할 수도 없다.

어릴때부터 나는 “귀찮다” 는 말을 많이 해서 어머니께도 쿠사리 꾸중을 들은 적이 종종 있을만큼 귀찮은 걸 싫어하는데, 그러다보니 새로운 프로젝트는 alter 걱정 없는 MongoDB 를 많이 쓴다. Ecto 는 DB 연결을 위해 Adapter 가 필요한데 MongoDB adapter 가 없고 (정확하게는 있긴 한데 active 하게 개발되진 않는 것 같다), ecto 없이 쓰자니 공부에도 큰 도움이 안될 것 같아 접어두었다

자랑은 아니지만 피닉스 컨트리뷰터고, 예 그렇습니다. 주석 한줄 고쳤구요, 자랑이 맞습니다.

아직까지는 Elixir 라는 언어와 ErlangVM 의 장점을 제외하고 Phoenix 는 Ruby on Rails 에서 많은 영향을 받았다는 것 외에 특별한 개성은 없다고 느껴졌다. 하지만 Phoenix LiveView 는 매력적인 툴이라고 생각한다. LiveView 는 브라우저에서 JS 를 몰아내자 서버에서 렌더링 된 HTML 을 웹소켓을 통해 조작하는 방식이다. 즉 websocket 을 통해 서버에서 state 를 관리하고 render tree 에서 변경된 부분을 browser 에 message 형태로 전달하여 DOM 를 업데이트하는 개념이라고 보면 될 것 이다. 딱 봐도 서버에 부담을 크게 전가될 것으로 보이는데 그게 맞다. 위에서도 언급했듯이 RoR 에서 concurrency 문제로 구현하기 어려웠기 때문에, 동시처리가 강력한 Erlang VM 기반의 Elixir 에서 만들게 된 것이다. 대표적인 SPA 라이브러리인 React 나 Vue.js 를 사용하기 어려웠던 PHP 나 Haskell 등도 영향받아 Laravel LiveWire 라던가 Haskell IHP 와 같은 기술도 개발되고 있다.

하지만 모든 처리를 서버에서 한다는 의미는 browser 의 널럴한 메모리를 거의 사용하지 않는다는 의미와도 연결되는데 file 처리, 이미지 lazyload 나 animation 등 브라우저에서 직접 처리하는 편이 편리한 부분은 LiveView 로 구현이 까다롭거나 거의 불가능한 부분도 분명히 존재한다.

Svelte

LiveView 단독으로 복잡합 인터렉션을 구현하기는 어렵고, 그래서 Frontend View Library 가 필요했다. 이 동네 깡패인 React 를 사용하는 것도 좋은 선택이겠지만, 개인적으로는 React 가 점점 개발하기 어려워 지고 있다고 생각하기 때문에 Svelte 를 선택했다. 가독성을 크게 해치지 않는 선에서 코드가 줄어들면 무조건 이득이라고 생각한다. React 는 hook 이 도입되면서 가독성에 다소 희생이 있었다고 생각하고, Svelte 가 이러한 면에서 더 편한 라이브러리 라고 생각한다.

Phoenix 에 Svelte 를 도압힌다는 부분에서는 좀 더 나아가면 Micro Frontends 라고 하는 괴상한 컨셉과도 연결되는 면이 있다. 물론 단순히 React, Vue, Svelte, Elm 등 원하는 걸 쓰자! 이런 건 아니지만, frontend 의 기술 스택에 대한 자유도를 높일 수 있다는 점에서 접점이 있다고 본다. dev.to 의 Stop Using React 라는 글의 댓글에 보면 이런 말이 나온다.

I think this is not the problem with React (well, apart from point 5), but with modern webdev in general. React is a good tool for single-page applications (so is Vue or Angular) but in many cases you simply don’t need and should not have a SPA in the first place.

사실 이게 맞다. 대부분의 경우 SPA (혹은 모던 웹 언어라고 해야 하나?) 는 필요 없다. 한편으로는 정말 복잡한 인터렉션이 필요한 웹 어플리케이션에서는 어차피 느려서 사용할 수 없다. 대부분의 Frontend 는 Data 를 Presentation 하는 역할이 주가 되고, 복잡한 인터렉션이 필요한 부분은 많지 않다. 반대로 복잡한 인터렉션이 필요한 부분에는 SPA 가 최적이라는 뜻이기도 하고.

짤봇 에서는 업로드에서 메모리에 이미지를 들고 있고 여러 처리를 한 후 서버로 리퀘스트를 보내는데, 이러한 일에서는 LiveView 와 같은 방식으로 구현하면 서버쪽 메모리에 부담이 크고 따라서 브라우저에서 처리하는 것이 바람직하다. Svelte 나 React 는 그러한 처리를 하기에 좋은 컴포넌트를 만들 수 있는 Library 지만, React Function Component 의 비동기 처리 방식에서 너무 고통을 받은 터라 Svelte 를 선택했다.

지금 생각해보면 Elixir 와 Elm 이 언어적으로 유사한 부분이 있어서 둘다 마이너여서 종종 함께 언급되는데, elm 쪽으로 가보는 것도 좋은 선택이었을 것 같다. 근데 얘는 진짜 너무 마이너라서 엄두가 안났다.


코드를 쓰려고 시작했는데 소개에 그쳤다. 실제 프로젝트 셋업 코드는 다음 포스트로 넘기고 대선.Elixir + Phoenix LiveView + Svelte 에 덤으로 Tailwind 까지 적용해보겠다.