๋๋ผ๋ง์ค์ปดํผ๋ ์น ๊ฐ๋ฐ ๊ทธ๋ฃน ๋ฉด์ ๊ณผ์ ๋ก ์ ์ํ single page application ์ ๋๋ค.
- Python 3.5.1
- Node 6.0.0
pip install -r requirements.txt
npm install
npm run build
npm run start
npm run test # for test
- ์น ํ๋ ์์ํฌ : Flask
- ORM : Flask-SQLAlchemy
- ๋ทฐ ๋ ์ด์ด : React
- ๋ผ์ฐํ : React-router
- ์ํ(๋ฐ์ดํฐ) ๊ด๋ฆฌ : Redux
- ๋ฆฌ์กํธ์ ๋ฆฌ๋ํธ ๋ฐ์ธ๋ฉ : React-redux
- ํ๋ก ํธ์๋ ํ๋ ์์ํฌ : Bootstrap
- ๋ชจ๋ ๋ฒ๋ค๋ง : Webpack
- ํธ๋์คํ์ผ๋ฌ : Babel
- ์๋ฒ์ฌ์ด๋ ์์กด์ฑ ๊ด๋ฆฌ : pip
- ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ์์กด์ฑ ๊ด๋ฆฌ ๋ฐ ์คํฌ๋ฆฝํ : npm
- ์๋ฐ์คํฌ๋ฆฝํธ ํ ์คํ : tape
๊ธฐ๋ณธ์ ์ผ๋ก ๋ฆฌ๋์ค์ ์ธ ๊ฐ์ง ์์น์ ๋ฐ๋ฅด๊ฒ ๋ง๋ค์์ต๋๋ค.
-
Single source of truth : ์ด ์์น์ ๋ฐ๋ฅด๋ฉด ์ฑ ๋ด์ ๋ชจ๋ ๋ฐ์ดํฐ๋ ํ๋์ store tree ๋ด์ ์ ์ฅ๋์ด์์ด์ผ ํฉ๋๋ค. ์ ๊ฐ ๋ง๋ ์ฑ์์๋ react-router๊ฐ ๊ด๋ฆฌํ๋ ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ๋ผ์ฐํ ๊ด๋ จ ์ ๋ณด๋ฅผ ์ ์ธํ ๋ชจ๋ ์ ๋ณด๊ฐ redux store์ ์ ์ฅ๋์ด ์์ต๋๋ค. ๋ฆฌ์กํธ๋ redux store ๋ด์ ๋ฐ์ดํฐ๋ฅผ props๋ก ๋ฐ์์ ๋ ๋๋ง ํ๋ ์ญํ ๋ง ๋ด๋นํฉ๋๋ค.
-
State is read-only : ์ฌ์ฉ์ ์ก์ ์ผ๋ก ์ธํด UI ์์ ๋ณํ๊ฐ ์ผ์ด๋๊ณ , redux store ์ ์ ์ฅ๋์ด ์๋ ์ฑ ๋ด ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ ํ์๊ฐ ์๊ฒผ์ ๋, UI๋จ์์ ์ง์ store๋ฅผ ๊ฑด๋๋ฆฌ์ง ์์ต๋๋ค. ๋์ ํด๋นํ๋ ์ก์ ์ react-redux๋ฅผ ํตํด dispatch ํ๊ณ , ์ด dispatch ๋ ์ก์ ์ ๋ฆฌ๋์์์ ์ฒ๋ฆฌํ๋ ์์ผ๋ก store์ ๋ฐ์ํฉ๋๋ค.
-
Changes are made with pure functions : ๋ฆฌ๋์๋ ๊ธฐ์กด์ ์ํ๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ , ๊ธฐ์กด์ ์ํ์ ์ก์ ์ ์ ๋ ฅ์ผ๋ก ๋ฐ์ ์๋ก์ด ์ํ๋ฅผ ๋ฐํํ๋ ์ํจ์(pure function)์ผ๋ก ์์ฑ๋์ด ์์ต๋๋ค.
Flux ์ํคํ ์ณ์ ๊ฐ์ ๊ตฌ์กฐ๋ก ์ด๋ฃจ์ด์ ธ ์๊ณ , ๊ฐ๊ฐ ์๋์ ๊ฐ์ ๋ถ๋ถ์ ๋ด๋นํฉ๋๋ค.
- Store : Redux(์ ์ฅ์)
- Dispatcher : React-redux
- View : React
๋ฐ์ดํฐ ํ๋ฆ์ ๊ธฐ์ค์ผ๋ก๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ๋งจ ์ฒ์ React๊ฐ ์๋ฒ์์ ๋ฐ์์จ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ทฐ ๋ ๋๋ง
- ๋ทฐ์์ ์ฌ์ฉ์๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ๋ ํ๋(e.g. ๋ฉ๋ชจ ์์ฑ)์ ํ ์ ์ก์ ์์ฑ
- React-redux๋ฅผ ํตํด ์์ฑ๋ ์ก์ ์ ์คํ ์ด๋ก dispatch
- ๋ฆฌ๋์์์ ๋น์ฆ๋์ค ๋ก์ง ์ฒ๋ฆฌํ๊ณ ์คํ ์ด์ ์๋ก์ด ์ํ ํ ๋น
- ์๋ก์ด ์ํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ทฐ ์ฌ ๋ ๋๋ง
- 2๋ก ๊ฐ์ ๋ฐ๋ณต
babel(ํธ๋์คํ์ผ)๊ณผ webpack(๋ชจ๋ ๋ฒ๋ค๋ง)์ ์ด์ฉํด ์ต์ข
์ ์ผ๋ก ์๋น์ค ์๋ฒ๋
_bundle.js
ํ ํ์ผ๋ง ์๋นํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ฝ๋์์ ์ฌ์ฉํ ES6 ํผ์ณ๋ค์ด IE์์๋
์ ์์ ์ผ๋ก ์๋ํ๋๋ก ํ๊ธฐ ์ํด babel-polyfill
์ CDN์์๋ถํฐ ๋ฐ์์ต๋๋ค.
โโโ README.md - ๋ฆฌ๋๋ฏธ ํ์ผ
โ
โโโ app/ - ์ดํ๋ฆฌ์ผ์ด์
ํด๋
โ โโโ __init__.py - ์๋ฒ ํ์ด์ฌ ๋ชจ๋ ์ด๊ธฐํ
โ โโโ models.py - ์๋ฒ ๋ชจ๋ธ ์ ์
โ โโโ views.py - ์๋ฒ ๋ทฐ ํจ์(API ์๋ํฌ์ธํธ) ์ ์
โ โ
โ โโโ src/ - ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ํด๋
โ โ โโโ actions.js - ์ก์
์ ์
โ โ โโโ components/ - ๋ฆฌ์กํธ ์ปดํฌ๋ํธ
โ โ โโโ containers/ - ๋ฆฌ์กํธ ์ปจํ
์ด๋
โ โ โโโ main.js - ๋ฉ์ธ ์๋ฐ์คํฌ๋ฆฝํธ (webpack ์ํธ๋ฆฌ ํฌ์ธํธ)
โ โ โโโ main.scss - ๋ฉ์ธ ์คํ์ผ์ํธ
โ โ โโโ reducers.js - ๋ฆฌ๋์ ์ ์
โ โ โโโ test/ - ํด๋ผ์ด์ธํธ ํ
์คํธ ํ์ผ ํด๋
โ โ
โ โโโ static/ - ์คํํฑ ํด๋ (๋น๋ ๊ฒฐ๊ณผ๋ฌผ)
โ โ โโโ _bundle.js - webpack์ ํตํด ๋น๋๋ ์๋น์ฉ ์๋ฐ์คํฌ๋ฆฝํธ
โ โ โโโ fonts/ - ๋ถํธ์คํธ๋ฉ์ด ์ฌ์ฉํ๋ ํฐํธ๋ค
โ โ
โ โโโ templates/ - ํ
ํ๋ฆฟ ํด๋
โ โโโ main.html - React container๋ฅผ ํฌํจํ๋ ๋ฉ์ธ ํ
ํ๋ฆฟ
โ
โโโ config.py - flask ์ฑ ์ค์ ํ์ผ
โโโ dramatic.db - SQLite3 ๋ฐ์ดํฐ๋ฒ ์ด์ค
โโโ package.json - npm ์ค์
โโโ requirements.txt - pip ๋ํ๋์ ๋ฆฌ์คํธ
โโโ run.py - ์๋ฒ ์์ ์คํฌ๋ฆฝํธ
โโโ run_with_dummy.py - ๋๋ฏธ ๋ฐ์ดํฐ๊ฐ ์๋ ์๋ฒ ์์ ์คํฌ๋ฆฝํธ
โโโ storeSpec.js - store ์คํ ์ ์ (์ฌ์ฉํ์ง ์๋ ํ์ผ)
โโโ webpack.config.js - webpack ์ค์
๋ฆฌ๋์๋ ์ํ์ ์ก์
์ ๋ฐ์ ์๋ก์ด ์ํ๋ฅผ ๋ฆฌํดํ๋ ์ํจ์๋ก ์ง์ฌ์ ธ์ผ ํฉ๋๋ค.
๊ทธ๋ฐ๋ฐ ์๋ฐ์คํฌ๋ฆฝํธ์ ๋ค์ดํฐ๋ธ Object API
์๋ ํ์ด์ฌ์ dictionary comprehension
๊ฐ์, ๊ธฐ์กด์ ๊ฐ์ฒด์ ์ด๋ค ๋ณ๊ฒฝ์ ๊ฐํ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ๋ฆฌํดํ๋ ๊ฐํธํ ๋ฐฉ๋ฒ์ด
์กด์ฌํ์ง ์์ต๋๋ค. ES6์์ ์ถ๊ฐ๋ Object.assign
๋ฉ์๋๋ฅผ ์ฌ์ฉํด ๋ชฉ์ ์ ๋ฌ์ฑํ์ง๋ง,
๊ฒฐ๊ณผ์ ์ผ๋ก ์ฝ๋๊ฐ ๋งค์ฐ verbose ํด์ก๊ณ , ๊ฐ๋
์ฑ์ด ๋จ์ด์ง๊ฒ ๋์์ต๋๋ค.
์ด ์ํฉ์ ๊ฐ์ ํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ ํด๊ฒฐ์ฑ
์ด ์์ต๋๋ค. ์ผ๋จ ๋ค๋ฅธ
์๋ฃ๊ตฌ์กฐ, ๊ตฌ์ฒด์ ์ผ๋ก๋ ImmutableJS์
Map
์๋ฃ๊ตฌ์กฐ๋ก ํ์ฌ ์คํ ์ด์์ ์ฌ์ฉ์ค์ธ ๋ค์ดํฐ๋ธ Object
๋ฅผ ์๋ฒฝํ๊ฒ
๋์ฒดํ๋ฉด์ ํจ์ฌ ๋ช
๋ฃํ ์ฝ๋๋ฅผ ์งค ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ฅผ:
labels: Object.assign({}, ...Object.keys(state.labels)
.filter(id => id != action.id)
.map(id => ({ [id]: state.labels[id]}))
)
๋ค์๊ณผ ๊ฐ์ด ๋์ฒดํ ์ ์์ต๋๋ค.
labels: state.labels.filter((key, value) => key != action.id)
๊ทธ๋ฆฌ๊ณ , redux์ combineReducers
๋ฅผ ์ด์ฉํด state์ ์ธ ํ๋(memos
, labels
,
checkedMemoIds
)๋ฅผ ๋ด๋นํ๋ ๋ฆฌ๋์๋ฅผ ์ชผ๊ฐฌ์ผ๋ก์ ํจ์ฌ ๊ฐ๋
์ฑ์ด ์ข์ ์ฝ๋๋ฅผ ์งค ์
์์ต๋๋ค. ์ง๊ธ ๋ก์ง์์ผ๋ก๋ memos
์ labels
๋ฅผ ๋์์ ์กฐ์ํ๋ ์ก์
(๋ฉ๋ชจ์
๋ผ๋ฒจ์ ๋ถ์ด๊ฑฐ๋ ๋ผ๋ ์ก์
)์ด ์กด์ฌํด์ memos
์ labels
์ ๋ฆฌ๋์๋ฅผ ๋ผ์ด๋์ง
๋ชปํ๋๋ฐ, ํด๋น ์์
์ ๋ ๊ฐ์ ์ก์
์ผ๋ก ๋๋ ๋ค์ ๊ทธ ๋์ ํ๋์ ํธ๋์ญ์
์ผ๋ก
๋ฌถ์ ์ ์๋ค๋ฉด ๋ถ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๊ณ ์ฝ๋๊ฐ ํจ์ ๊น๋ํด ์ง ๊ฒ์ด๋ผ ์๊ฐํฉ๋๋ค.
ํ์ฌ ์ด ์ฑ์ ๋คํธ์ํฌ ์ค๋ฒํค๋๋ฅผ ์ค์ด๊ธฐ ์ํด ์ด๊ธฐ ๊ตฌ๋์ ํ ๋ฒ๋ง ์๋ฒ์์ ์ ์ฒด ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๊ณ , ๊ทธ ๋ค ์ผ์ด๋๋ ๋ณํ์ ๋ํด์๋ ๋ณํ๋ ๋ถ๋ถ์ ๋ํ ์ ๋ณด๋ง ์ฃผ๊ณ ๋ฐ์ ํด๋ผ์ด์ธํธ ๋จ์์ ์ ๋ฐ์ดํธ๋ฅผ ์ฒ๋ฆฌํ๋ ์์ผ๋ก ๋ง๋ค์ด์ ธ ์์ต๋๋ค.
์ด ๋ ํ์ฌ๋ ๋ณด์์ ์ธ ์ ๊ทผ์ผ๋ก ์ผ๋จ ํด๋ผ์ด์ธํธ ๋จ์์ API ์ฝ์ด ๋ ์๊ฐ ๋ค ์๋ฒ ์ธก์์ ์๋ต์ด ๋ค์ด์์ ์์๋ง ์๋ง๊ฒ ํด๋ผ์ด์ธํธ ๋จ ์คํ ์ด๋ฅผ ๋ณ๊ฒฝํ๊ณ ์์ต๋๋ค. ์ด๋ฌํ ๋ฐฉ์์ผ๋ก๋ ๋ก์ง์ด ๊ฐ๋จํ๊ณ ์๋ฒ์ ๋ฐ์๋ ๋ฐ์ดํฐ๋ง ํด๋ผ์ด์ธํธ์์ ๋ณด์ฌ์ค๋ค๋ ์ฅ์ ์ด ์์ง๋ง, ๋คํธ์ํฌ ํ๊ฒฝ์ด ์ข์ง ์์ ์ ํด๋ผ์ด์ธํธ์ ์ก์ ์ด ์ผ์ด๋ ํ ์ค์ ๋ก ์ฑ์ ๋ฐ์ดํฐ ๋ณ๊ฒฝ์ด ๋ฐ์๋๊ธฐ๊น์ง์ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฐ๋ค๋ ๋จ์ ์ด ์์ต๋๋ค.
์ด๋ฌํ ๋จ์ ์ ๊ฐ์ ํ๊ธฐ ์ํด ๋๊ด์ ์ผ๋ก ์ผ๋จ ํด๋ผ์ด์ธํธ ์ฌ์ด๋์ ์ํ๋ฅผ ๋จผ์ ๋ณ๊ฒฝํ ๋ค API ์ฝ์ ๋ ๋ฆฌ๊ณ ๋ง์ฝ ์๋ต์ ๋ฐ์ ํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค๋ ๊ฒ์ ํ์ธํ ์ ์ ์ฒด ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๋ฐ์์ ๋ฐ์ดํฐ๋ฅผ ์๋ฒ์ ์ฑํฌ ์ํค๋ ๋ฑ์ ์ ๊ทผ์ ์ทจํ ์ ์์ต๋๋ค. ์ด ๋ฐฉ๋ฒ์ ์ฑํํ ์ ์๋ฅผ ๋ค์ด ํด๋ผ์ด์ธํธ๋จ์์ ์๋ก ์์ฑ๋ ๋ฉ๋ชจ์ id๋ฅผ ๊ฒฐ์ ํด์ค์ผ ํ๋ ๋ฑ ๊ท์ฐฎ์์ง๋ ๋ถ๋ถ์ด ์กฐ๊ธ ์๊ธฐ๋๋ฐ, Google Keep ๊ฐ์ ํ๋ก๊ทธ๋จ์ ๋ณด๋ฉด ํ๋ค์ด๋ ๋ง๋ค ์๋ ์์ ๊ฒ ๊ฐ์ต๋๋ค.
React์์๋ props๋ฅผ ๋ฐ์ ๋ ๋๋ง๋ง ํ๋, ๋ทฐ๋ฅผ ๋ด๋นํ๋ component์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐ์ดํฐ(state)์ ๋ํด ์๊ณ ์๊ณ ๋ณ๊ฒฝ์ ์ํ ์ก์ ์ ์ทจํ ์ ์๋ container๋ฅผ ๋ถ๋ฆฌํ๋๋ก ๊ถ์ฅํ๊ณ ์์ต๋๋ค. ์ด๋ฒ ๊ณผ์ ์์๋ ๋น ๋ฅด๊ฒ ๊ฐ๋ฐํ๋ ค๋ค๋ณด๋ ๋๋ถ๋ถ์ ์ปดํฌ๋ํธ๊ฐ container๋ก ๋ถ๋ฅ๋๊ฒ ๋์์ง๋ง, ๋ง์ฝ ์ข ๋ ์๊ฐ์ ๊ฐ๊ณ ์ฝ๋๋ฅผ ๋ฆฌํฉํ ๋งํด representation ์ ๋ด๋นํ๋ ๋ถ๋ถ์ component๋ก ๋นผ์ฃผ๊ณ container์๋ ๋ฐ์ดํฐ๋ง ๋ด๋๋ก ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ๋ฅผ ์คํํ๋ค๋ฉด ์ฅ๊ธฐ์ ์ผ๋ก ์ ์ง๋ณด์์ฑ์ด ๋ ์ข์์ง ๊ฒ์ ๋๋ค.
ํ์ฌ ์คํ์ผ์ํธ ์์์๋ ์๋ก์ด ๊ธ ์์ฑ, ๋๋ ๊ธ ์์ ์ ์ํ ํ๋ฌ์ด ํ ๋์ ์ฌ์ฉ์์๊ฒ ๋ค์ด์ค์ง ์์ต๋๋ค. ํน์ ๋ฉ๋ชจ๋ฅผ ์ ํํ ์ํฉ์์ ๋ค์ ๋ฉ๋ชจ ์์ฑ์ผ๋ก ๋์๊ฐ๊ธฐ ์ํ (๋ชจ๋ ๋ผ๋ฒจ LabelItem์ ์๋) ์ ๋ฉ๋ชจ ์์ฑ ๋ฒํผ๋ ์๋์ ์ผ๋ก ๋์ ๋์ง ์๋ ํธ์ธ๋ฐ, ์นผ๋ผ๋ง๋ง ์ ํด์ค๋ ์ฌ์ดํธ์ ํต์ผ์ฑ์ ํด์น์ง ์์ผ๋ฉด์ ์ด๋ฌํ ์ ํ์ง๋ค์ ์ข ๋ ๋์ ๋๊ฒ ํ ์ ์์ ๊ฒ ๊ฐ์ต๋๋ค.
์๊ฐ ๊ด๊ณ์ redux synchronous action creator ์ reducer ์ ๊ดํ ํ ์คํธ๋ง์ ์์ฑํ ์ ์์์ต๋๋ค. ์๋ฒ์ธก ์๋ํฌ์ธํธ, ๋น๋๊ธฐ API ์ฝ, ๋ฆฌ์กํธ ์ปดํฌ๋ํธ ๋ฑ์ ๋ํด ์ปค๋ฒํ๋ ํ ์คํธ๋ฅผ ์์ฑํ๊ณ ํ์ฌ ์ปค๋ฒํ๋ ๋ถ๋ถ๋ค์ ๋ํด์๋ ์ข ๋ ๋ค์ํ๊ณ ๋ง์ ์ผ์ด์ค๋ฅผ ์ปค๋ฒํ๋๋ก ํ ์คํธ ์ผ์ด์ค๋ฅผ ๋ณด๊ฐํ๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค. ์๋ฒ์ธก ํ ์คํธ๋ Flask-Testing ํ์ฅ์ ์ฌ์ฉํ๋ฉด ํด๊ฒฐํ ์ ์์ ๊ฒ ๊ฐ๊ณ , ๋ฆฌ์กํธ ์ปดํฌ๋ํธ ํ ์คํธ๋ Redux ๊ณต์ ๋คํ๋ฉํ ์ด์ ์์ ์ถ์ฒํ๋ Enzyme์ ์ฐ๋ฉด ๋ ๊ฒ ๊ฐ์ต๋๋ค.
- ESLint ๋ฅผ ํตํ ์คํ์ผ ๋ฆฐํ
- ๋ช ๋ช ๋ฒ ๋ verbose ํ๊ฒ ๋ณ๊ฒฝ
- (์ค์ ์๋น์ค๋ก ๋ง๋ค์) ์ ์ ๋ฐ ์ธ์ ๊ด๋ จ ๊ธฐ๋ฅ ๊ตฌํ
- (์ค์ ์๋น์ค๋ก ๋ง๋ค์) ์คํ์ผ์ํธ ๋ชจ๋ํ