好的設計不是免費的。它必須是你不斷投資的東西,這樣小問題就不會積累成大問題。 幸運的是,好的設計最終會收回成本,而且比你想象的要快。 ...
“作者簡介: 常柱,微信公眾號【架構未來】作者,十多年一線互聯網研發從業經驗;前五八同城商業會員技術負責人,寶駕租車技術總監,現58 到家業務中台技術負責人。
好的軟體設計最重要的元素之一是在處理編程任務時採用的思維方式。許多組織鼓勵一種戰術心態,專註於讓特性儘可能快地工作。然而,如果你想要一個好的設計,你必須採取一種更有策略的方法,投入時間來產生乾凈的設計並解決問題。本章討論了為什麼戰略方法可以產生更好的設計,並且從長遠來看實際上比戰術方法更便宜。
3.1 戰術的編程
大多數程式員使用一種我稱為戰術編程的思維方式來進行軟體開發。在戰術方法中,您的主要關註點是讓某些東西工作起來,比如一個新特性或一個 bug 修複。乍一看,這似乎是完全合理的:還有什麼比編寫有效的代碼更重要呢?然而,戰術規劃使它幾乎不可能產生一個良好的系統設計。
戰術編程的問題在於它是短視的。 如果你在戰術上編程,你是在試圖儘快完成一項任務。也許你有一個艱難的最後期限。因此,規劃未來並不是優先事項。你不會花很多時間去尋找最好的設計;你只是想儘快開始工作。你告訴自己,如果可以讓當前的任務更快完成,增加一點複雜性或者引入一兩個小的封裝是可以的。
這就是系統變得複雜的原因。如前一章所述,複雜性是遞增的。使一個系統變得複雜的不是某一件特定的事情,而是數十個或數百個小事情的積累。如果你有策略地編程,每個編程任務都會增加一些複雜性。為了快速完成當前的任務,它們中的每一個似乎都是合理的妥協。然而,複雜性迅速增加,特別是如果每個人都在戰術上編程。
不久之後,一些複雜的問題就會開始產生,你會開始後悔當初沒有走那些捷徑。但是,您會告訴自己,讓下一個功能正常工作比返回並重構現有代碼更重要。從長遠來看,重構可能會有所幫助,但它肯定會降低當前任務的速度。因此,您需要尋找快速補丁來解決遇到的任何問題。這隻會產生更多的複雜性,這就需要更多的補丁。很快,代碼就亂成一團了,但到目前為止,情況已經非常糟糕,需要幾個月的時間才能清理乾凈。你的時間表不可能容忍這樣的延遲,而且解決一兩個問題似乎也不會有太大的不同,所以你只是在戰術上繼續編程。
如果您已經在一個大型軟體項目中工作了很長時間,我懷疑您已經在工作中看到過戰術編程,並體驗過它所導致的問題。一旦你開始走上戰術道路,就很難改變。
幾乎每個軟體開發組織都至少有一個將戰術編程發揮到極致的開發人員:戰術旋風。戰術旋風是一個多產的程式員誰泵出的代碼比別人快得多,但工作在一個完全戰術的方式。 當涉及到實現快速特性時,沒有人比戰術性 tornado 完成得更快。在一些組織中,管理層將戰術旋風視為英雄。然而,戰術旋風留下了破壞的尾跡。他們很少被將來必須使用他們的代碼的工程師視為英雄。通常,其他工程師必須清理戰術旋風留下的混亂,這使得那些工程師(真正的英雄)看起來比戰術旋風進展緩慢。
3.2 戰略規劃
成為一名優秀的軟體設計師的第一步是認識到僅僅為了完成工作編寫代碼是不夠的。為了更快地完成當前的任務而引入不必要的複雜性是不可接受的。最重要的是這個系統的長期結構。 任何系統中的大多數代碼都是通過擴展現有的代碼庫來編寫的,因此作為開發人員,您最重要的工作就是促進這些未來的擴展。因此,您不應該認為“工作代碼”是您的主要目標,儘管您的代碼當然必須工作。您的主要目標必須是產生一個偉大的設計,這也碰巧工作。這是戰略規劃。
戰略規劃需要一種投資心態。 您必須投入時間來改進系統的設計,而不是以最快的方式來完成當前的項目。這些投資在短期內會讓你慢下來一點,但在長期內會讓你加快速度,如圖 3.1 所示。
一些投資將是積極的。例如,花一點額外的時間為每個新類找到一個簡單的設計是值得的;與其實施第一個出現在腦海中的想法,不如嘗試幾個替代的設計,選擇最乾凈的一個。試著想象一些系統在未來可能需要改變的方式,並確保你的設計是簡單的。編寫好的文檔是主動投資的另一個例子。
其他投資將是被動的。 無論您預先投入多少,在您的設計決策中都會不可避免地出現錯誤。隨著時間的推移,這些錯誤將變得顯而易見。當你發現一個設計問題時,不要忽視它或修補它;花一點額外的時間來修複它。如果您有策略地進行編程,您將不斷地對系統設計進行小的改進。這與戰術編程相反,在戰術編程中,您不斷地添加小的複雜性,這些複雜性會在將來導致問題。
3.3 投資多少?
那麼,正確的投資額是多少呢?一筆巨大的前期投資,比如試圖設計整個系統,是不會有效的。這就是瀑布法,我們知道它行不通。隨著您對系統的經驗的積累,理想的設計往往會零零碎碎地出現。因此,最好的方法是在連續的基礎上進行大量的小額投資。 我建議您將總開發時間的 10-20%用於投資。這個量足夠小,不會對您的日程安排產生重大影響,但是足夠大,隨著時間的推移會產生顯著的好處。因此,您最初的項目將比純戰術方法多花費 10-20%的時間。這些額外的時間將導致更好的軟體設計,並且您將在幾個月內開始體驗這些好處。用不了多久,你的開發速度就會比戰術編程至少快 10-20%。在這一點上,你的投資是免費的:從你過去的投資中獲得的收益將節省足夠的時間來彌補未來投資的成本。你將很快收回最初投資的成本。圖 3.1 說明瞭這種現象。
圖 3.1:在開始階段,一種戰術的編程方法將比一種戰略方法更快地取得進展。然而,在戰術方法下,複雜性積累得更快,從而降低了生產率。隨著時間的推移,戰略方法取得了更大的進展。註意:這個數字只是一個定性的說明;我不知道任何經驗測量的準確曲線形狀。
相反,如果你有策略地進行編程,你將會以 10-20%的速度完成你的第一個項目,但是隨著時間的推移,你的開發速度會隨著複雜性的增加而減慢。用不了多久,您的編程速度至少會降低 10-20%。您將很快地歸還您在開始時節省的所有時間,並且在剩下的系統生命周期中,您將比採用策略方法時開發得更慢。如果您從未在嚴重降級的代碼庫中工作過,請與曾經工作過的人交談;他們會告訴你,糟糕的代碼質量至少會降低 20%的開發速度。
3.4 創業與投資
在某些環境中,有強大的力量反對戰略方法。例如,處於早期階段的初創公司會感到巨大的壓力,要求他們儘快發佈自己的早期版本。在這些公司,似乎 10-20%的投資都是負擔不起的。因此,許多初創公司採取戰術性的方法,在設計上花費的精力很少,在出現問題時進行清理的時間更少。他們認為這樣做是合理的,如果他們成功了,他們就會有足夠的錢聘請更多的工程師來清理垃圾。
如果您所在的公司傾向於這個方向,那麼您應該意識到,一旦代碼庫變成了義大利麵條,就幾乎不可能修複了。您可能要為產品的生命周期支付高昂的開發成本。此外,好的(或壞的)設計的回報來得很快,所以很有可能戰術方法甚至不會加快您的第一個產品發佈。
另一件需要考慮的事情是,公司成功最重要的因素之一是工程師的素質。降低開發成本的最佳方法是雇佣優秀的工程師:他們的成本並不比平庸的工程師高多少,但卻擁有驚人的高生產率。 然而,最好的工程師都非常關心好的設計。如果你的代碼庫是一個殘骸,消息會傳出去,這將使你更難招募。結果,你很可能以平庸的工程師而告終。這將增加您未來的成本,並可能導致系統結構進一步退化。
Facebook 就是一個鼓勵戰術編程的初創公司。多年來,公司的座右銘是“快速行動,打破常規”。“剛從大學畢業的新工程師被鼓勵立即投入到公司的代碼庫中;對於工程師來說,在工作的第一周將提交推進到生產中是很正常的。從積極的一面來看,Facebook 建立了一個賦予員工權力的公司聲譽。工程師有很大的自由度,幾乎沒有什麼規則和限制來阻礙他們。
Facebook 作為一家公司已經取得了驚人的成功,但它的代碼基礎卻因為公司的戰術方法而受損;很多代碼都不穩定,很難理解,只有很少的註釋和測試,而且很難處理。隨著時間的推移,公司意識到它的文化是不可持續的。最終,Facebook 改變了它的座右銘,“以堅實的基礎設施快速發展”,以鼓勵它的工程師在好的設計上投入更多。Facebook 能否成功地解決多年戰術編程積累的問題仍有待觀察。
公平地說,我應該指出,Facebook 的代碼可能並不比創業公司的平均水平差多少。戰術編程在初創公司中很常見;Facebook 就是一個特別明顯的例子。
幸運的是,在矽谷,戰略方法也有可能獲得成功。谷歌和 VMware 與 Facebook 差不多是在同一時期成長起來的,但這兩家公司都採取了更具戰略性的策略。兩家公司都非常重視高質量的代碼和良好的設計,並且都構建了能夠用可靠的軟體系統解決複雜問題的複雜產品。兩家公司強大的技術文化在矽谷廣為人知。很少有公司能與他們競爭頂尖的技術人才。
這些例子表明,一個公司可以用任何一種方法取得成功。然而,在一家關心軟體設計並擁有乾凈代碼庫的公司工作要有趣得多。
3.5 結論
好的設計不是免費的。它必須是你不斷投資的東西,這樣小問題就不會積累成大問題。 幸運的是,好的設計最終會收回成本,而且比你想象的要快。
在應用戰略方法時保持一致是至關重要的,要把投資看作是今天要做的事情,而不是明天要做的事情。當你陷入困境時,很容易把清理工作推遲到危機結束後。然而,這是一個滑坡;在當前的危機之後,幾乎可以肯定會有另一個危機,在那之後又會有一個。一旦你開始延遲設計改進,延遲就很容易變成永久性的,你的文化也很容易滑入戰術方法。解決設計問題的時間越長,問題就越大;解決方案變得更加令人生畏,這使得人們更容易把它們推遲。最有效的方法是讓每個工程師持續地對好的設計進行小的投資。
“免責聲明:本文翻譯僅供學習使用,本文的版權歸英文原作者或出版方,若有侵權,請聯繫刪除。