go언어 Web Framework 선택 하기

얼마전부터 nodejs가 아닌 다른 언어로 Web Application만들기에 도전하고 있다. 굳이 nodejs가 아니라 다른 언어로 만들기 시작한건 nodejs가 구리다던가 callback hell을 피하기 위해서가 아니다. 물론 TJ는 그게 신물난다고 nodejs를 떠나서 go 언어를 택했다고 했지만 그럼에도 불구하고 nodejs는 쓸만하니까 아무래도 좋다.

TJ에 굳이 영향을 받을 것도 아니면서 굳이 go를 고른 이유는 새로 구상하고 있는 웹 어플리케이션이 websocket를 아주 hard하게 써야만 하기 때문이다. 더군다나 메모리와 성능제약이 심한 raspberry pi를 사용해야 하기 때문이다. websocket을 위한 뛰어난 라이브러리를 두고도 굳이 nodejs를 피한것은 native로 compile되면 좀더 빠를것 같기 때문이다. nodejs는 v8의 뛰어난 성능을 이용해서 훌륭한 performance를 뽑아내지만 아무래도 그 태생적 한계는 있을수 밖에 없다. 벤처마크를 보면 더 처절한데 go언어의 Web Framework인 revel 보다 순수 nodejs가 더 느리다. 심지어 plain text도 느린걸로 보아 더 말할 여지가 없다.

Web Framework종류

go 언어도 패키지 관리자가 있기 때문에(요새 추세이기도 하다) 다양한 framework들이 있다. 마침 아주 친절한 한 외국 블로거 분이 잘 정리 해 두셨다.

따로 설명이 필요없을 정도로 정리를 잘해두셨는데 그냥 설명만 보고 결정할 수는 없는 노릇. 다 조금씩 써보긴 했다. 그 첫인상(?)들은 다음과 같다.

Revel

마치 Play Framework을 보는 듯한 느낌을 준다. 그야말로 framework라서 구조적 제약이 심한 편에 속한다. View는 특정 폴더에 짜야 하고 Controller의 Name과 View의 Name을 동일하게 맞춰줘야 하는 등 은근 짜증나는 부분이 한두군데가 아니다. 확장성은 매우 좋으나 이상한데서 제약이 있는 경우가 있다. 마치 play framework 2.0.x 버전을 생각나게 할만큼 사용성이 좋지않다. 예제중에 Play Framework와 완전히 동일한 예제가 있는거 보면 영향을 받은것 같긴하다. 자동 재시작 모듈도 자체 포함도 그러하고 conf에 라우팅 파일이 따로 존재하며 ORM을 쓰려고 하는것 까지 완전 판박이다.

Martini

Express에 영향을 많이 받은듯 한 Framgework다. 실제 routing이라던가 middleware의 방식이 많이 닯아 있다. 제작자가 아예 밑에 영향 받았다고 써놓기 까지 했다. 한글 번역이 존재하며 nodejs를 쓰던 사람이라면 매우 쉽게 적응할수 있다. 이쪽도 Live Loading에 다른 패키지를 쓰는것 하며 활성화된 3th party middleware까지 express 판박이다. 심지어 Logger모듈이나 static router도 판박이다.

gocraft/web

첫인상은 Martini의 열화판처럼 느껴진다. 실제로 기능이 다양하지않다. 기본적인것만 다 챙겨논 느낌이며 Router와 middleware구조만 갖추고 있다고 느껴질수도 있다. 하지만 Context를 자유롭게 붙일수 있고 subroute를 철저하게 지원하며 가장 큰 장점인 라우팅 효율이 O(log(N)) 라는 점이 있다. 일반적으로는 O(N)이지만 트리방식의 라우팅을 통해 가장 빠른 라우팅을 보여준다. 이거 하나만으로도 엄청난 장점이며 심플함이 강점이다.

Gorilla

Web Framework는 아니고 Toolkit이라는데 Framework에서 구조적인 것만 빼놓은 거라 기능이 다 있다. 구조를 너마음 대로 하라고 그런것 같은데 가장 자유도가 높다. 기능이 좋을 뿐만 아니라 기본 http를 사용할수 있기 때문에 다른 Framework랑 같이 사용할수 있다. 이거랑 gocraft랑 같이 사용하면 좋은 시너지 효과가 발생한다.

그래서 뭘선택할것인가.

넷중에 websocket 지원은 Revel과 Gorilla가 된다. Revel은 Play Framework의 그 방식대로 websocket을 지원하는데, 이게 은근 짜증난다. 튜토리얼에서 설명한 방식대로 하기에는 정말 튜토리얼만 가능하기 때문에 고민좀 해야 한다. 결국은 있으나 마나… Revel은 구조적 제약을 매우 심하게 걸기 때문에 원하는 프로그램을 쉽게 만들기 어렵고 ORM을 붙인다고 붙여놨는데 도무지 왜 붙여놨는지 모르는 수준을 보여준다. 물론 Revel의 문제는 아니고 gorp라는 외부 모듈의 문제이긴 한데 ORM이라고 하고는 “select from ~” 절을 그대로 사용한다. 그렇다고 DB접속기 아닌가 라고 생각하면 Insert는 객체로 한다. 뿐만아니라 session은 오직 cookie로 내릴수 있는 데이터만 담을 수 있다. 따라서 보안에 민감한 자료는 사용자가 알아서 빼줘야 하고 매 요청마다 string으로 직렬화 할수 있어야 한다. 이는 session을 cryptographically signed cookie로 저장하기 때문인데 뭐 분산 처리나 로드벨런스에는 확실히 유리하지만 이걸 끌수 있는 옵션이 없다. 즉 무조건 강제. 이런점은 한두개가 아니다.

Gorilla는 구조적인 측면에서는 아주 자유롭기 때문에 그냥 사용하면 되지만 처음 접하는 사람은 “이게 뭐냐”라는 느낌이 든다. 도저히 뭘 해야할지 감도 안온다. 문서가 부족한건 덤. 기능은 확실히 좋고 작은 모듈로 나누어 져있어서 써먹기 좋지만 이것만 쓰기에는 애매하고 다른 무언가와 사용해야 한다.

하지만 Gorilla 덕택에 websocket이 지원되지 않는 Framework라도 손쉽게 websocket을 사용할수 있는데, martini와 gocraft는 구조적인 부분이 조금 자유로운 편이고 스타일도 Express와 닯아 있다. 하지만 martini는 reflection을 많이 써서 성능이 떨어질뿐만 아니라 Type-safe하지도 않다 (참고). 이는 종종 커다란 문제를 불러일으킬 가능성도 있지만 반대로 매우 유연하다고 할수 있다. 다시말해서 성능은 아무래도 gocraft가 좋은데 martini가 더 유연하다. 그래서인지 martini가 middleware를 더 많이 보유하고 있다.

이중에 무엇을 선택해야하는지는 여러분의 자유이다. 만약 nodejs를 오래 했었다면 martini가 적절할것이다. 만약 spring이나 play framework 혹은 pure java servlet을 오래 사용했다면 Revel이 적절할 것이다. 성능을 중시한다면 gocraft를 선택하는것이 좋을 것이다.

단, Revel은 Google App Engine에서 동작하지 않으니 주의해야 하겠지만 말이다.

2018.1 추가 : 현재 martini 는 중단되고 대신 https://github.com/gin-gonic/gin 이 그 자리를 차지하고 있다. 요새 거의 모든 프로젝트를 gin 을 사용중인데, 모든 케이스에서 사용하기 좋다.