你見過的“垃圾”項目是這樣子么?
本文轉載自微信公眾號「跨界架構師」,作者Zachary。轉載本文請聯系跨界架構師公眾號。
大家好,我是Z哥。
我相信每一位程序員最怕遇到代碼質量堪憂的項目,畢竟增加一個同樣的功能,在一個代碼整潔、清晰的項目里與在一個代碼混亂不堪的項目里,效率和質量上的差距達到一個數量級一點也不奇怪。
但是殘酷的現實是,“垃圾項目”到處存在,哪怕是大廠里也不例外。畢竟,沒有人天生就能寫出無比優雅的代碼,都是通過寫“垃圾代碼”一步一步成長起來的,唯一的區別可能就是成長的速度不同罷了。
一個項目如果運氣好,未來成為受重視的項目,那么它還有機會擺脫不少的“垃圾代碼”,但是如果沒那么好運,那就苦了后來人了。
所以,如果你是一位新人程序員,那么我得提醒你,一定要有一個合理的預期,這個合理的預期就是——與垃圾代碼長期為伴。因此,如果你以后因為遇到“垃圾代碼”而破口大罵,這是不講“碼德”的。什么?那么索性跳槽?你怎么能確保下一個接手的項目會更好?
在Z哥看來,一個項目走向“垃圾”、人見人棄的地步,原因只有一個,代碼垃圾,而什么樣的代碼才算垃圾代碼?這就多了,我與你分享一些常見的。
01 組件顆粒度過大
現在三層架構基本已經成為一個基礎共識了,只要不是太古老的項目,不太會存在UI、業務邏輯、數據操作寫在一起的情況。(雖然架構設計方面的后起之秀很多,但是三層架構因為更容易理解,所以市場占有率依舊最高)
但是三層架構的每一層又該如何進一步細分,如何建模?還沒有能夠成為共識的統一標準或者最佳實踐出來。
所以,很多項目在經歷了一年以上的業務發展和變更后,業務邏輯層往往率先淪陷,開始出現大對象,成為開發效率的瓶頸。
近幾年的火熱的領域驅動設計其實已經開始深入到每一層的內部該如何劃分上了。但是離達到共識還有很長的路要走。
02 API數量泛濫
有一些經驗的程序員們會用一招來讓自己在垃圾代碼中游走自如。這招就是盡量通過“增加”的方式實現功能而不是“修改”歷史代碼。
這種方式的確能避開很多“屎坑”,但是從長期來看,這大概率是在創造新的“屎坑”。
某些核心class里幾百個function,成千上萬行的代碼就是這么來的。
03 低內聚、高耦合
「高內聚、低耦合」是軟件開發領域的一條黃金法則,相信每一位程序員都知道。但是現實是,很多項目都存在低內聚、高耦合的問題。
出現這個問題倒也不是說是由于大量的重復代碼導致,而是過度的追求消除重復代碼。盲目的追求減少重復代碼,自然會導致代碼被過度拆分,原本一個完整的業務處理清清楚楚,硬生生被拆分到多個function里去。
復用當然是好的,但應該有個前提條件:不增加系統復雜度的情況下的復用。如果不這樣做,損害了穩定性,增加了復雜性,還會造成代碼可讀性降低。
04 業務邏輯和程序處理邏輯糾纏
Z哥認為,代碼的作用其實就分為兩種,業務邏輯和程序處理邏輯。前者體現的是這個軟件的現實價值,后者則是讓軟件能在計算機上run起來必不可少的部分。
程序處理邏輯主要就是各種數據的存取、dao操作、序列化/反序列化、緩存操作,以及異常處理、參數和返回值準備等等。
如果程序的處理邏輯與業務邏輯混在一起,就好比芝士拌飯,都黏在一起,隨便改一小點功能就扯出一大段代碼要看。
更加可怕的是,如果里面還充斥著大量Magic Number,比如if (errCode == 50001) 。那你得忍住不要罵人。
05 又長又寬的if else
這點其實長期以來就是一直被人詬病的陋習。但是這又幾乎是每一門編程語言都有的語法,那么問題到底在哪里?
因為不管是if else也好,還是switch case也好,其實是一種硬編碼的方式。這就會導致它不容易被修改。
想象一個場景:某個枚舉增加了一個新的值,這個時候你需要將原先判斷這個枚舉的所有if else都檢查一遍,以確保新增的業務能正確執行。真正做過這件事的人相信有過深刻地感受,如果這個枚舉被用到幾十上百的地方,檢查一遍外加弄懂上下文,估計至少半天時間就沒了,而且很有可能最終還是漏改或者改錯什么。
以上就是一些常見的垃圾代碼的樣子。那么,在你的工作中如果遇到充滿垃圾代碼的垃圾項目該怎么辦呢?從流派上說,主要有三大流派,激進派、保守派、重頭再來派。
保守派的做法,主要是從局部修改問題代碼入手。比如前面提到的這些“垃圾”代碼,常見的處理思路是以下這些。
01 業務層禁止層內依賴
你可以留意觀察一下,業務層內的內部相互依賴,是導致代碼高耦合低內聚的主要推手。因為這會導致一個業務方法體內部經常容易囊括一些不在當前業務邏輯內的分支邏輯,使得每個方法的耦合逐漸提高。
所以,禁止層內依賴對降低耦合有立竿見影的效果,這也是領域驅動設計提倡專門拉出一個Application Layer來協調各個Domain之間的交互的目的。
02 將大函數拆小
讓代碼恢復健康,最難啃的骨頭就是那些動輒幾百上千行的函數。保守派雖然避免了大量應用新框架進行替換所帶來的工作量。但是這個最難啃的骨頭是避不開的坎,否則所謂的代碼重構只是隔靴搔癢而已,并沒有多大效果。
03 減少代碼
減少代碼最高效的方式是調用新的系統api或者使用新的框架或者工具。他們可以大批量的代替原先冗余的「程序處理邏輯」。只是對保守派來說,他們會更謹慎地使用新的框架。畢竟,運用一個新框架可是一個不小的手術。
激進派與保守派最大的區別在于,他們更傾向于使用新的框架、工具甚至是新的技術棧、編程語言來解決問題。不過在我看來,這些新東西,可能在短期的確能解決眼前的問題,但是這些問題到底是新技術解決的?還是因為使用新技術而大量重寫“新鮮”的代碼解決的?值得打上一個問號。
最后的重頭再來派很有意思。他們認為老項目已經沒救了,必須重做才行,這是比激進派更激進的一個流派。
可是我見過好多重頭再來派的人員,重頭再來做出的項目,在其他人眼里可能并沒有比之前好多少,甚至在過了一段時間之后,發現重新陷入了之前的困境之中。
因為盲目樂觀是我們人性的弱點。這就像創業者總覺得自己是九死一生中唯一生的那個,買彩票的人總覺得自己是那個千萬分之一的幸運兒一樣。
這三個流派,并沒有絕對的好壞之分,不同的流派都有不同的適用場景,區別就在于「時間、成本、質量」這三個要素上的取舍不同。所以,我們在選擇方案的時候可以根據這三個要素的具體情況來判斷。
因為Z哥認為一個項目的核心要素就是這三者,并且這三者無法兼得,最多只能取其二,類似于分布式系統領域的CAP定理。
Z哥有幸分別參與和主導過這三個流派的工作,以我的經驗來看,我認為這三個流派分別適用的項目情況如下:
- 保守派。時間快,成本低,對質量僅有最基本的要求。
- 激進派。有較高的質量要求,滿足時間較寬裕或者接受成本大幅增加其中的一點。
- 推倒重來派。時間和成本完全給質量讓步,追求可見范圍內的最好。
其實這么一分析你也能發現,總是推倒重來是不現實的,時間和成本這種屬于資源,資源總是有限的。所以,大多數情況下,保守派的選擇才是最常見的。因此我們更應該思考的是如何通過保守改造最大化提高項目的質量,讓他擺脫“垃圾”的標簽。這需要我們沉下心來才能完成,不要老想著推翻重做。
好了,總結一下。
這篇呢,Z哥和你分享了我對如何應對“垃圾項目”的看法。
首先和你分析了5個常見的使得項目逐漸變得垃圾的陋習。
- 組件顆粒度過大
- API數量泛濫
- 低內聚高耦合
- 業務邏輯和程序處理邏輯糾纏
- 又長又寬的if else
然后分享了三個常見的保守派做法:
- 業務層禁止層內依賴
- 將大函數拆小
- 減少代碼
最后分享了應對“垃圾項目”時的三大流派,分別是:
- 保守派
- 激進派
- 推倒重來派
從時間、成本、質量三個維度的權衡來看。保守派才是主流,所以不要動不動就想著推倒重來,收起浮躁的心,沉下心來。
好了,希望對你有所啟發。