天天看點

關于代碼品質退化的思考

一個軟體項目從探索階段到發展方向明确階段,會經曆從簡單到複雜的一個過程,需求的不斷疊加,會讓系統越來越龐大,功能繁多,公司業務的擴充也讓軟體系統的生命周期變的更長。在業務變複雜軟的過程中,各種原因的驅使,代碼品質會退化,維護和開發新功能的成本也會相應的變高,推倒重新開發的成本也是高的吓人。

代碼品質退化的步驟

大多情況下編碼設計品質最高的時候是根據第一版需求進行編碼實作的時候,但隻要需求一變更,就會打亂原來的編碼設計,軟體品質也就會越來越差。或者就沒有了設計。

關于代碼品質退化的思考

到了項目中期,有新的功能或者bug的修複,老闆就給我了一天時間,讓我寫好處理代碼?逾期是要被罵的;這個沒用的功能,做了也沒人用,随便寫吧,早點結束,早去幹别的;我手上現在這麼多活,你又插進來個新功能,我隻能亂搞了,團隊内人員水準的不同寫的代碼更是天差地别,等等,這都是我們實際工作中會遇到的問題。責任心讓我們也會想先這樣寫,以後再重構,一般以後重構表示永遠不會重構。

上面說的這些都會讓我們增加糟糕的代碼,混亂的業務邏輯分布在我們系統的各個地方,部門人員變動,新的員工更不可能了解那些雜亂無章的東西,再接着推糟糕的代碼,想要理清楚一個業務邏輯,非常容易在混亂的代碼中迷路。最直接的後果就是這些混亂的代碼會增加新功能的開發周期,上司層問為啥現在開發個功能這麼慢?是不是人手不夠,再招幾個人吧。這雜亂的項目,不是新員工能理的清的,你會發現,雖然員工變多了。但開發效率還是上不去。

關于代碼品質退化的思考

那我們重新來做一個新的系統完全替代這個老項目吧,我們可以用最新的架構,更好的實作方式去完成這個系統,這種天真的想法會在團隊成員的腦海裡無數次出現,舊的系統業務很複雜,新的系統在相容舊系統邏輯的同時,舊的系統也在更新需求,增加功能,在新系統完全可以抗衡舊系統之前,舊的系統會一直運作。如果你的新系統開發的時間過長,等完成的時候,可能員工都已經不知道換了幾批了,代碼又亂成了一鍋粥,周而複始。

軟體的退化變的越來越嚴重的過程中,我們也在思考和改變現有的系統,如何才能讓系統的在擁有更長的生命周期的同時,提高代碼的品質,不讓其退化,并擁有更好的可維護性和擴充性?那就是根據需求的變化去調整架構、代碼,不斷的打破原來的設計,保持清晰,而不是讓他爛在那裡。

漸進式架構

大多數人能想到的最直接的方案是從架構入手,引入多元度的架構,微服務化,領域驅動模型(DDD)等等

從頂層設計出發引入新的架構模型,或者說根據需求的變動不斷的調整代碼的分層和子產品,加上理論知識的應用,會讓業務代碼在結構歸屬上更清晰。分層的嚴密能讓整體的業務邊界更明确,前提是我們要從多元度去審視系統的構架,思考如何去現有的架構做出合理的改動。

從不同的角度去分析和改進現有架構

比如在項目初期業務比較簡單,最簡單的分層架構就實作了項目需求,觀察我們的架構可能是這樣子的,從上而下的松散分層架構

關于代碼品質退化的思考

後來又加入了緩存,又加入了消息隊列,業務的不斷擴張又加入了不同的資料庫nosql,業務的更新有了v2.0,v3.0,新業務要相容舊功能等等,如果還是原來的分層結構,很快就會出現邏輯代碼堆積的問題,業務層之間引用雜亂,一個代碼檔案幾千行代碼,需求變動時牽一發動全身,及時調整架構的必要性就展現出來了。

一定要複用好依賴倒置原則,層與層之間不應該依賴實作,要依賴于抽象,比如我們的基礎設施層要為其他三層提供支援,基礎設施層可以實作其他層定義的接口來進行抽象,從這個角度來開的話我們的基礎設施層應該在最上面,也可以是左邊或者右邊

關于代碼品質退化的思考

應用依賴倒置後,我們調用的是抽象接口,你會發現層的概念沒有了,層的概念被打破了,我們可以更激進一點把基礎設施層剝離出去用各種擴充卡去接入各種元件,把層的關系拉平,把架構調整為六邊形構架

關于代碼品質退化的思考

不要固化自己的思維,根據業務和系統的發展去調整你的系統架構,能讓系統能更高的可擴充和可維護性。

對于非常老的項目調整架構是痛苦的,一定要得到管理層充分的支援下再去做改造,這樣的工作隻能是從上往下推進,痛苦的過程終會換來後期維護的喜悅。

代碼層面

在團隊内除了要有代碼規範,所有人都要遵守,這樣代碼的風格才能更統一,和使用Lint工具去檢查代碼,各種語言lint工具,能在早期查檢出你代碼中不合理的地方。還有下面一些辦法

功能子產品化

程式員最喜歡的就是編碼實作具體的功能,在這裡才是我們真正秀内功的地方,可以應用各種模式把代碼和邏輯寫的很漂亮,但是放到整個項目結構裡,被調用和使用的過程又感覺那麼的不協調,根源是我們子產品劃分不正确,子產品之間的依賴耦合性太強。

這就是典型的寫的很優雅,使用的很粗糙。依賴倒置原則,依然适用于子產品間的劃分,子產品與子產品之間的依賴是倒置的,用依賴注入的方式去解耦,子產品對外暴露出盡可能少的接口,之間的調用依賴于接口。抽象的好處能讓你把子產品的邊界定義的更明确。

對象之間是協作關系,不是糾纏

業務越複雜,需要操作的對象也就越多,對象的邊界不明确就會出現糾纏不清的情況,要不就是一個對象負責的東西過多;要不就是幾個對象同時做一件事,邏輯雜亂。

當你發現你的對象之前不再是協作關系時就要停下來,從高處去看你組織的代碼,把大對象分解,職責界線理清楚也就是功能單一原則,很多同學不知道如何确定一個對象的職責,不清楚一個屬性是不是屬于某個對象,最簡單的方法就是,判斷這個屬性的變動會不影響某個對象,如果沒有就不屬于這個對象。

還有就是,面對新的業務需求敢于打破原有的代碼設計,不破不立。

不要過度開發,删除沒用的代碼

定期要檢查和删除沒用的代碼。少寫或者不寫感覺未來可能會用到的方法,這些多出來的代碼會成為将來重構的絆腳石,會浪費精力在這些沒有用到的代碼上,查找有沒有地方在使用他。

SOLID 原則

不能不提的,就是Bob大叔(Robert C. Martin)的SOLID編碼原則,他是設計模式的基石,要不斷的去應用和實踐。

随着編碼時間的增長,越來越感覺SOLID真的是一盞明燈,當你在黑暗中找不到方向的時候,指引你回歸正确的道路。

如果你對SOLID原則應用的比較熟練,我上面說的幾項完全都可以忽略。

  • 單一職責原則(Single Responsibility Principle)

    每個對象隻有一個職責,明确對象的邊界,文章上面說的對象之間是協作關系,不是糾纏裡就說過如何确定一個屬性是否屬于某個對象。

  • 開閉原則(Open Closed Principle)

    即可擴充(extension),不可修改(modification)原則,抽取出代碼中不變的邏輯,封裝可變的代碼,

    政策模式就很好的表達這個原則的模式,可以檢視之前的部落格: 政策模式

  • 裡氏替換原則(Liskov Substitution Principle)

    繼承必須確定超類所擁有的性質在子類中仍然成立,裡氏替換原則主要闡述了有關繼承的一些原則,也就是什麼時候應該使用繼承,什麼時候不應該使用繼承,以及其中蘊含的原理。裡氏替換原是繼承複用的基礎,它反映了基類與子類之間的關系,是對開閉原則的補充,是對實作抽象化的具體步驟的規範。關于裡氏替換原則的例子,最有名的是“正方形不是長方形

  • 接口隔離原則(Interface Segregation Principle)

    盡量将臃腫龐大的接口拆分成更小的和更具體的接口,讓接口中隻包含調用方感興趣的方法,這也是我們把複雜功能分子產品的應用法則。

    接口隔離原則和單一職責都是為了提高類的内聚性、降低它們之間的耦合性,但兩者是不同的:

    單一職責原則注重的是職責,而接口隔離原則注重的是對接口依賴的隔離。

    單一職責原則主要是限制類,它針對的是程式中的實作和細節;接口隔離原則主要限制接口,主要針對抽象和程式整體架構的建構。

  • 依賴倒置原則(Dependence Inversion Principle)

    抽象不應該依賴于細節,細節應當依賴于抽象。換言之,要針對抽象(接口)程式設計,而不是針對實作細節程式設計。上面在說改進架構的時候有說這個原則

具體的代碼示例這篇文章就不寫了。

關于代碼品質退化的思考

被bob大叔指到的你,一定能寫出更完美的代碼

重構代碼

新功能的開發的同時要重構之前邏輯,堅持開閉原則,能達到事半功倍的效果。

工作閑暇時間去浏覽現有的代碼邏輯,我們每天都在成長,對系統的認知也在改變,思維方式也在不斷的變化,用現在的眼光去審視舊的代碼邏輯,大多數是能找可以優化的地方,或者隐藏的bug,重構他,不要以為這些隻是一些擠牙膏式的調優,所有的事情都有一個從質變到量變的過程。

代碼評審(code review)

代碼評審在團隊裡還是很有必要的,代碼評審不是口水戰,也不是批鬥大會,如果隻是走形式code review的意義也就不存在了。

你寫的代碼是需要讓團隊的成員能看明白的,将來也是會有新的員工來維護你寫的功能的,code review是一個能讓團隊内的其他成員快速了解新代碼意圖的辦法。

大多數團隊裡程式員的水準參差不齊的,對業務和系統的了解深度也是不一樣的,讓團隊内不同的人去code review能及時發現代碼中的不足之處,哪些地方邏輯上有問題,哪裡的業務沒有考慮全面。

關于代碼品質退化的思考

當一次送出的代碼太多時,一下子是看不完,也可能了解不了,就要很評審整體思路,再review實作主幹邏輯,最後才是實作細節。

需說明一下的是,code review 并不能完全發現代碼中隐藏的bug,不要把找bug的任務和他混在一起。

學習多少構架或者架構知識,都不能阻止我們寫爛代碼。但當你沉下心來去打磨産品或者認真去實作一個功能時,你會在意你寫的代碼,會主動去寫更清晰的邏輯,并改變和想辦法去并處理糟糕的代碼,希望這篇文章有能幫助到你的地方。

作者:李鵬

出處:http://www.cnblogs.com/li-peng/

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

繼續閱讀