Devs.tw 是讓工程師寫筆記、網誌的平台。歡迎您隨手紀錄、寫作,方便日後搜尋!
寫程式的時候,常常聽到 abstraction。
什麼是 abstraction?今天試著用一個小例子解釋:被孩子們搗亂過的幼稚園遊戲間。
要做出優秀的 abstraction 是非常困難的。
主因兩個。第一:它很花時間,需要在開發之前有通盤的架構設計
第二:它很吃經驗,通常需要對類似功能、模組有過開發經驗 才能做出比較漂亮的 abstraction。
除此之外,如果沒辦法做出優秀的 abstraction,卻硬要做出看似精細的 abstraction,通常比不做更慘。
錯誤的 abstraction 比沒有 abstraction 還糟糕,直接增加整體系統的理解難度、成本。
這點跟寫測試的時候,剛剛好是相反
寫測試是:有總比沒有好、只測到簡單陽春的情境,也比完全不測好。
abstraction 是寧可你不做、你 duplicate code,也不要亂把不同概念的 code 抽象到同一個地方(模組、類別、函式之類的)
以檔案架構來說,如果不確定,那麼做出幾個扁平、肥肥的檔案、資料夾
也比深層、複雜,但是設計錯誤的檔案結構來得好。
哪種比較好理解?不妨以整理散落一地的雜物做比喻。想像幼稚園的遊戲間剛被孩子們搗亂過。
老師要整理的時候,一開始沒有把握,先只做簡單的分類,把同類的東西收在一起即可(玩具放一起、零食放一起、故事書放一起)。
可想而知會變成幾個大箱子、大櫃子,這就是扁平寬大。
雖然很隨便,但是做起來快速、方便,而且效果不差了!
接著要進一步整理的話,如果收拾同樣東西好幾次了,有經驗了,就可以進一步分類
玩具再去細分不同類型、不同部位、零件,故事書也可以分類型、出版社、甚至是封面顏色,可以有各種收法,這就是深層複雜
反之,如果一開始就硬要用幾個小箱子、小隔間把玩具、零食硬是分類到不同地方
做出錯誤的深層複雜 abstraction,那麼下次要找東西時,只會超難找而已!
整理的方式就是 abstraction,好不好找到就是 maintainability。
不管是程式概念、還是檔案結構上的設計,都是給人看的。對電腦來說,沒有好不好理解的問題。
所謂抽象化、模組化、重用性、可維護性,全部只跟人有關。
對電腦來說,都只是層層 compile 之後的 1 跟 0 而已,所以,abstraction 的時候主要考慮人,並且常常需要伴隨著出現一些效能的損失。
把一個東西拆分成多個,就算是漂亮的拆分,也會伴隨著重新組織彼此起來時的 overhead。
以幼稚園的例子來說,雖然叫孩子們每次下課就把東西收好是一個不錯的主意,但是完全不去收其實也不錯呀。孩子們隔天上學時回到老地方順手就能繼續玩了,說不定連坐在附近的朋友都一樣。
這種每天都收起來、隔天再拿出來的力氣耗費,就是 overhead,對電腦來說,就是效能的損失。
效能的損失有時大有時小,有時這需要跟 abstraction 帶來的好理解做權衡取捨。
通常碰到跟資料庫相關的 abstraction 最需要小心取捨,需要審慎評估伴隨的 overhead 是否會過大。
不過話說回來,不做 abstraction 的話,孩子們隔天進去時要記得昨天他們坐在哪、玩什麼、哪個玩具是誰在玩。搞錯的話會吵架、老師會傷腦筋。省下這個記得的功夫,就是 abstraction 的好處。
好的 abstraction 讓程式直觀、易懂、好讀,用起來就跟看起來預期的一樣,很爽的。
看到這邊也許會覺得,既然做錯 abstraction 那麼糟,不如少做少錯。其實也不然。
過份的 abstraction 很糟,欠缺 abstraction,長遠來看也不行,根本是新手寫的程式碼。
遊戲間的東西散落一地卻收都不收,當孩子們不多、遊戲間不大的時候還沒關係,至少老師知道大家在玩什麼就行了。
當孩子們變多、遊戲間很大的時候就不行了,絕對不可行。
有句話是這樣說的
The secret to building large apps is never build large apps.
Break your applications into small pieces.
Then, assemble those testable, bite-sized pieces into your big application.
小系統來說,就是拆分到適當的檔案、類別、函式裡頭。大系統來說,就是做幾個模組、系統,讓彼此分工合作,互相獨立而又協調。
當軟體逐漸成長的時候,或說是一開始設計與組織大型軟體的時候,終究是需要有越來越強的 abstraction,才能讓系統保持好維護。
被孩子們搗亂過的幼稚園遊戲間到底要不要整理?要多頻繁地去整理?要收拾分類到什麼程度?
這個問題就是我想說的:abstraction 沒有標準答案。
堅持在開發初期就要有完整 abstraction 而不顧慮伴隨的時間消耗是不對的:這拖慢了開發速度,而且,還有可能出現錯誤的 abstraction。別忘了商業需求、技術規格的可能改變,這保證了 abstraction 會出現錯誤的可能。
而對 abstraction 毫無要求、毫無追求也是不對的:這讓開發出現瓶頸、每次都需要記住整體才能夠理解,最後出來的程式碼毫無優雅可言。令人一看就懂的漂亮 abstraction,與之伴隨的藝術性、工藝精神,是每個工程師值得追求的目標。
(完)