程序員書庫(ID:OpenSourceTop) 編譯
書單來自:https://lethain.com/notes-philosophy-software-design/

最近,我讀了一本朋友推薦的《軟件設計的哲學》,它相當簡潔,只有160頁,用了幾天時間把它讀完了。


當我讀了《軟件設計的哲學》……



這本書提到了關注系統的複雜性這一新理念,並希望讀者“在軟件的生命週期中通過複雜性來引導軟件的設計”。對此,作者還開了一門關於軟件設計的本科課程,模仿論文教學的方式(初稿,寫作,評論,重寫,評論,再重寫),並將這種方式和多年的系統開發經驗相結合,以此來開展軟件的複雜度類別。


作者簡介



當我讀了《軟件設計的哲學》……



John Ousterhout 是斯坦福大學計算機系教授,也是 Tcl 語言的創造者。John Ousterhout1975 年獲得耶魯大學物理學學士學位,1980 年獲得卡內基梅隆大學的計算機科學博士學位

讀書筆記


我身邊的朋友都很推薦這本書,認爲它是很適合在代碼審查過程中使用的一種工具,它提供了一系列的危險提示,包括信息泄露、淺層模塊、名稱模糊、實現文件接口污染、連接方法,以及特定的混合文件等


下面,分享一些我在書中看到的一些有趣的部分:


複雜性是使軟件難以理解或難以修改的重要因素。


雖然作者對於複雜性的定義很寬泛,但隨着本書內容的深入,這個概念會越來越清晰


如果能把複雜性隔離在一個模塊,不與其他模塊相關聯,就達到了消除複雜性的目的。


我想這說的已經很明顯了,這一點也給我留下了深刻的印象。我們沒有充分思考到底是哪裏產生了複雜性,如果我們做的好的話,就可以快速地讓我們的系統變得更簡單。


相比作者而言,閱讀代碼的人更容易察覺到代碼的複雜性如果其他人都認爲一段代碼很複雜,那麼它就是複雜的。


這種說法是老調重彈,但卻很有道理。但令人驚訝的是,人們對這種觀點大多很牴觸,包括我自己。


書中列舉了三種複雜(complexity)的類型:變更擴大化(change amplification),認知負荷(cognitive load),無法預知的一切可能(unknown unknowns)。當局部修改會引起其他多個地方改變的時候,變更擴大化是最優的解決方案


減少每個設計模塊所影響的代碼量,變更的時候修改的代碼就


認知負荷要求我們注意力從計算代碼的行數上轉移到接受更多更簡單的代碼行;這樣的代碼比少而複雜的代碼要簡單的多。(當我開始寫Go代碼的時候,一直在糾結這個問題。每行代碼都儘可能簡單,但它卻比我之前用Python編寫的時間還長。


最後,無法預知的一切,是你想要了解的東西,但是沒有找到辦法可以從代碼本身學習到的。


然後,開始轉到了複雜性的定義:


複雜性是由模糊性(obscurity)和依賴性(dependencies)造成的。


還有複雜性的組成因素的定義是:


依賴性是指模塊無法獨立於其他模塊而被理解。
模糊性是指在重要信息不明確的情況下
這往往是因爲缺乏文檔。


複雜性管理爲什麼如此具有挑戰性?這是因爲


複雜性是遞增的,前面做出的每一個決策,都可能導致後面的設計越來越複雜。


爲了避免複雜性不斷遞增,他建議區分戰略性編程和戰術性編程。


戰術性編程是專注於讓代碼能夠跑起來,但這使得它幾乎不可能產生好的系統設計。


相反,戰略編程會轉移目標重心


戰略性編程是意識到光有能運行的代碼是不夠的
最主要的目標應該是有一個不僅能夠運行,還能解決問題的好的系統設計


有趣的是,這個建議並不是要你把重心放在的前期設計階段,而是你應該隨着時間的推移不斷做出大量的設計改進。這與“敏捷設計”略有不同,因爲敏捷過於關注特性,然而


開發的遞增應該是抽象的,而不是僅僅是某些特性。
......
理想情況下,假如你從一開始就考慮到更改系統設計時,會帶來的變化,那麼當你完成每個變更時,系統就會變成你一開始預想的那個結構


很多人會反對這種對抽象的關注,認爲它沒有什麼太大的用處,因爲你並不需要它,他會認爲


一個好的設計很快就能得到回報。但這些策略都不太可能實現
速度更快的戰術性編程都做不到了,更不用說戰略性編程了


該部分特別駁斥了快速啓動和稍後修復問題的創業心態,認爲這是一種錯誤的方式。


管理複雜性最重要的方法是從接口轉移到實現中:


模塊是接口和實現。
最好的模塊是接口比實現更簡單

更重要的是模塊要有一個簡單的接口,而不是一個簡單的實現。


當你在設計模塊時,要特別小心,因爲


抽象是實體的簡化視圖,它忽略了一些不重要的細節。忽略重要的細節就會導致模糊,從而產生錯誤的抽象。


這種技術被稱爲信息隱藏:


接口(interface)本身應該很簡潔,把複雜的功能隱藏在簡潔接口的下邊,這些知識不應該出現在它的界面中,這纔是一種好的抽象


信息隱藏的另一面是信息泄漏:


如果多個模塊耦合,那就把這些模塊合併成一個。


這本書花了很長篇幅在討論異常,以及異常如何偏離正常的代碼流,從而帶來更多的Bug問題。這是因爲你


必須恢復和嘗試恢復(很難)或嘗試修復然後繼續開發(也很難)。這在許多情況下會導致不一致。


解決方案是“定義不存在的錯誤”,即設計不會出現Bug的接口。 文中給出的是 unset 與 delete 的例子,前者將確保不存在某些東西,而不是確保以前存在的東西現在已經消失。 第二個例子是從列表中獲取片段,對於不存在的範圍而言,更容易的處理是返回無內容,拋出更多的異常。


最好的設計不是你的第一個設計,而是你應該


設計兩次,採用完全不同的方法。


這個話題有一個有趣的地方,就是很多聰明的人,通常都被他們的早期經歷所影響,認爲他們的第一直覺就是正確的,也正是這個原因,所以他們很難利用這一技巧。


大多數大型軟件設計問題與學校的根本不同,大型軟件本身並不是爲了解決問題而設計的,因此他們受益於多種不同的方法。


最後,戰略性編程告訴我們:


如果你沒有想着把設計做得更好,那你可能會把它弄得更糟。


總而言之,這是一篇非常值得讀的書,強烈推薦大家去讀一讀,目前還沒有中文版


讀者書評:


@larrylv:同組的斯坦福小夥大學時上過作者的課,強烈推薦了本書。書雖薄了些,但收穫不小。
@ye11ow :引用最後一章第一句話:This book is about one thing: complexity。雖然標題裏帶有"philosophy",但其實書裏介紹的大部分內容還是挺直覺。關於異常和註釋的兩章反而讓我收穫最多
@豆花魚:喜歡這本書道理寫在前然後舉例說明的講解方式,很好讀,有一些幫助。
@秋明:降低複雜度,less is more
相關文章