大腦極限與可讀性之探討
如果各位是工程師,那麼在日常開發中應該時常聽到可讀性這個詞,像是:這段程式可讀性真差、這段程式可讀性不錯,但我們有想過什麼程式碼才具有可讀性嗎?你知道大腦極限跟程式碼可讀性之間的關聯嗎?
此篇文章希望有效的解釋大腦運作與程式碼可讀性之間的關聯係,也希望能讀者看完能夠了解以下目標:
- 了解大腦系統基本運作。
- 了解大腦記憶運作。
- 了解什麼是可讀性。
- 了解哪些設計容易破壞可讀性。
- 了解提升可讀性的基本建議。
大腦系統運作
大家知道嗎?我們的大腦中有兩個系統,分別是:
- 系統一:通常用來處理簡單、不需要消耗大腦資源的工作,像是:已經養成的盲打習慣、一天中所有的瑣碎小事,處理事情容易快速跳到結論。
- 系統二:通常用來處理複雜、消耗大腦資源的工作,像是:處理困難的數學問題、撰寫良好設計的程式,處理事情需要深度思考。
了解上述兩個系統後,對我們寫程式碼有什麼幫助呢?
我們至少知道:當遇到困難實作要完成時,如果一時半刻沒辦法找到解決辦法,依賴系統一會想要快速得到堪用的結論,但解決方法欠佳;依賴系統二則會讓我們進行深度思考,使用多種設計方式進行比較,找出較好的解決方法。
系統一有只使用腦袋目前想到的資訊去做決策的特性,即便你深入理解很多設計原則,但腦袋如果目前只有一個原則,系統一便會只使用一個原則去設計,這也是為什麼有時候會寫出爛code的原因,因為考慮不周到。
系統二相較於系統一有嘗試使用更多的資訊進行決策的特性,會把情境、限制、不同的解決辦法依依考慮,對於重大系統設計有較好的幫助。
大腦記憶運作
大腦的記憶運作大致上分為兩種,分別是:
- 短期記憶區:用來存放隨時遺忘的資訊,儲存容量為7+-2。
- 長期記憶區:用來存放重要、不能隨便遺忘的資訊,存儲容量很大,但需要時間積累才能被好好存放。
還記得上述的大腦系統嗎?如果加上大腦記憶運作一起考慮,我們能知道以下幾件事:
- 當新資訊量過大時,會導致短期記憶區負荷不了,系統一會想要直接跳到結論,以節省腦力的消耗。
- 當維護複雜程式碼時,無法使用短期記憶區,需要長期記憶區與系統二的幫助才能理解程式運作。
上述觀察也是為什麼複雜程式碼容易出錯的原因,遇到過度複雜程式 > 短期記憶區無法使用 > 系統一想要降低腦力消耗選擇快速跳到結論 > 導致Bug出現。
上述觀察也是為什麼複雜程式碼恐怖的原因,遇到過度複雜程式 > 強迫使用系統二與長期記憶區 > 大量消耗腦力 > 越維護越怕。
大腦極限來定義可讀性
所以對於大腦來說怎樣才有可讀性呢?
能夠使用系統一與短期記憶區就能夠理解的程式碼,不需要過度依賴系統二與長期記憶區就能夠理解的程式碼。
翻成白話文就是:用直覺看程式就能理解,背後不會有太多隱藏的彩蛋。
範例如下:
int escapedCharSize = segments
.stream()
.map(Solution::calculateEscaped)
.reduce(0, Integer::sum)
;
上述程式碼有良好可讀性,原因如下:
- 程式區塊不大,能使用短期記憶理解。
- 程式碼沒有隱藏的副作用,就算使用系統一也不會造成沒有思考到的傷害。
- 程式區塊內,擁有需要理解的資訊。
相反的例子相信大家應該都遇過,這邊就不提供範例 (QQ)。
但我們還是需要理解為什麼可讀性差,原因如下:
- 程式區塊大 (幾百行),沒辦法使用短期記憶理解。
- 程式碼內包含過多的副作用,像是:全域變數、狀態亂改,使用系統一去理解容易出錯,因為背後太多隱藏彩蛋 (還記得系統一只用眼前看到的資訊做決策的特性嗎?副作用多半是屬於眼前看不到的資訊)。
- 程式區塊內,只擁有部分的資訊,更多的是眼前沒看到的全域變數、狀態修改。
降低可讀性之設計
了解了大腦系統與大腦記憶區後,我們可以針對這兩個區塊來分析降低可讀性之設計。
影響大腦系統之設計:
- 全域變數:當全域變數會被任意模組變動,容易造增系統一的決策失靈。
- 隱晦更新狀態的函數:當呼叫函數看似無狀態,實際上去隱晦更新狀態時,容易造增系統一的決策失靈。
- 模組之間的隱性耦合:當模組呼叫順係關係被隱藏時,容易造增系統一的決策失靈
影響大腦記憶之設計:
- 複雜函數:當函數過於複雜,沒辦法使用短期記憶理解時,會需要使用長期記憶,然而長期記憶需要時間存放,降低開發效率。
- 破壞封裝API:沒辦法有效封裝的API,會需要使用長期記憶區,如果沒看過這種設計,容易造成呼叫順序出錯。
- 過度暴露實作細節:過度暴露實作細節,導致需要記憶的資訊龐大,需要長期記憶區存放,降低開發效率。
如何提高可讀性
了解了哪些設計會降低可讀性後,就不難理解哪些設計能提高可讀性。
影響大腦系統之設計:
- 禁止全域變數:當沒有全域變數時,使用系統一快速理解程式碼,不會造成太多的錯誤。
- 無狀態函數:當函數沒有太多狀態更新時,使用系統一快速理解程式碼,不會造成太多的錯誤。
- 禁止模組之間的隱性耦合:當模組呼叫順係關係是顯性時,使用系統一快速理解程式碼,不會造成太多的錯誤。
影響大腦記憶之設計:
- 微小函數:當函數簡單,使用短期記憶區便能快速理解。
- 良好封裝API:當API封裝性設計良好時,不需要記憶太多東西到長期記憶區就能呼叫成功,降低出錯機率。
- 程式顯露高階意圖,不是實作細節:當程式碼顯露意圖,代表複雜的資訊被抽象化成一個概念,較好使用短期記憶處理,提高開發效率。ex: 命名incrementDoorCount vs openTheDoor,前者需要記憶增加一個單位等於開門,這需要使用長期記憶;後者直接使用短期記憶即可,因為函數意圖顯露,不需要使用長期記憶。
結論
- 大腦有系統一與系統二:系統一有省力、快速得到結論的特性,但容易做出劣質的決策;系統二有消耗腦力、深度思考後在決策的特性,決策品質較好。
- 大腦有短期記憶與長期記憶:短期記憶只有7+-2,存放、使用較為方便,但容量有限;長期記憶存量多,但資訊需要一些時間才能被存放,速度較慢。
- 所謂的可讀性就是大腦能夠用系統一與短期記憶區就能理解的程式,讓人用直覺就能理解。