人月神話讀後心得
軟體工程其實是管理學
大學時讀過一遍,最近再讀一遍,發覺書中說的觀念仍然適用。工作經驗愈久,愈能認同書中所言。可能有些當時新穎的觀念,現在已被視為常識 (例如要用漸進式開發模型而不是瀑布模型)。也因為這樣,重看後其實沒學到什麼新東西,如同作者在《人月神話二十年後》自我調侃:
… 坐在我旁邊的那位陌生人正在看《人月神話》,而我一直在等,等看看他會不會有什麼反應,也許是一番話或某些表示。最後,飛機終於降落滑向了登機門,我不能再等了:
「這本書如何?你喜歡嗎?」
「哦!這裡頭講的都是我老早就知道的東西。」我決定不作自我介紹了。
作者認為相較於其它技術,《人月神話》之所以能歷久不衰,主要是本書在討論人的問題,而不是技術問題。軟體開發的重點在於如何讓組織有效率地運作。以下分幾個方面整理心得。
系統設計的概念整體性 (conceptual integrity)
書中認為保有概念整體性是系統設計時最重要的原則,包含功能的使用介面和背後的軟體架構。多人的想法很難一致,也不易管理。因此,專制是必要的。
但在專制的背後,實作人員仍有很大的發揮空間。架構設計須獨立於實作: 架構師可以提供一種實作建議,但不能指定如何實作。舉例來說,架構師定了一個服務可以快速找出某個時間範圍內的資料。實作的人要用 binary tree、sorted array 都無所謂,只要符合規格即可。
此外,作者認為這種限制反而讓實作者更能發揮創意 (“Form is liberating”),因為他會專注在限定的範圍內構想,不會天馬行空。所以專制的結果是雙贏。我滿認同這點的。
架構師在定義規格時要很嚴謹,不只說明有那些規範,不在規範內的也要說清楚。像 C 語言沒有定義函式參數的運算式執行的順序,雖然給編譯器實作者有最佳化發揮的空間 (可以選擇平行執行各參數的運算式),但也增加潛在的問題,例如:
i = 0;
sum = add(i++, i++);
add() 收到的參數是 (0, 0), (0, 1), (1, 0) 的那一個呢?
實務上作者認為要同時有精確的正式定義 (接近數學式那樣)以及易於閱讀的 (散文式定義)。然後兩者選一個為主作為標準,何者為主皆可。
某項實作成果也可當作定義,缺點是會產生一些不好處理的定義。現實似乎比較多這類結果? 如果問我網頁正式的行為是什麼,相較於查閱 W3C 的規範,我可能會以 Chrome 的實作表現為主。若 Chrome 不小心寫了某種 bug,網頁開發者廣為使用,日後這 bug 變成規格,反而不能修正了。
題外話,就我自己的除錯經驗來看,含有明確設計概念的模組,比較不易出錯。即使出錯,也容易預期正確的行為是什麼,知道該往那個方向修正。反之,東拼西湊完成的模組,只有剛好滿足目前已知的問題,看不出整體的概念。出現新問題時,很難判斷什麼才是正確的行為,產生副作用後也不知該繼續修正新的副作用,還是要改用其它設計。
產品規格設計
作者提及要維護產品的概念整體性,必須定義使用者群的行為。有了預期使用者的特徵,才好分析某項設計是否合理。還有需要更改設計時,怎麼改才會更符合目標。比方說手機上的應用程式是否需要單手操作?若這是必須在家裡坐好聚心會神玩的重度遊戲,那單手操作並非必要。若是目標族群多在通勤時加減使用,單手操作是必要的。
作者堅信架構設計師必須去猜目標使用者群的行為,錯誤而明確遠比模糊不清好。因為這樣才有明確的討論。若討論的結果必須驗證特定使用者行為,這時就有足夠理由花費更多成本取得更精確的使用者行為。
人月迷思
作者認為用人月估時程並不可靠: 需要10人做1年的專案,不見得能用120人在1個月內做完。討論這部份時,作者說出了本書的經典句子:
生小孩就是需要九個月,你叫多少個媽一起生都一樣。
套用 multi-threading 加速程式的觀點容易理解,關鍵在於資料 (工作) 相依性。只有在工作能完全切分互不影響的情況下,才能藉由加一倍的人手而縮短一半的時間。
一但有了相依性,更多人員反而增加溝通成本。
時程估計
作者對時程的經驗法則:
- 1/3 規劃。
- 1/6 寫程式。
- 1/4 組件測試和早期系統測試。
- 1/4 系統測試,完成所有組件。
注意寫程式只占 1/6 時間,軟體專案不順的主因是缺乏良好的時程規劃。事前排定測試時間可以提高品質,避免進度落後時,無法把測試列入考量。
團隊組成
作者提倡「外科手術團隊」。以一人為主,其他人輔助處理一個小專案。公司再切成多個團隊處理各個專案。這個作法可因少數人的決策兼顧概念整體性,且減少溝通而提升全員生產力。
團隊之間是樹狀結構是不可免的結果,這樣才能有明確的更高決策單位。但溝通仍是網狀的,因此需要特別組織補足樹狀結構溝通不足的問題。
每個專案都有管理者或技術總監,有三種可行的搭配方法:
- 一人兼任兩者,但很少會這樣。一來這樣的人少,二來這兩份工作都需要大量時間,即使有這樣的能力,時間也不夠用。
- 管理者為主,充份授權給技術總監發揮。
- 技術總監為主,管理者幫忙處理雜事。
管理者最重要的工作是溝通而非做決定。
組織文化
高階管理者需要讓所有人了解和認同組織文化。以 CloudMosa 為例的話,一個常被提及的規則是「做的人最大」。這樣可以維持專案的概念整體性,不會變成一群人意見妥協的四不像。而且獨裁很有效率,每個人都有獨裁的機會 (聽起來很公平!),就看主事者是誰。
為了實踐這點,老闆可以接受許多他認為「正確」的作法不被採納,讓做的人完全發揮。例如使用者介面,從我入公司到現在六年間,老闆的提案不斷被打槍,至今沒有被實作出來,身體力行這點很了不起 (不斷找機會試圖翻盤也很有毅力),因此大家也很能認同和實踐此點。
為避免這樣的文化被濫用,找進來的人要符合公司的文化,不合文化即使能力再好也不適用。一但找進來的人符合文化,其實需要的管理很少,組織自然運作得很有效率。
打造易於改變的組織
作者認為軟體會不斷地變動,組織也因此需要不斷地改變。長遠來說,要打造一個富有彈性利於改變的組織。這比設計利於改變的系統還難。像 Google (或 CloudMosa ) 著重在招收一般性 (通才) 的軟體工程師,這樣無論專案內容如何變化,公司員工都能應付。不用擔心因為方向轉變而需要處理特定專長的員工。例如公司不開發 Android app 後,專職 Android 開發的員工該改做什麼?他們願意接受嗎?還是要全員資遣?
但是缺少特定專長的員工也需要多些時間熟悉特定領域的知識。對於不斷改變的小型新創公司來說,一方面需要搶時間,另一方面也會不斷地改變方向。感覺還是需要有些取捨。多數通才加上少數專才應該是不錯的平衡。
漸近式開發模型
由上而下寫好主程式,然後讓各模組放入空的實作,再一步步由上而下實作內容。一直保持一個可以運行的系統。這樣可以提早測試,完成多少測多少。提早發現問題,提早處理。
這在現今已是常識,不過我剛出社會工作時,還會疑惑要由下而上還是上而下開發。現在已忘了當時疑惑的點,在這裡留個記錄。
在作者的年代還沒有 TDD (Test Driven Development) ,不知過個十年,TDD 是否也會成為常識,被認定是更好的開發模型?我滿喜歡 TDD 的理念,不過實務上怎麼做最有效率,還沒拿準作法。或許架構師在制定架構時將可測性列入主要指標,是實行的必要條件。
重用既有的軟體模組
書中有大量篇幅討論為什麼往後十年內找不到 10x 生產力的方法。然後轉而討論在這樣的前提下,要如何減少開發時間?答案是: 盡可能重用軟體模組。
書裡提到的是購買商用的軟體模組,不過那是 1995 的時代。如今 open source 盛行,更容易重用軟體模組。作者提到軟體重用的關鍵是介面明確易於重覆使用且開發成本高,像數學計算模組是典型的例子。對照到 open source 的話,openssl 或 ffmpeg 都是廣為使用的函式庫,沒有人會想自己重寫 TLS 連線或是影音格式解壓縮演算法。
如今要能更快地完成品質更好的軟體,熟悉使用 open source 是一大關鍵。舉例來說,開發軟體難免會需要處理 Unicode。比起自己了解 UTF-X 的規格細節然後實作,使用 ICU 才是正解。或是參考 Chromium 的作法,可以取得更易於使用的介面。
Brooks法則的例外
(更新於2018/12)
Brooks法則:向進度落後的項目中增加人手,只會使項目更加落後。
這大致上是對的,因為增加人手會增加溝通成本,還有短期訓練成本,都會佔用既有團隊的時間。
但是這裡有個隱含的前提:既有團隊比新加入人手更熟悉開發中的項目。當加入的人手擁有既有團隊需要且缺乏特定領域的知識時,增加人手會有幫助。例如 :Web 服務後期壓力測試 database 效能有問題。向外找 database 專家協助會有幫助。其它像是產品規劃、軟體開發流程也是如此,關鍵在於既有團隊在這方面有多欠缺,加入的人手有多專業。