snippod-starter-demo-app – Full Stack Architecture : React & Flux + Django REST Framework
일명 Single Page Application (SPA), 웹 어플리케이션은 네이티브앱과는 별도로 빠르게 성장하고 있는 플랫폼입니다. 여전히 웹은 누구에게나 친숙하고 접근성이 좋은 플랫폼이며, SPA는 네이티브와 유사한 경험을 줄 수 있기 때문에 사용성이 중요한 웹서비스는 웹앱으로 만들어 지고 있습니다.
2015년 초 창업을 준비하면서 웹앱으로 프로덕트를 준비해야 겠다는 생각과 함께 어떤 stack으로 웹앱을 구현할지가 새로운 고민이 되었었습니다. 그리고 Facebook이 공개한 React JavaScript 라이브러리와 Flux Architecture를 접하며 이를 이용하는 것이 가장 좋은 선택이라는 결론을 내렸고, 관련된 오픈소스들을 분석해보면서 사용법을 익히고 가장 스탠다드한 적용방식이 무엇인지 고민했습니다. 몇개월여 준비하여 snippod-boilerplate 를 만들었고, 이를 기반으로 2016년부터 Snippod 웹앱 서비스를 개발하고 있습니다. 그리고 최근(2016년 7월) 스닙팟(Snippod)의 베이스가 되는 boilerplate가 많이 변경되었고 더 이상 boilerplate 라고 명명하기엔 많은 기능들이 담기게 되어 데모 앱(Demo App) 형태로 GitHub 에 새로 공개하였습니다. 그래서 다시 현재 공개된 Snippod-Starter-Demo-App 저장소 코드에 대한 상세 설명을 블로그에 포스팅게 되었습니다.
대부분의 웹앱 샘플 프로그램의 서버사이드는 JavaScript End to End 구현에 따른 여러 잇점때문에 Node.js를 많이 사용하고 있었습니다. 그래서 처음에는 저 역시 Node.js로만 서버를 구현하려 했습니다. 하지만 향후 본 프로덕트를 보다 복잡한 데이터 모델을 사용하는 서비스로 발전시켜야 했기 때문에, 이전에 경험해본 Django ORM 모델을 활용하고 싶었고,1 그래서 Django으로 REST API 서버를 별도로 구축하게 되었습니다.
공유한 데모 앱은 React + Redux 프론트사이드와 Django REST 서버사이드로 Full Stack을 구현한 오픈소스이며 저장소에는 프론트 사이드와 서버 사이드 GitHub 저장소를 각각 Git 서브모듈로 바라보고 있습니다.
- Git Repository : https://github.com/shalomeir/snippod-starter-demo-app
- Git Repository (Front Side) : https://github.com/shalomeir/snippod-starter-demo-app-front
- Git Repository (Server Side) : https://github.com/shalomeir/snippod-starter-demo-app-server
- Git Repository For CodeLab (Front Side) : https://github.com/shalomeir/snippod-starter-demo-app-front/tree/codelab
- Git Repository For CodeLab 설치를 위한 설정 가이드 문서 : https://docs.google.com/document/d/1PPooko0uzUanYZMwKrEUXUWMD3FXCarKhVxGq5_Kip0/edit?usp=sharing
- Git Repository For CodeLab 강의 PPT 자료2 : https://drive.google.com/file/d/0B9ltVFRI_UMiTjdNYzc5UklQTVU/view?usp=sharing
그래서 본 포스팅에서는 공유한 Full Stack 데모 프로그램에서 사용하고 있는 기술 스택들과 세부적인 라이브러리들을 간단히 소개하고 본 기술 스택을 처음 사용하게 되면서 도움이 되었던 여러 자료들을 공유하고자 합니다.3
사용한 기술 스택
본 snippod demo app에서 사용한 주요 라이브러리 들과 간략한 소개는 다음과 같습니다.
Frontend side
- React: UI View 를 만들어 주기 위한 라이브러리. 만들고자 하는 부분들을 Component단위로 구현
- Redux: Flux 의 구조에 영향을 받아 단방향 데이터 흐름을 사용하게 해주는 상태 컨테이너
- normalizr: Flux 와 Redux 앱을 위해 JSON 응답 결과를 정의한 Schema에 따라 정규화 해주는 라이브러리
- Redux Form: Redux store를 통해 React 콤포넌트 내 form 데이터를 관리해주는 라이브러리
- Semantic UI: UI 스타일링을 위한 프레임워크로 Bootstrap과 유사한 역할을 하지만 더 자유도가 높은 편이며 커스터마이징을 위한 체계적인 스타일 구조를 별도의 빌드 프로세스를 통해 지원함
- Radium: React Inlins Styles을 보다 파워풀하게 사용하기 위한 라이브러리
- React-router: SPA 에서 중요한 Routing (url path) 처리
- react-router-redux: 구 이름은 redux-simple-router. React-router와 Redux store의 sync를 유지해줌
- React Intl: Yahoo에서 제공하는 국제화(i18n)를 위한 JavaScript 라이브러리 Format.js의 일부로 React 를 위한 바인딩 기능을 제공
- superagent: ajax call 을 쉽게 하기 위한 라이브러리
- Webpack: 모듈 번들러
Server side
- Django: 장고 웹 프레임워크
- Django REST Framework: REST API 서버를 만들기 위한 프레임워크
- psycopg2: PostgreSQL 을 장고에서 쓰기 위한 어답터
React + Flux(Redux)
React를 이용한 웹 어플리케이션을 개발할 때 Flux 아키텍쳐를 쉽게 구현하기 위한 여러 라이브러리를 고려하였었고 초기에는 reflux를 적용하였었습니다. 하지만 reflux는 ES6를 완벽하게 지원하지 않고 mixin 을 중심으로 만들어져 있어 React 버전 업데이트에 따라 다른 대안을 고려하게 되었습니다. 마침 새롭게 떠오른 redux가 현재 React 커뮤니티에서 독보적인 지지를 받고 있었기에 redux를 통해 전체 어플리케이션 구조를 관리하는 것으로 바꾸게 되었습니다. 처음 redux를 접할때는 비동기 API 핸들링이나 미들웨어 개념등 한번에 잘 이해가 어려운 부분이 있었지만 적용하고 사용하면서 redux를 사용하지 않았다면 현재의 복잡한 데이터 스토어를 관리하기 위해 얼마나 많은 부분을 직접 처만들고 관리해야 했을지 걱정이 되고 지금은 redux로 구조를 바꾼 결정에 아주 만족하고 있습니다.
redux는 개발자는 기능에 따른 함수인 ActionCreator 및 Reducer 들을 만들고 redux를 통해 조합해주면 모든 웹앱의 상태를 단일 Store로 관리할 수 있게 합니다. 제공한 오픈소스에서는 ActionCreator 및 Reducer 를 구현하는 과정에서 ‘Erik Rasmussen’님이 제안한 Ducks 방법을 통해 기능적으로 공통분모가 있는 ActionCreator 와 Reducer, Actions 를 하나의 파일로 관리하고 있습니다. 또한 JSON 데이터 처리를 하는 데 있어 개별 ID에 따라 모든 데이터를 ‘entities’에 단일 객체로 저장하고 list 는 별도의 pagination 객체로 처리하고 있으며 이를 위해 정규화 과정을 처리해주는 normalizr 라이브러리를 사용하여 자동화 하였습니다.
React-router
WebApp을 만들때 routing 처리는 까다롭지만 너무 중요한 요소 입니다. React-router가 그 역할을 잘 수행해줍니다. 또한 react-router-redux를 통해 Redux Store와 잘 동기가 되어 있습니다. 실제 router를 셋팅하는 데 있어 처음에는 조금 막막한데, 샘플 소스가 가이드가 될 수 있을 것 같습니다.
Semantic UI
UI 구현을 위해 사용하는 프레임워크로 본 오픈소스에서는 Semantic UI를 도입하였습니다. 일반적으로 많이 사용되는 Bootstrap과 비교해 보았을 때, Class 네이밍 룰의 의미적인 조합으로만 특정 Dom에 원하는 콤포넌트 스타일링이 적용되기에 사용하기 편리하고 제공하는 기본 콤포넌트들의 수준 또한 굉장히 높고 다양합니다. 최근 많이 적용되고 있는 Google이 제안한 Material 디자인을 활용한 React Meterial Component 도입도 검토하였으나 적용은 쉬운 반면 커스터마이징이 쉽지 않다고 판단되었고 Semantic UI는 유연하게 스타일 변경이 가능한 점이 특히 마음에 들어 도입하였습니다.
Semantic UI에서는 테마 적용 및 커스텀 테마를 작성하고 적용 하기 위한 별도의 스타일 선언 및 관리 체계가 구조화되어 있고 이를 위한 별도의 빌드 도구도 Gulp를 통해 제공합니다. 만약 체계적으로 CSS (SASS or LESS) 스타일을 관리하고 싶다면 Semantic UI에서 제공하는 스타일을 거의 사용하지 않아도 커스텀 테마 기능이 좋은 가이드가 되어 줍니다. 아쉬운 점이 없는 것은 아니지만 한번 사용해보는 것 추천 드립니다. Quora에 올라온 “Do you prefer Semantic UI or Bootstrap?” 질문에 대한 답변들도 참고해보세요~
Radium
React Inlins Styles은 React 커뮤니티가 성장하면서 이목을 많이 받고 있는 스타일 적용의 한 방안으로 React 에서 기본적으로 제공하는 기능중 하나입니다. React 만으로는 ‘:hover’ 또는 MediaQuery 등의 적용이 까다로운 편인데 이를 편하게 할 수 있고 그외 편의성을 향상시켜주는 라이브러리가 많이 존재합니다. 그중 저는 Radium을 적용하였습니다. Global하게 선언하는 CSS 스타일 외에 직접적으로 Style을 주입시키는 Inlins Styles 방식을 하이브리드로 함께 사용하는 것이 편하지만 정확히 어떤 경우에만 Inlins Styles을 통해 스타일을 선언할 지 명확한 기준을 세워서 사용하는 것이 좋을 것 같습니다. (그때 그때 귀찮지 않으려고 순간적으로 기준을 안 지킬 경우가 많아서 확고한 기준을 앞으로는 세우고 지켜야 겠다는 생각을 하고 있습니다.)
React Intl
국제화와 지역화 기능을 앱 프레임워크 차원에서 지원하기 위해 현재 탄탄하게 개발 발전하고 있는 Yahoo에서 제공한 JavaScript 라이브러리 Format.js의 React 바인딩 버전인 React Intl을 전면적으로 도입하였습니다. 쉽게 여러 언어로 설정을 변경할 수 있게 되어 있으며 번역 파일을 별도로 관리할 수 있도록 체계화 되어 있습니다. 참고로 GitHub 공유된 ‘redux-react-router-async-example’ 오픈소스에서 본 기능을 가져와 적용하였습니다.
superagent
ajax call 을 하기 위해 사용하였습니다. jQuery로 처리할 때보다 편한 점이 있어 사용합니다.
Django
서버 프로그래밍에선 비동기 프로그래밍이 더욱 까다롭기에 JavaScript보다 python이 더 편하것 같습니다. 게다가 Django Model 에서 제공하는 ORM이 아주 훌륭하고 공식 문서도 너무 잘 되어 있어요.
Django REST Framework
RESTful 한 API 서버가 서버와 클라이언트간의 기준이라고 할 때, 이 기준을 잘 지킬 수 있게 해주는 고마운 프레임워크 입니다. REST API를 제대로 다 이해하고 직접 구현했어야 한다면 굉장히 많은 시간을 이 부분에 쓰거나, 또는 무시하고 나중에 고생하거나 하지 않을까 싶습니다.
psycopg2
RDBMS 를 선택하는데 있어 Django 와 함께 사용한다면 PostgreSQL과 MySQL이라는 두가지 선택지 중에 고민하게 되는 경우가 많을 것 같습니다. 저는 처음에는 MySQL로 배포를 하다 변경사항 발생시 Migration 과정에서 여러가지로 애를 먹고 PostgreSQL로 바꾸었습니다. PostgreSQL에서는 Migration 중에 문제가 사라져서 초보인 저는 맘 편하게 고민하지 않고 PostgreSQL를 사용하고 있습니다. 공유된 snippod-boilerplate 소스에서는 SQLite3로 개발환경 셋업이 되어 있어서 배포를 하지 않는 다면 DB는 따로 신경을 쓰지 않으셔도 됩니다.
AWS 배포하기
Elastic Beanstalk은 로드 밸런싱, 스케일링 작업도 손쉽게 가능하고 모니터링도 쉽게 가능하다는 여러 홍보물을 접해왔었기에 이를 이용해봐야 겠다고 생각하고 이번에 데모 프로그램을 배포하는데 사용했습니다. 공유된 [‘Snippod Starter Demo App’]을 살펴보시면 Elastic Beanstalk에서 제공하는 것을 그대로 사용하였음을 알 수 있는데요. 개발환경에서 올려보는 것과는 여러가지로 다른점이 많아 초기 셋팅에 에로사항이 꽤 있었습니다.
혹시 Elastic Beanstalk에 Django 배포 셋업을 참고하시고 싶으시다면 공유된 소스 중 ‘./ebextensions’ 디렉토리를 살펴보시면 도움이 될 것 같습니다.
React Server-side Rendering
초기 React를 Node.js서버로 구현하고 싶었던 가장 큰 이유는 Server-side Rendering 구현이 훨씬 쉽다는 점 때문입니다. SEO를 위해서는 React Server-side Rendering이 반드시 적용되어야 하며, 첫 페이지 로딩 속도도 훨씬 빨라지기 때문에 Django 에서도 React Server-side Rendering을 할 수 있는 방안을 검토해 보았습니다.
본 데모 앱에서는 Node.js서버에서 Server-side Rendering 이 가능하도록 잘 구현된 boilerplate에서 코드를 가져와서 적용은 하였지만 아직 충분히 테스트 되지 못하여 option은 꺼둔 상태 입니다.
Reference
Instagram Stack
React에 처음 관심을 가지게 된 것은 역시 Instagram의 Pete Hunt가 발표했던 Instagram에서 React를 통해 SPA를 도입한 사례 소개 영상 때문이었고 이후 Instagram이 굉장히 효율적으로 서비스를 만들었다는 생각에 Instagram 관련 기술 정보 들을 많이 참고하였습니다. Instagram에서 적극적으로 정보를 공유해주어 참고할 수 있는 자료가 많았는데요, 개발팀이 스타트업 초기 고려했던 기술 스택에 대해 쓴 글인 ‘What Powers Instagram: Hundreds of Instances, Dozens of Technologies’은 한글로 번역된 포스팅도 존재합니다. 결국 본 데모 프로그램에 사용한 주요 기술들인 React+Django+PostgreSQL 은 Instagram 과 정확히 일치합니다.
GitHub Open Source
GitHub 에서 React, Flux, Django 및 그외 사용한 라이브러리들에 관련된 샘플 프로그램들은 되도록 많이 설치해 보려했고 굉장히 도움이 많이 되었습니다. 개별적인 소스 들 중에 본 데모 프로그램에 직접적으로 영향을 준 소스는 아래와 같습니다.
Front side
- React Redux Universal Hot Example : React 와 Redux를 적용한 boilerplate 중 가장 파워풀한 소스 중 하나로 현재 데모 앱의 기반이 됩니다.
- Redux Real-World Example: 특히 normalizr를 paginate하는 방식을 잘 보여줍니다.
- gaeron’s Flux React Router Example : 한번 GET 해온 데이터들을 Page 나 Sorting 옵션이 바뀌어도 잘 보관하고 있도록 하는 것은 중복적인 서버와의 통신을 막고 훨씬 빠르게 페이지간 이동을 가능하게 해주는 데요, 이러한 방식의 Store를 구현하기 위해 gaeron이 공유한 소스가 굉장히 도움이 되었습니다.
- redux-react-router-async-example : React Intl적용 및 빌드 도구는 본 예제소스에서 가져왔습니다.
Server side
- Thinkster.io Django and AngularJS Tutorial : Django가 Template이 아닌 AngularJS를 주로 사용하는 케이스로 Django REST Framework를 사용하고 있었기에 서버 측면에서 참고가 되었습니다.
본 정보는 스닙팟 에서도 #주제 별로 공유되고 있어요.
🔗 # React 정보 모음 팟
🔗 # Django 정보 모음 팟
🔗 # AWS 정보 모음 팟
🔗 # 어바웃 스닙팟 정보 모음 팟