React+Redux+Next.js vs Flutter+Firebase

꽤 오랜 시간을 리엑트로 작업을 해왔던 것 같다. 미국에 와서 유라임을 만드는 데에 처음에는 pure한 JS로 개발을 하다가 AngularJS를 알게되고, 처음으로 backend/frontend의 분리를 알게 되었다. 난 당시만 해도 이게 최선인 줄 알았다. 그러다가 dom에 더덕더덕 붙이게 되는 앵귤러에 특히나 퍼포먼스적인 부분에서 질리고 나서는 대안을 찾다가 리엑트를 알게 되었고, 지금까지도 프론트앤드는 주로 리액트를 통해서 개발하곤 하였다. create react app이 얼마나 편하던가. 그냥 토이 프로젝트를 시작하기에도 이만한게 없다. MERN스택만 있다면, TypeScript까지 적용되면 컴파일 타임 체크까지 대부분 지원되니 이를 쓰지 않을 이유가 없었다.

하지만 내가 줄곳 개발자를 뽑지 않고 스타트업을 운영하다 보니 느꼈다. 자바스크립트는 너무나도 발전이 빠르다는 것을. 아니, 정확히는 자바스크립트라기 보다는 이에 파생되는 다양한 라이브러리 말이다. 리엑트도 그중 하나고 타입스크립트도 마찬가지다. 몽고DB도 비슷한 맥락이겠지. 솔직히 자바스크립트, 쉽기도 하지만 잘못 사용하면 정말 미친듯한 미궁으로 빠져버린다. 버전 하나만 잘못 고쳐도 이건 대체 어디서부터가 잘못됬는지, 디버깅을 하다보면 하루, 이틀, 일주일이 순식간에 지나가버린다.

그러다 최근에 학위를 받는다고 근 1년정도 코딩에 손을 대지 못했다. 덕분에 발생하는 현상 덕분에(?) 나는 이제 더 이상 리엑트가 답이 아니라는 결론을 내렸다. 아무리 내가 하이브리드 앱을 지향하지만, 리엑 네이티브 등으로 대표되는 리엑트 생태계는, 솔직히 내가 그간 배워온 약 4년이란 시간이 너무너무나도 아깝지만, 더 이상 이 스타트업에서 리엑트는 썩 나은 수단이 아니라는 생각이 들어서 그렇다.

package.json을 1년만에 업그레이드 해본 결과. 안바뀐게 없다.

물론 오픈소스 생태계가 생기고, 다양한 프로젝트가 생기는 것은 좋다. 리엑트만 해도 왠만한 것들은 내가 원하는 모든 것들이 존재한다. 특히 UI적으로 말이다. 그래서 가져다 쓰기도 편하고 다 좋다. 좋은데, 리엑트를 13버전부터 써온 입장에서는 특히나 그 컴포넌트 관리나 자원관리가 너무나도 힘들다. 정말 오죽하면 예전에 form -> post방식이 좋게 느껴질까. 대체 내가 프론트앤드에서 그렇게까지 verify를 해주거나 전처리를 해줘야 하는 이유는 무엇일까. 어차피 소스 까보면 로직이 다 보일텐데.

자원관리

이 Redux나 Thunk 로 대표되는 리액트에서의 자원관리도 그렇다. 솔직히 정말 이를 이해하는데 많은 시간이 걸려서 뭐 액션이니 thunk패턴이니 그런거 잘 짜뒀다. 그런데 이것도 시간이 지나고 액션이 많아질수록 관리가 너무나도 힘들다. 게다가 어차피 callback에 액션 연결해서 쓸꺼면 차라리 그냥 callback단계에서 다 처리하면 되지 않을까, 난 솔직히 리엑트에서 정말 별짓을 다해봐도 아주 깔끔하게 MVC가 분리가 안됬다. 모델 동기화? 그런거 없다. 물론 Props를 좀 쓰면 되지만 이게 strict하지 않으니 바쁘면 안쓰게 되고, axios에서 리턴된 값에 대한 verification은? 거기서 한두개가 빠져도 솔직히 모른다. 모든게 유연하기 때문이다. 때문에 예상치 못한 버그가 발생한다. 나는 잘 되는데, 상대방은 안된다. 이런 버그가 한두개던가? 5년간 진짜 족히 수백개는 발견한 것 같다.

Next.js

그리고 SEO때문에 3년전에 SSR로 돌리면서 Next.js (지금은 Vercel)을 썼다. 사실 Next.js도 익숙해지면 상당히 편하긴 한데, 얘도 익숙해 지려면 _app.js나 _documents.js이런 개념 알아야 하고 가장 중요한 것은 자꾸만 SSR인데 이게 서버단에서 실행될지 프론트 단인지 헷갈린다. next.config.js만 봐도 지금은 모르겠지만 SCSS나 CSS만 쓰려 해도 결국 Webpack도움을 받아야 한다. 사실 무엇보다 Next.js는 설정이 너무너무너무너무나도 많아서 아주 지겨워 죽겠다. 예컨데 next-i18n같은걸 쓰려면 뭐 또 설정 바꿔주고 거기다 browser language detection같은거 쓰려면 middleware를 또 설치하고, 추가해줘야 한다. 이건 마치 끝없은 가지치기 같다고 해야할까? fork에 fork를 비롯해서 계속해서 모듈간의 의존성 관계가 생기다 보니깐 이건 절대로 혼자서 관리가 안된다. package.json에 50개 이상 추가되면 진짜로 너무나도 힘들다. 결국 Next.js도 하나의 모듈 아니던가. 거기다 좀더 커스토마이징 하려면 Node.js Express써야하는데 그럼 또 커스톰 라우팅에서 갑자기 막 뭐 토큰검증이라든가 이것저것 추가하게 된다.

플러터

지난달에 나는 플러터를 배운적이 있다. 부트캠프로 자격증까지 수료했다. 생각보다 플러터가 강력한 것은 확실하다. 솔직히 말해서, 깔끔하다 해야할까. CSS나 dom에서의 액션과 비슷한 프로퍼티가 있고, 그것들이 마치 자바Swing처럼 잘 바인딩 되어있다. 아직까지는 자원처리 입장에서는 살짝 헷갈리긴 하는데, 어쨌건 페이지가 전체적으로 트리구조로 되어있고, State management가 리엑트의 그것보다는 확실히 깔끔하다. 리덕스를 썼을때 그것과 비교하면 천국같음.. 다만 전체적인 UI가 Material UI기 때문에 조금 걱정되기는 하지만, 당장 나는 모바일 개발보다는 웹개발이 우선이기 때문에 뭐 Cupertino UI라던가 그런걸 굳이 지금 따질 필요가 없다.

무엇보다 Dart라는 언어가 마음에 든다. 약간 자바랑 자바스크립트, C++의 짬뽕같은 느낌이긴 한데 어쨋든 어느방면으로 봐도 세련된 언어임은 틀림없다. 그리고 사실 내가 구글을 다니는 만큼 얻을 수 있는 정보도 많겠지. (회사 사랑 ㅋㅋ) 하지만 단점이 많다. 무엇보다 모바일 우선적인 프레임워크라서 내가 굳이 지금 모바일을 고집하지 않는 이상 사실상 필요는 없다. 또한, 새로운 언어라서 전체적인 프레임워크를 이해하는 데에 진입장벽이 있다. 마치 내가 Angular에서 리엑트로 전환할 때 몇개월에 걸쳐서 그 패러다임을 이해한 것처럼 말이다. 그리고 가장 큰 문제점은 SSR이 안된다는 것. 이건 매우 치명적인데, SEO를 통해서 계속해서 트래픽을 늘려야 하는 앱 입장에서 SSR이 적용되지 않으면 이건 하나마나라는 결론이다.

결론?

하지만 여러 고민끝에 난 플러터를 사용하지 않기로 했다. 배운게 조금 아깝긴 한데, 글쎄 간단한 모바일 앱 개발은 Swift와 Swift UI가 더 편한 것 같은 생각이다. 그리고 무엇보다 SSR이 안되는 부분이 가장 치명적이다. 물론 리엑트도 나름대로 단점이 많지만, 최근에 많은 리엑트를 느리게 하는 것들이 해소가 되었고 무엇보다 리엑네이티브를 통해 소스코드 쉐어를 하면서 하이브리드 앱 개발이 가능하다는 장점도 있으니, 굳이 플러터와 다트를 또다시 배워서 할 필요는 없다는 생각이다.

그리고 위에 언급은 안했지만 파이어베이스, 정확히는 Firestore가 필요하다. 사실 유라임을 운영하는데 한달에 $150 정도가 소비된다. Kubernetes로 두개의 백엔드 인스턴스, 그리고 MySQL (Cloud SQL) 이 그정도 된다. 그런데 파이어베이스 쓰면 On-premise이기 때문에 장기적으로 운영을 해야하는 입장에서는 이를 사용하는게 맞는 것 같다. 그리고 사실 REST라는 백엔드는 뭔가 SaaS프로그램을 만드는 데에는 도움이지만 나처럼 타임라인을 가지고 있는 입장에서는 차라리 빠른 binding과 hooking이 필요한 것 같다. 뭐 좀더 manipulation이 필요하면 cloud function으로 간단히 노드로 만들어서 쓰는게 더 낫다. 지금처럼 괜시리 Kubernetes로 Play Framework로 REST하나 돌려다 썼는데 이건 비용도 $100이상 나오는 것 뿐만 아니라 사실 별로 트래픽이 없는 지금의 입장에서는 낭비라는 생각이다.

어쨌든, 언제 다시 유라임을 개발할지는 모르겠지만 새로운 유라임 버전2는 백엔드는 파이어베이스를 기반으로 가되, 타임라인이나 뭐 batch작업 같은 것은 SaaS나 Cloud Function을 노드+익스프레스로 작업해서 만들고, 프론트앤드는 next.js기반 SSR의 리엑트인데, 여기다 조금 보태서 TypeScript로 짜고 싶다. 그래서 최신 리엑트 버전을 근간으로 그간 만들었던 컴포넌트를 가져와보면서 쓸때없는 리소스들 정리하고, 그리고 CI/CD를 Cloud Function과 연결해서 push하면 굳이 테스트 필요없이 바로 배포되게 만들고 싶다. 아마 그렇게 된다면, 굳이 사용자 트래픽이 많지 않은 이상 서비스에 큰 요금을 구하지는 않을것이라 생각한다. 뭐 이런 가정도 일단 개발을 해야지.. 라는 생각이지만 ㅎㅎ 여튼 고민 끝!