前任物品斷捨離 X 專案資料夾架構與收納 從把妹角度理解前後端如何和平相處

me
林彥成
2022-09-30 | 5 min.
文章目錄
  1. 1. 專案資料夾架構
    1. 1.1. 屬性分類
    2. 1.2. 功能分類
  2. 2. React.js 前端專案架構
    1. 2.1. 前端專案依屬性分類
      1. 2.1.1. Side Effect 處理
    2. 2.2. 前端專案依功能分類
    3. 2.3. 簡化架構的函式庫與框架
  3. 3. 後端專案架構
    1. 3.1. 後端專案依屬性分類
    2. 3.2. 後端專案依功能分類

專案資料夾架構

今天談談專案資料夾的結構,在還沒開始寫任何程式前,可以思考的是檔案要怎麼收納。

不知道各位情場高手都怎麼收納前男友或前女友們的禮物呢? 是按照物品種類來分類? 還是依照對象來分類? 或是直接丟掉?

隨著數量上升後管理的難度也會上升,以小編這幾年看過不少專案的經驗下來,覺得程式碼也跟收納一樣分成兩種流派

  1. 按照屬性分類
  2. 按照功能分類

接下來就讓我們看看兩種收納的差別吧!

屬性分類

會看屬性分得多細,若是分類比較粗一點,當衣服的數量變多就會變成很難找到整套運動服該如何正確搭配,屬性分類用衣服的概念來看就是分類成

  • 全部的內衣
  • 全部的內褲
  • 全部的褲子
  • 全部的上衣
  • 全部的外套

依專案來說,小編認為小專案較適合這種配置,比較適合拿來學習新知識時使用。

功能分類

當衣服變多的時候也知道怎麼依照功能找到全部相關的配套,不過由於依照功能區分,就會需要比較多的種類,功能分類就會是

  • 慢跑外套、上衣、褲子、內衣、內褲
  • 登山外套、上衣、褲子、內衣、內褲
  • 約會外套、上衣、褲子、內衣、內褲
  • 上班外套、上衣、褲子、內衣、內褲
  • 居家外套、上衣、褲子、內衣、內褲
  • 休閒外套、上衣、褲子、內衣、內褲

依專案來說,小編認為大專案較適合這種配置,每個功能都會有自己屬於的資料夾,對菜鳥工程師來說則是快樂小天地。

React.js 前端專案架構

一般會有元件、API、資料流、樣式相關分類。

React 是 component-based 的前端 UI 函式庫,通常會配合其他函式庫使用:

  • react-router: 處理 SPA 的路由
  • redux: 做統一的狀態管理,協助元件之間的溝通
    • redux-thunk or redux-saga: 處理 AJAX 的 side effect

前端專案依屬性分類

比較小的專案如果不包含 Redux 可以簡單分類

1
2
3
4
5
6
7
8
9
10
api/
├─ ProfileAPI.js
└─ UserAPI.js
components/
├─ Footer.js
├─ Footer.css
├─ Profile.js
├─ ProfileHeader.js
└─ ProfileHeader.css

搭配 Redux 後,主要就是增加元件之間需要溝通工具,會有以下特性:

  • 單向資料流
  • 公共的狀態儲存 (Store)

專案架構也會受到這種概念去分類:

  • actions: 觸發狀態改變用的 function
  • pages: 頁面容器元件
  • containers: 有連接 Store
  • components: 沒有連接 Store
  • reducers: 收到 action 後的資料邏輯

所以專案資料夾架構依照屬性去分類就會長成下面這個樣子,在完成任務的過程中需要在多個不同的資料夾中來回,覺得較適合小型專案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
└── src
├── actions
│ ├── typeOneActions.js
│ └── typeTwoActions.js
├── api
│ ├── apiHandler.js
│ ├── typeOneApi.js
│ └── typeTwoApi.js
├── components
│ ├── TypeOneComponent.jsx
│ ├── TypeOneListComponent.jsx
│ ├── TypeTwoComponent.jsx
│ ├── TypeTwoPageComponent.jsx
│ └── HomePageComponent.jsx
├── containers
│ ├── TypeOneContainer.js
│ └── TypeTwoPageContainer.js
├── pages
│ └── HomePageContainer.js
├── index.js
├── reducers
│ ├── typeOneReducer.js
│ └── typeTwoReducer.js
├── routes.js
├── store.js
└── utils

之前弄的小專案當例子,如果有加上 redux 的話,專案架構大概會長成下面的樣子,在比較簡單的專案中可以更簡化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
├── .storybook
├── src/
│ ├── constants/
│ ├── utils/
│ ├── pages/
│ ├── containers/ # containers 放置與 Redux 連接的相關元件,單元測試檔案為 `元件名稱.test.js`
│ ├── components/ # components 放置相關元件,單元測試檔案為 `元件名稱.test.js`
│ │ └── Root.js # 路由根目錄
│ ├── hooks/ # hooks 相關
│ ├── middleware/ # 資料處理相關
│ │ ├── API.js # axios 的 instance
│ │ └── redux-api.js # redux-api
│ ├── styles/ # 樣式檔們
│ ├── index.js # 程式入口
│ ├── serviceWorker.js
│ └── setupTests.js # 測試相關設定
├── .eslintrc # ESLint 設定檔
├── .prettierrc # prettierrc 工具設定
├── .travis.yml # 持續發佈工具
├── package-lock.json
├── package.json
└── README.md

Side Effect 處理

平常不太會去特別注意的名詞,我們用這個來分類 function 或元件:

  • Pure function or UI 元件
    • 每次送進去固定的輸入,出來就會是固定的結果
    • 相同的 props, 產生相同的 component,會放在 components 資料夾
    • 不寫商業邏輯
    • 不加入有 side effect 的 code
  • 有 side effect 的 function or 元件
    • 因為與狀態相關所以就會放在 containers 資料夾
    • AJAX,相關程式在 react hooks 中就會放在 useEffect,class component 就會放在 componentDidMount
    • AJAX 跟 redux,side effect 交給 redux-thunk 或是 redux-saga 去管理

最近開始接觸單元測試後,也深刻感覺到 side effect 越少,測試也越好寫,所以我想如果刻意去寫出好測試的元件,最後也會讓專案的結構變得更好偵錯與維護。

前端專案依功能分類

對新加入專案的工程師來說,最多的時間就是花在找尋相關的程式,其實可以透過小訣竅可以去優化前端開發者體驗,那在資料夾的架構方面,其實很簡單的透過把相近功能的程式碼放在一起 (Co-located) 就可以大量省去尋寶的時間,也能夠更方便的管理。

1
2
3
4
5
6
7
├── Login/
│ ├── SocialButton/
│ │ ├── LineButton.js # 社群登入的 Line 按鈕
│ │ └── FacebookButton.js # 社群登入的 FB 按鈕
│ ├── Modal/
│ │ └── ModalLogin.js # 登入的 Modal
│ └── index.js # 登入邏輯與主要 Layout

比較大的專案,就會把相關功能的元件都放在同個資料夾中降低相依性、增加內聚性,這樣在維護和修改時可以確定只要照顧好這個資料夾中的檔案即可。

使用 ReduxToolKits 後按照功能搭配分類,覺得較適合大型專案,依照功能就會分成

  • typeOne
  • typeTwo
  • typeThree

每個功能所需要的 action、components、containers、reducers 都會放在一起,所以在開發時,每個工程師都可以在獨立的資料夾中完成該次的任務。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
src
└── features
├── typeOne
│ ├── TypeOne.js
│ ├── TypeOne.styles.scss
│ └── typeOneSlice.js
├── typeTwo
│ ├── TypeTwo.js
│ ├── TypeTwo.styles.scss
│ └── typeTwoSlice.js
└── typeThree
├── TypeThree.js
├── TypeThree.styles.scss
└── typeThreeSlice.js

元件如果複雜一些也是依照功能區分,覺得較適合大一點的專案。

1
2
3
4
5
6
7
8
.
└── admin
└── UserCard
├── layouts
│ ├── UserCard.mobile.tsx
│ └── UserCard.desktop.tsx
└── UserCard.tsx

簡化架構的函式庫與框架

對於專案或是後端收到的資料,若沒有太多需要客製化的部分,可用底下函式庫與框架簡化:

  • storybook: 用故事書元件的角度設計,元件通常就能夠獨立且好測試
  • 將 Redux 常用的寫法封裝來減少寫太多重複的程式碼,簡化架構
    • Redux Toolkit
      • RTK Query
      • createSlice
  • axios,Promise based HTTP client for the browser and node.js
    • 前後端共構
    • 使用客製化 instance 的方式可以將收跟送的邏輯統一實作,減少重複的程式碼
  • Next.js,是一套以 React.js 生態系打造出來的完整的框架,幫我們配置了
    • AMP
    • 路由
    • CSS-in-JS
    • 靜態頁面輸出
    • 伺服器渲染

後端專案架構

通常 Mongoose 會搭配一個後端的框架來做使用,像是 Express 或是 Koa 等等,那在網路上有看到常見的兩種架構。

後端專案依屬性分類

依照屬性性,controller、routes、models 集中放置在各自的分類資料夾,覺得較適合小型專案。

1
2
3
4
5
6
7
8
9
├── src/
│ ├── controller/ # 資料庫 CRUD
│ ├── routes/ # API 設定
│ ├── models/ # Schema 定義
│ └── index.js # 程式入口
├── .eslintrc # ESLint 設定檔
├── package-lock.json
├── package.json
└── README.md

後端專案依功能分類

依照資料功能去做區分,把同個資料表的 model、controller、route 集中存放,覺得較適合大型專案。

1
2
3
4
5
6
7
8
9
10
11
├── src/
│ ├── entities/ # 按照資料表去區分
│ │ └── user/ # 使用者表
│ │ ├── model.js # Schema 定義
│ │ ├── controller.js # 資料庫 CRUD
│ │ └── route.js # API 設定
│ └── index.js # 入口
├── .eslintrc # ESLint 設定檔
├── package-lock.json
├── package.json
└── README.md

喜歡這篇文章,請幫忙拍拍手喔 🤣


share