不知道大家工作上是不是也常遇到過這些問題 ?
- 這段程式碼太長太亂,讀起來好吃力
- 這段程式碼之前 .. 好像 .. 有寫過但是不知道去哪裡找 ?
- 功能小改一下,但不知道改下去會不會導致其他功能壞掉
- 本來應該要寫單元測試的,但是程式寫完才發現測試不知道該怎麼測 ...
- 明明資料庫、CPU、記憶體資源都沒吃滿,怎麼效能這麼差
- 明明做的事情很簡單,怎麼消耗了好多計算資源
這些小問題隨著天長日久,累積起來就會像是滾雪球一樣滾出大問題。所以最好的方法就是在察覺問題的時候,就爭取馬上著手解決它。工作到現在我會覺得
每一個讓你難受的點,都是可以學習改進的機會
這段程式碼太長太亂,讀起來好吃力
函數式
- 觀察整個流程,把每一段流程取名字,如果一段流程能取用一個簡單的名字表示,通常就代表它適合抽出去變成另一個函式,例如:
- turnLeft 適合單獨抽出去
- turnLeftAndTurRightAndTakeTwoStep 不要寫這種函式!
- 有些操作實在是太常見太重複了,尤其是資料結構的操作、錯誤處理、非同步事件的處理,多認識並合理使用這些工具函式可以大幅降低程式碼複雜度
- 假設有一個二維陣列,我們要把它變成一維陣列,手刻會長這樣
let oldArray = [[...], [...], ...]
let newArray = []
for(row of oldArray){
for(item of row){
newArray.push(item)
}
}
- 利用 flatten 這個工具就可以非常簡單的達成目標
const oldArray = [[...], [...], ...]
const newArray = flatten(oldArray)
切面導向
- 利用函數式程式設計的技巧把流程命名後,如果有些流程滿足兩個條件就可以抽出去變成一個切面
- 這個流程不式目前流程的主要流程,只是輔助功能
- 這個流程會出現在很多不同的主要流程之中
- 例如驗證、監控、效能測試
這段程式碼之前 .. 好像 .. 有寫過但是不知道去哪裡找 ?
物件導向
- 觀察專案的資料夾結構,嘗試從專案層面上作分類,不同類型的專案有不同的設計方式,可以多看看找找架構設計的教學,以後端來說常常會有
- controller
- service
- model
- repository
- 每個層級往下都可以視需要再細分,但切忌過度設計,例如 model 還可以往下分
- 設計的時候可以留下一些文件,重要的是務必要確保團隊成員對這些分類有共識,不然過一陣子又亂掉了
- 依照這些分類方式對程式碼做
封裝
,把相關的資料跟方法包在一起,這樣一來只要找到目標類別,就能找到所有相關的功能
功能小改一下,但不知道改下去會不會導致其他功能壞掉
函數式
- 在進行資料操作時,盡量保持不可變動性(immutability),可以確保不會計算到一半被其他流程給陰了
- 盡量保持型別安全,型別設計越是注重細節,越容易在開發階段就發現型別錯誤
- 即使是弱型別
- 雖然說型別設計通常越細緻越好,但是也會同時導致開發成本上升,如何取捨是個問題
物件導向
- 良好的物件導向設計遵守 SOLID 原則,程式碼的小改動常常可以限制在一個檔案內
- 然而遵守規則同樣需要付出額外的成本,同樣需要進行取捨,以單一職責原則(SRP)來說
- 我們需要一到多個 PO 用來和資料庫互動
- 我們需要一到多個 DTO 來和不同客戶端互動
- 我們需要一個 Entity 作為以上 PO/DTO 轉換的核心
- 如果我的資料庫、資料處理、請求回應都是同一個資料型別,是不是就可以不遵守單一職責原則了呢?
- 有時候過度遵守設計原則同樣是過度設計
- 所以再說一次,不要過度設計
本來應該要寫單元測試的,但是程式寫完才發現不知道該怎麼測 ...
函數式
- 單元測試的目標是主要程式邏輯,不應該包含外部服務,以及他們可能造成的副作用
- 通常難的是如何把程式中的副作用跟主要程式邏輯切割開來
- 只要副作用都被剝離到主要流程,變成純函式,相信我,超級好測的!
物件導向
- 只要遵守依賴反轉原則,我們就可以實作簡單的虛假測試用介面來測試物件行為
明明資料庫、CPU、記憶體資源都沒吃滿,怎麼效能這麼差
響應式程式設計
- 把佔據大量資源的任務變成可觀察的資料流
- 篩掉重複的、沒意義的事件
- 現在應用層面的程式效能通常受限於外部資源讀寫,因此盡量依賴前期的資料流處理,減少外部資源讀寫
- 利用 coroutine / suspend / async await / concurrent ...設計妥善利用資源
明明做的事情很簡單,怎麼消耗了好多計算資源
程序式/結構式
雖然現在大部分時候計算資源式過剩的,但有時候抽象化太過頭,還是難免會有效能問題,這時候就得先找出哪些部分是瓶頸,再把這部分用程序式/結構式的寫作方式,用最簡單的硬體的執行方式重寫一遍