}
這類程序員往往是項目組里開發(fā)效率比較高的人,但是大量的業(yè)務開發(fā)工作導致他們不會做多余的思考,他們的口頭禪是:“我每天要做 XX 個需求”或者“先做完需求再考慮其他的吧”。
這種反模式表現(xiàn)出來的后果往往是代碼很難復用,面對 的時候,程序員迫切的想要把需求落實成代碼,而這往往也會是個循環(huán):寫代碼的時候來不及考慮復用,代碼難復用導致之后的需求還要繼續(xù)寫大量的代碼。
一點點積累起來的大量的代碼又帶來了組織和風格一致性等問題,最后形成了一個新功能基本靠拷的遺留系統(tǒng)。
2.5 還有嗎
爛代碼還有很多種類型,沿著功能-性能-可讀-可測試-可擴展這條路線走下去,還能看到很多匪夷所思的例子。
那么什么是爛代碼?個人認為,爛代碼包含了幾個層次:
所以,當一個團隊里的底層代碼難以閱讀、耦合了上層的邏輯導致難以測試、或者對使用場景做了過多的假設導致難以復用時,雖然完成了功能,它依然是垃圾代碼。
2.6 夠用的代碼
而相對的,如果一個工程的代碼難以閱讀,能不能說這個是爛代碼?很難下定義,可能算不上好,但是能說它爛嗎?如果這個工程自始至終只有一個人維護,那個人也維護的很好,那它似乎就成了“夠用的代碼”。
很多工程剛開始可能只是一個人負責的小項目,大家關心的重點只是代碼能不能順利的實現(xiàn)功能、按時完工。
過上一段時間,其他人參與時才發(fā)現(xiàn)代碼寫的有問題,看不懂,不敢動。需求方又開始催著上線了,怎么辦?只好小心翼翼的只改邏輯而不動結(jié)構(gòu),然后在注釋里寫上這么實現(xiàn)很 ugly,以后明白內(nèi)部邏輯了再重構(gòu)。
再過上一段時間,有個相似的需求,想要復用里面的邏輯,這時才意識到代碼里做了各種特定場景的專用邏輯,復用非常麻煩。為了趕進度只好拷代碼然后改一改。問題解決了,問題也加倍了。
幾乎所有的爛代碼都是從“夠用的代碼”演化來的,代碼沒變,使用代碼的場景發(fā)生變了,原本夠用的代碼不符合新的場景,那么它就成了爛代碼。
3、重構(gòu)不是萬能藥
程序員最喜歡跟程序員說的謊話之一就是:現(xiàn)在進度比較緊,等 X 個月之后項目進度寬松一些再去做重構(gòu)。
不能否認在某些(極其有限的)場景下重構(gòu)是解決問題的手段之一,但是寫了不少代碼之后發(fā)現(xiàn),重構(gòu)往往是程序開發(fā)過程中最復雜的工作。花一個月寫的爛代碼,要花更長的時間、更高的風險去重構(gòu)。
曾經(jīng)經(jīng)歷過幾次忍無可忍的大規(guī)模重構(gòu),每一次重構(gòu)之前都是找齊了組里的高手,開了無數(shù)次分析會,把組內(nèi)需求全部暫停之后才敢開工,而重構(gòu)過程中往往哀嚎遍野,幾乎每天都會出上很多意料之外的問題,上線時也幾乎必然會出幾個問題。
從技術上來說,重構(gòu)復雜代碼時,要做三件事:理解舊代碼、分解舊代碼、構(gòu)建新代碼。而待重構(gòu)的舊代碼往往難以理解;模塊之間過度耦合導致牽一發(fā)而動全身,不易控制影響范圍;舊代碼不易測試導致無法保證新代碼的正確性。
這里還有一個核心問題,重構(gòu)的復雜度跟代碼的復雜度不是線性相關的。比如有 1000 行爛代碼,重構(gòu)要花 1 個小時,那么 5000 行爛代碼的重構(gòu)可能要花 2、3 天。要對一個失去控制的工程做重構(gòu),往往還不如重寫更有效率。
而拋開具體的重構(gòu)方式,從受益上來說,重構(gòu)也是一件很麻煩的事情:它很難帶來直接受益,也很難量化。這里有個很有意思的現(xiàn)象,基本關于重構(gòu)的書籍無一例外的都會有獨立的章節(jié)介紹“如何向 boss 說明重構(gòu)的必要性”。
重構(gòu)之后能提升多少效率?能降低多少風險?很難答上來,爛代碼本身就不是一個可以簡單的標準化的東西。
舉個例子,一個工程的代碼可讀性很差,那么它會影響多少開發(fā)效率?
你可以說:之前改一個模塊要 3 天,重構(gòu)之后 1 天就可以了。但是怎么應對“不就是做個數(shù)據(jù)庫操作嗎為什么要 3 天”這類問題?爛代碼“爛”的因素有不確定性、開發(fā)效率也因人而異,想要證明這個東西“確實”會增加兩天開發(fā)時間,往往反而會變成“我看了 3 天才看懂這個函數(shù)是做什么的”或者“我做這么簡單的修改要花 3 天”這種神經(jīng)病才會去證明的命題。
而另一面,許多技術負責人也意識到了代碼質(zhì)量和重構(gòu)的必要性,“那就重構(gòu)嘛”,或者“如果看到問題了,那就重構(gòu)”。上一個問題解決了,但實際上關于重構(gòu)的代價和收益仍然是一筆糊涂賬,在沒有分配給你更多資源、沒有明確的目標、沒有具體方法的情況下,很難想象除了有代碼潔癖的人還有誰會去執(zhí)行這種莫名其妙的任務。
于是往往就會形成這種局面:
4、寫好代碼很難
與寫出爛代碼不同的是,想寫出好代碼有很多前提:
寫出好代碼的方法論很多,但我認為寫出好代碼的核心反而是聽起來非常 low 的“持續(xù)不斷的練習”。這里就不展開了,留到下篇再說。
很多程序員在寫了幾年代碼之后并沒有什么長進為什么源代碼沒有2,代碼仍然爛的讓人不忍直視,原因有兩個主要方面:
而工作幾年之后的人很難再說服他們?nèi)ヌ岣叽a質(zhì)量,你只會反復不斷的聽到:“那又有什么用呢?”或者“以前就是這么做的啊?”之類的說法。
那么從源頭入手,提高招人時對代碼的質(zhì)量的要求怎么樣?
前一陣面試的時候增加了白板編程、最近又增加了上機編程的題目。發(fā)現(xiàn)了一個現(xiàn)象:一個人工作了幾年、做過很多項目、帶過團隊、發(fā)了一些文章,不一定能代表他代碼寫的好;反之,一個人代碼寫的好,其它方面的能力一般不會太差。
舉個例子,最近喜歡用“寫一個代碼行數(shù)統(tǒng)計工具”作為面試的上機編程題目。很多人看到題目之后第一反映是,這道題太簡單了,這不就是寫寫代碼嘛。
從實際效果來看,這道題識別度卻還不錯。
首先,題目足夠簡單,即使沒有看過《面試寶典》之類書的人也不會吃虧。而題目的擴展性很好,即使提前知道題目,配合不同的條件,可以變成不同的題目。比如要求按文件類型統(tǒng)計行數(shù)、或者要求提高統(tǒng)計效率、或者統(tǒng)計的同時輸出某些單詞出現(xiàn)的次數(shù),等等。
從考察點來看,首先是基本的樹的遍歷算法;其次有一定代碼量,可以看出程序員對代碼的組織能力、對問題的抽象能力;上機編碼可以很簡單的看出應聘者是不是很久沒寫程序了;還包括對于程序易用性和性能的理解。
最重要的是,最后的結(jié)果是一個完整的程序,我可以按照日常工作的標準去評價程序員的能力,而不是從十幾行的函數(shù)里意淫這個人在日常工作中大概會有什么表現(xiàn)。
但即使這樣,也很難拍著胸脯說為什么源代碼沒有2,這個人寫的代碼質(zhì)量沒問題。畢竟面試只是代表他有寫出好代碼的能力,而不是他將來會寫出好代碼。
5、悲觀的結(jié)語
說了那么多,結(jié)論其實只有兩條,作為程序員:
如果你看到了這里還沒有喪失希望,那么可以期待一下這篇文章的第二部分,關于如何提高代碼質(zhì)量的一些建議和方法。
本文由秦迪投稿,編輯四正,想更多交流上述高質(zhì)量代碼話題,可以回復 join 申請進群。轉(zhuǎn)載本文請注明來自高可用架構(gòu) 「」微信公眾號并包含以下二維碼。