原文地址:blog.islasher.com/2019/05/29/前端
最近在讀《人月神話》,這是一本成書於 1975 年的關於軟件工程的書,考慮到計算機領域的飛速發展,這本書真的能夠算是計算機歷史上洪荒時代的做品了,然而雖然時代久遠,可是這本書仍然被無數人推薦必讀,可謂暢銷數十年。既然如此,做爲半路出家的軟件開發工程師,我固然要拜讀一下了。程序員
我手上這本是 32 週年中文記念版,這本書主要有兩個版本,75 年的第一版和 95 年的二十週年版,主要的差異是 20 週年版添加了沒有銀彈等四個章節。這個 32 週年中文記念版應該就是基於二十週年版的一個翻譯版本,32 週年估計是中文出版商的一個宣傳噱頭。算法
固然,版本不重要,書的內容是主要的,那麼書的主要內容是什麼呢?編程
書名《人月神話》中的人指的是人力,月指的是工做時間,主要的意思是人月做爲一種衡量軟件開發工做量的單位有其誤導性,舉例來講,1我的能夠在10周以內作完的項目,10我的不必定能夠在1 周以內完成。其實在書中做者更進一步地指出,單純地增長開發人力,不只不能對應地減小項目的開發時間,甚至有可能增長開發的時間,由於更多的開發人員須要更多的交流溝通,這部分的時間成本也是很可觀的。固然,這本書不只僅是論述這一個的觀點,從這個觀點出發,本書還介紹了不少其餘的大型軟件工程的規律和最佳實踐。接下來,我將一一介紹該書每一章的主要內容,算是個人讀書筆記吧。網絡
第一章做者將軟件系統開發比做吞噬了恐龍、劍齒虎等史前巨獸的焦油坑,許多大大小小的團隊被軟件開發的焦油坑所吞噬。架構
做者首先介紹了變成系統產品的演進,指出程序、編程系統、編程產品、編程系統產品幾個概念間的區別,其中只有編程系統產品纔是真正可用的面向用戶的產物。編程語言
而後做者分別介紹了編程的樂趣和苦惱,固然這部分見仁見智,人類的悲歡畢竟並不相通。工具
第二章做者主要介紹了軟件開發項目在進度安排上常常出現的問題。也就是書名人月神話的出處。首先,因爲咱們對項目開發的進度估計過於樂觀,咱們估計出來的工做量一般會低於實際須要的工做量,尤爲是對測試所需時間的安排經常是進度估算失誤的重災區,這應該是不少有經驗的開發者會在估時的時候乘以一個固定的係數的緣由(1.5 或者 2 甚至 3)。其次人員和時間的關係並不是老是反比的關係,若是任務屬於能夠徹底分解的理想狀態話,是可能達到人員越多時間越少的反比效果的,可是,任務越複雜也就越難以分解,那任務中的溝通需求就會佔用更多的時間,甚至可能致使人員越多,項目所需的時間越長。進而能夠得出結論:當進度落後的時候,無腦增長開發人手可能並不能加快開發進度,甚至有可能致使進度更加緩慢。向進度落後的項目中增長人手,只會使進度更加落後,這也被成爲 Brooks 法則。開發工具
基於上一章的結論:更大的隊伍不必定能帶來更快的開發進度,那麼,問題來了,什麼樣的隊伍纔是合適的呢,小團隊當然高效,可是你不能期望一個 20 人的小團隊在合理的時間內去開發一套完整的操做系統吧?做者在這一章裏給出瞭解決方案:將大項目合理地劃分紅更小的系統,各個外科手術隊伍分別開發這些更小的系統。固然外科手術隊伍只是一個小團隊的方案,具體細節我認爲已經再也不具備很大的參考價值,可是精幹的小型隊伍這一理念仍然頗有價值。測試
這裏我聯想到大企業病的問題,企業規模的擴大必然會致使人浮於事、效率低下的問題,因而現在一些大企業都會將企業的業務分割給各個小團隊來負責,一個很著名的例子就是亞馬遜的兩個披薩的原則,有效地避免了大團隊的致使的低效問題。
接上一章:短小精幹的隊伍帶來了新的問題,如何對大項目進行合理的分割?這依賴於一個很重要的前提:概念的完整性,具體而言是指在項目的開發過程當中,應該有一個一以貫之的明確的目標和清晰界定的範圍,不然隨着人員的變更和時間的變遷,這個項目可能會逐漸演變成四不像(我最近在參與的一個項目就是如此,人員的變更致使了項目功能、技術棧的變遷,項目的週期被極大地拉長)。而如何產生概念的完整性呢?答案是貴族專制,少數人決定一個概念並釐清邊界,而後據此分割執行,不然人多嘴雜,必然會致使項目在討論中變成奇怪的樣子。
這一章主要是告誡系統設計師們,不要過分設計,尤爲是在第二個系統(第一個系統完成後開發的第二個系統)中,不要過分自信,保持警覺,避免初始的概念和目標獲得充分的體現,而不讓一些次要的功能喧賓奪主。(是否是能夠說是保持初心?)
概念的完整性不只僅要在專制的貴族和系統設計師這一層面上充分傳達並理解,在系統的實現人員中,也要充分傳達。在不理解業務背景的狀況下,開發者也很難寫出優秀的代碼。做者在這一章介紹了不少方法以達到這一目的,包括規格說明手冊、形式化定義(個人理解是 Web 開發中的原型圖同樣的存在)、會議和大會、多重實現(舉例:假如JavaScript只有 V8 一個引擎,那若是引擎實現與 ES 標準不一致時,改標準比改引擎實現要容易得多,可是有多個引擎時,與標準不一致的引擎就必須修改本身的實現,從而保證了標準文檔的貫徹執行)、電話日誌、產品測試。
固然這些方法在現在可能已通過時了,可是經過種種方式保證軟件開發的進度不偏離最初的概念和目標,是實現項目成功的重要保障。實際上在當代的軟件開發流程中也有一些措施來實現這一目標,如敏捷開發中天天的站會。
咱們都知道巴比倫塔的失敗是由於上帝給了人類不一樣的語言致使的溝通失效。那麼在大型項目中如何保證溝通的順暢呢?做者詳細介紹了項目工做手冊的內容、發佈方式、更新方式等等,可是當年他們仍然是紙質文檔,後來才進化成微縮膠片,現現在咱們有了更方便的字處理工具和文檔協做工做,於是這部分的建議就用不上了,可是保持文檔的更新和有效獲取仍然很重要,不然不一樣的人對需求的記憶和理解可能出現誤差、進度可能會出現錯位等等,致使項目的開發進度被拖慢。
相應的,外科手術隊伍也能夠有效地下降交流的難度,畢竟人越少,溝通越便捷,這樣一來,整個項目經過合理的人力劃分和職責限定,就會自上而下造成一個樹狀結構。做者特意論述了團隊中技術負責人和產品負責人的分工與關係,可是我很難將做者的觀點映射到當代的開發團隊中來,只好略過。
這一章是介紹對變成效率的量化的,種種量化方法將程序員的生產效率細化到指令/年(很差意思,他們當年是寫彙編的,高級語言那個時候還不多)。我以爲這個實際上意義不大, 可是仍然是一個有趣的參考,最終的結論是工做量=常數*指令數量^1.5,也就是說工做時長跟代碼數量的指數關係而不是線性關係,隨着代碼數量的增加,工做時長是指數級上升的。
這一章主要是講程序大小的,包括代碼大小和內存佔用的大小。代碼大小如今應該已經不是軟件開發的重要考量了吧?可是這一問題在現在的 App 開發中應該也有,雖然不少公司絕不在意佔用用戶幾百 M 的存儲空間……固然在前端還存在另一個問題,即過大的代碼包會耗費過多的流量,尤爲是在早年的移動端開發中,那時候流量很金貴,如今這樣的顧慮逐漸變少了,可是一直都存在的顧慮是代碼的加載速度,固然這一問題也能夠經過分包懶加載來解決了。總而言之,當年的那些經驗在前端領域適用的已經很少了,可是在客戶端領域可能仍然適用。
內存固然始終是一個問題,可是應該主要考慮不要發生內存泄露的問題,自動的垃圾收集能夠解決大部分問題了吧?計算機硬件的進步真的極大地下降了軟件工程的難度。
這一章主要是介紹文檔的重要性,對於項目經理來講,文檔是很重要的,它包含了項目目標、產品的技術說明、時間、資金預算、工做空間的分配和人員的組織結構。文檔的重要性在於首先,明確的書面記錄會讓分歧更明朗,使混沌的狀態變得清晰、明確;其次,文檔下降了溝通的負擔;最後,文檔便於項目經理跟蹤項目的進度狀態。
這對於程序員來講多是一個十分不幸的消息:系統必然會面對各類變化,你開發的軟件必然會在修修補補中變得面目全非,最初的設計必須在各類妥協中打上各類醜陋的補丁。不管是多麼良好設計的系統,都會走向混亂,區別只是這個過程的快慢而已。所以,好的設計會讓這個過程儘量地慢,儘量地不那麼痛苦,咱們能作的就是眼光儘可能放長遠,讓咱們的代碼儘量地具備高可擴展性而且易於維護。並且,在面對不得不進行的重構時,作好心理準備。
這一章一言以蔽之:磨刀不誤砍柴工。好的開發工具和開發環境能夠極大地提升開發效率,固然,做者在這一章中介紹具體方法、工具、語言等已經不適用於咱們這個時代了。
咱們將總體的項目分割成更小的部分來開發,可是最終咱們仍然須要將這各個部分合併成一個總體對外提供服務,這就帶來了新的問題:各個部分可能獨立工做良好,可是當合併成總體時反而致使了新的系統級的 bug。這就要求咱們在設計系統結構時精心設計,減小各個部分間的耦合,各個模塊的獨立性越高,系統級的 bug 的可能性就越低。此外做者在本章還介紹了一些測試的方法,這部分我不太瞭解,並且測試的方法、流程可能也已通過時了,畢竟咱們已經有了更好、更方便的版本控制工具和測試流程,可是其中一些理念仍是有意義的,如重構過的模塊在合進總體的時候仍然須要對系統總體進行測試,而不是僅僅測試重構過的模塊。
項目的進度頗有可能由於各類各樣不可避免的因素滯後,這是極可能出現的狀況,有的時候甚至可能不知不覺就會落後,難以察覺地落後一天、半天,累積起來整個項目的完成就會遙遙無期。避免這種難以察覺的落後的辦法是制定里程碑,將項目的進度安排劃分紅一個一個階段並清晰地界定各個階段須要完成的任務,里程碑邊界的清晰、明確十分重要,含糊的里程碑跟沒有里程碑沒有區別。「其餘部分反正會落後」是一種很可怕的想法,是須要項目經理極力去避免的。此外,一線經理不要害怕向老闆反映進度落後的真實狀況,同時老闆遇到進度落後時也不要越俎代庖代替一線經理作決定,不然一線經理會傾向於不報告真實信息。
除了面向開發者的項目文檔和說明以外,軟件開發也須要編寫詳盡的面向用戶的文檔,文檔須要包含軟件的目的、運行環境、輸入輸出範圍、實現的功能和使用的算法、輸入輸出的格式、操做指令、選項、運行時間、輸出結果的精度和校驗方式等等,除此以外,還須要充分的測試用例來講明程序的功能和邊界。另外,對於其餘開發者而言,須要提供項目開發所須要的文檔(相似 Github 上 how to contribute 的部分吧)。
沒有銀彈是一篇頗有名氣的文章,這篇文章發表於1986年,同時這也是一個廣爲流傳的軟件開發的原則,這一原則是指,在將來的十年內(1986-1996),沒有任何技術或管理上的進展,可以獨立地許諾在生產率、可靠性或簡潔性上去的數量級的提升。做者作出這一論斷的前提是:全部軟件包括根本任務和次要任務,根本任務是打造構成抽象軟件實體的複雜概念結構,次要任務是用編程語言表達這些抽象實體。不少技術或管理上的進展在解決次要任務上發揮了巨大做用,可是在主要任務上卻進展寥寥,做者進而分析了形成這種境況的緣由,分別從複雜度、一致性、可變性、不可見性論述了他的觀點,我在此不作總結了,就我我的的理解而言,軟件本質上是須要完成業務需求的,而業務需求則來源於商業決策、社會、文化等等人類文明系統的各個方面,甚至能夠說是軟件工程是對現實世界的模擬,這個現實的社會系統如此複雜而且變化無窮,以致於任何一種架構設計都不可能囊括全部的可能性,因此,需求必然會變動,沒有一發銀彈能夠應對全部的需求。軟件開發的難度不在於開發,而在於設計一個完美的軟件架構,而這個架構依賴於對業務的熟悉和前瞻性的展望。
做者進而提出瞭解決核心問題的方法:首先:不開發軟件,不開發軟件就不會有問題……買一個就行了(我暈,這也算辦法?不過雖然這個方法有些無厘頭,可是其實預見了微軟爲表明的薄膜包裝軟件的興盛,由於當年的軟件大可能是客戶定製化開發的,而不是售賣通用的軟件解決方案);其次,快速地搭建原型(Demo吧?),從而更好地肯定用戶的需求;第三,增量開發,我以爲這個方法最靠譜,也就是把軟件當作是生長的有機體,而不是一個建好就能夠的建築,軟件會不斷成長,先從簡單的核心開始,一邊交付一邊開發,不斷增長新的功能,一邊增長新的功能,一邊重構已有的部分,其實這跟咱們目前的不少項目的開發模式很類似了;最後,培養優秀的設計人員……講真,我以爲這個也過高遠了……不能解決眼前的問題,固然,這是有意義的,培養出優秀的系統設計師(如今應該說是架構師?)是十分重要的,可是,這也只能在實踐中培養吧,畢竟紙上談兵是確定不行的。
這一章是《沒有銀彈》這篇文章發表10年後(1996年),做者對針對這一話題的討論的一些迴應與評價,其中也包括對一些新興技術的討論,頗有意思,其中的不少觀點在現今仍然不時在網絡上出現。此處不一一列舉了,文章網上均可以看到。在這篇文章中,做者對一種新的軟件開發趨勢寄予了比較高的指望:重用,也就是咱們如今說的複用,我以爲這一趨勢成就了今天的開源社區。
固然做者仍然堅持認爲,子彈沒有出現。
這一章也是20週年版本新增的內容,20年的發展讓第一版的一些觀點變得過期,可是仍然有很多觀點仍然適用,於是做者在這一章裏把以前的每一章的主要觀點都抽離出來,並對已通過時了的觀點作了說明,能夠說這一章是整本書的精華了吧,具體內容我就不列了,做者對每一章的總結與我在上面的整理也有很大的不一樣,我只不過是將本身的理解整理出來,做者的總結則更加細緻全面。總而言之,十分推薦。
這一章很長很長,算是一篇單獨的文章,討論了不少軟件開發相關的技術和管理思想,其中包括:
這本書真的是夠老了,已經40多年了,很難想象一本計算機領域的書可以暢銷這麼久。可是讀完以後我發現暢銷是有道理的,雖然書裏不少概念、例子、技術都屬於上古時期的遺蹟了,可是書裏介紹的軟件開發的困難、管理的思路,仍然能夠在今天的軟件開發中找到對應的場景,原來我今天遇到的困難早在洪荒時代就已經被討論而且提出過解決方案,並且今天的一些軟件開發的流程、管理方案、團隊組織等等均可以看到當年那些解決方案的影子。因此讀這本書仍是頗有收穫的,能夠理解實際開發過程當中遇到的困難和這些困難的應對方法,不管你是在開發團隊中擔任什麼角色,是產品經理仍是開發者抑或技術負責人,我都十分推薦這本書。 讀完這本書還有一個感覺:國內的軟件開發行業真的是十分落後,簡直是小做坊式的開發,但願每個老闆、項目經理、產品經理、開發者都能讀一讀軟件開發相關的書籍,瞭解軟件開發特有的規律,不要再摸着石頭過河了。 固然,這本書畢竟已是老古董了,讀的時候有不少地方會很難理解,建議跳過這些細節,關注那些細節背後的原理和規律,尤爲是十分推薦對照着 《人月神話》的觀點:是與非 這一章來讀,能夠起到提綱挈領、高屋建瓴的效果(後悔本身讀到後面才知道有這麼一章)。