系統漸漸淪為“屎山”,原因是..

来源:https://www.cnblogs.com/kdaddy/p/18079482
-Advertisement-
Play Games

相信有很多小伙伴都有小貓這樣的體會,尤其是接手一個老的系統的時候,總是會吐槽當前的系統很爛,恨不得馬上將其完完全全重構掉。 ...


分享是最有效的學習方式。

博客:https://blog.ktdaddy.com/

背景

小貓維護現有的系統也有一段時間了,踩坑也不少,事故不少。感興趣的小伙伴可以瞭解一下,往期的小貓踩坑記合集

這天,小貓找到了商城系統的第一任開發老A開始聊天。

“你們這系統是真坑,我都吃過好多次虧了,太爛了...”小貓開玩笑地吐槽道。

“我們當時其實還是花了很長的一段時間去做設計以及評審的,每一步都是有嚴格把控的,當時系統總體骨架還是相當清晰的,也沒有那麼多新的概念,你說現在系統不行了,可不能怪我們啊。一會我給你原始設計文檔看看。後面經過了很多研發的手了,甚至運營和產品都換了好幾撥了,每任運營可能對當前系統的要求都不一樣吧,大家理解可能都不同......”老A侃侃而言著。

小貓抿了口剛倒的茶,意味深長地看著老A...

寫在前面

相信有很多小伙伴都有小貓這樣的體會,尤其是接手一個老的系統的時候,總是會吐槽當前的系統很爛,恨不得馬上將其完完全全重構掉。

前段時間老貓還遇到一個比較逗的小伙伴,他想表達的意思大概是“代碼寫的爛也就算了,他居然還在註釋里撒謊...”,結果他樓下哥們還在一個勁追問他的註釋是怎麼撒謊的,老貓當時邊吃午飯邊在刷手機,老貓看到評論後,笑到噴飯,當然在此也對這位小伙伴表示同情。

其實很多時候一個系統的腐爛和破敗並不是在開始的時候就出現了,而是在持續地迭代升級中漸漸腐化繼而淪為“屎山”。

接下來咱們就來盤點一下到底是一些什麼原因將一個原本架構清晰的系統腐敗淪喪為複雜“屎山”的,然後咱們作為後來人又該如何應對?

“屎山”特征

既然說到系統淪為“屎山”,那麼什麼樣的系統會被定義成“屎山”呢?其實所謂的“屎山”即為非常複雜的系統,難以維護。John OusterhOut在A Philosophy of Software Design這本書中就已經提及了“複雜性就是使得軟體難於理解和修改的因素”。

John OusterhOut將“屎山”(這裡要說明一下,這哥們並沒有說複雜系統叫“屎山”,哈哈,只是咱們都習慣這麼叫了)歸為三大類:

  • Change Amplification(變更放大)
  • Cognitive Load(認知負荷)
  • Unknown Unknowns(未知的未知)

上述幾類特種總結有點抽象,咱們來具體化闡述一下。

變更放大

變更放大其實就是說明明一個相當簡單的需求,卻要動到很多地方的代碼。

相信大家在日常開發中應該也會遇到這樣的問題。老貓也經常遇到,例如明明從需求的理解來說,只要加一個固定的校驗邏輯,這個事情就應該可以搞定了,結果發現,改一個地方的校驗邏輯還不行,可能還要動到各個地方的校驗邏輯。這種情況往往是由於開發在寫代碼過程中復用沒有到位,或者本身流程問題導致的。軟體可拓展性變得很差。

認知負荷

認知負荷說白了就是相關的開發人員在進行開發任務的時候,需要花費很多時間去學習所需要的知識(當然這裡大部分指的是技術知識)才能完成一系列開發任務,於此同時,如果某個知識點沒有掌握好,可能會導致未知的Bug。

打個比方,大部分的開發還是比較傾向於自己熟悉的編程語言或者是開發框架,以及中間件的。例如,前後端分離雖然好,DDD雖然好,但是對於簡單的內部管理系統而言,明明一個mvc就能搞定的事情,非得搞成前後端分離,加上DDD設計分層。明明一個人天就能搞定的事情,非得搞成三人天,另外的維護者可能還得花時間去研究相關技術,這種盲目追求最新技術增加系統本身實現複雜度就是一種本末倒置的行為。

當然認知負荷有的時候可能也不一定是新技術帶來的,也有可能是純粹的技術實現爛,例如不恰當的介面設計、混亂的命名,還有“愛撒謊”的註釋等等。

未知的未知

未知的未知是最要命的,例如,當我們從產品那邊得到一個需求的時候,我們甚至不曉得為了完成這個需求我們到底需要修改哪些代碼才能完成,當前開發甚至還不清楚相關的業務知識。

這種很多時候體現在咱們接手一個新項目的時候,尤其是項目比較複雜的情況下,並且此時的項目沒有任何的技術文檔,這種情況下我們往往是抓瞎的,非常被動,即使對代碼調整完畢之後心裡也還是會沒底,涉及的一些業務場景甚至都沒有理清楚。也不曉得調整完畢之後會不會出現新的問題。

“屎山”誘因

從技術側聊聊,複雜系統發展的誘因,UML之父Grady Booch在《面向對象分析和設計》的觀點是,軟體的複雜性是一個固有屬性,並不是偶然屬性,軟體的發展必然會伴隨複雜性。

誘因有下麵三個:

  1. 模糊性:模糊性產生了最直接的複雜度。
    老貓的理解,關於模糊性包含其實有兩層,一個是需求模糊性,第二個技術模糊性。產品經理對實際的業務把控沒有做到很精準,存在模糊性,導致系統本身的業務覆蓋點經常發生變更,這種是導致系統複雜的罪魁禍首之一。第二技術側的模糊性,技術側的模糊性當然就包含研發人員本身對業務把控不到位,另外的在定義API以及方法命名變數命名的時候存在模糊,無法通過命名直接理解想要表達的意思。

  2. 依賴性:模糊產生複雜性,而依賴導致複雜的傳遞,不斷外移的複雜性將導致最終系統無限腐化,質量失控,修複成本指數級增長。打個比方一個不合理的實現方法被我們認為是一套標準的實現方式,然後後面的很多業務代碼為了方便都會去復用這段邏輯。但是這種不合理的實現方法還在不停的迭代,所以之後系統會發展成什麼樣子,大家可想而知了。

  3. 遞增性:一個軟體系統無論多麼複雜,都是從第一行代碼開始的。然後慢慢“生長”。隨著業務發展,需求不斷產生,功能逐漸豐富,軟體系統隨之演進,同時廢棄而未被及時清除的代碼也是日益膨脹。最終形成一個複雜的系統。
    這點相信理解起來還是比較簡單的。

系統“腐爛”的真相

就像上面小貓和老A的對話那樣,其實很多時候,系統的腐爛並並不是發生在最開始。

很多後端研發在接手新的系統之後,往往對其設計的理解其實是不夠深入的,來了需求之後就是一頓“兵來將擋水來土掩”,可以說是一種戰術性編程,或者說的難聽些“應付式編程”。

這種編程的特點有下麵這幾種:

  1. 快。這類程式員為了快速解決產品需求,總是以腐化系統為代價去解決問題。經過他們之手維護的系統可拓展性差。
  2. 高產。這類程式員代碼量極大,可能不擇手段,完全不會考慮復用,很多時候解決問題就是cv大法。
  3. 坑。他們往往只是專註於功能堆砌卻忽略設計原則和設計規範,有時候命名規範甚至都懶得遵循,成本放到未來,後人買單。咱們經常提到的倒霉的小貓就是經常買單的那位。

上述共同特點就是缺乏設計,完全聚焦於快速交付,註重短期價值不考慮未來發展。

那麼為什麼會這樣的呢?可能會受到以下三點的影響:

  1. 研發人員本身的水平以及認知還有責任心。研發人員本身認知不夠,意識不到系統其實是需要考慮拓展性的,這種往往也是沒有辦法的,另外一種是研發人員抱有僥幸心理,雖然意識到拓展性的問題以及設計問題,但是比較懶,本著“多一事不如少一事,反正我只是過客”的心態去做系統。這類往往在外包系統中體現更為放大。

  2. 互聯網背景下,老闆為了快速適應市場,會進行大量業務試錯,這就會要求程式員快速開發。很多程式員想要好好設計一下系統,可是無奈妥協於項目經理的一而再再而三的問你上線時間。這種情況下,設計可能就成了一種奢侈。

  3. 考評體系不合理。老貓有個朋友,之前一天他和我們吐槽,他們目前領導需要拉出他們每天寫代碼的量去看看他們每天干了多少活。這種真的是滑天下之大稽,在這樣的考評體系下麵,程式員還會好好寫代碼麽。當然這種往往是發生在領導屁都不懂研發的公司。這類領導也是老貓最最鄙視的。技術上明明屁都不懂,還要裝x去指指點點。

“屎山”應對之道

上面聊了這麼多,我們也大概知道了為什麼我們的系統會逐漸淪為“屎山”,可能是在軟體發展過程中的必然,其中也摻雜著各種人為因素以及非人為因素。
當然事情還是要去解決的。那麼我們應當如何應對呢?

  • 尋找合適的架構

    當咱們接到一個複雜系統的時候,其實首先需要理清楚相關的架構,知道系統是如何進行模塊拆分的,另外它們的協作關係和通信方式。具體操作,大家可以訪問老貓之前寫的系統梳理大法

  • 遵循設計原則
    組件層面,咱們的設計原則需要遵循復用/發佈等同原則,共同閉包原則,共同復用原則,無依賴環原則,穩定依賴原則和穩定抽象原則。
    代碼層面,可以參考老貓之前梳理的開發中需要遵循的設計原則

  • 避免破窗效應

    這裡的“破窗效應”其實是出自David Thomas Andrew Hunt的著作《程式員修煉之道》,一扇破窗,只要一段時間不去修理,建築中的居民就會潛移默化地產生一種被遺棄的感覺————當權者不關心這幢建築。然後其他窗戶也開始損壞,居民開始亂丟廢物,牆上開始亂塗鴉,建築開始出現嚴重結構性的損壞。

    聊到咱們軟體系統側其實也是一樣的,在系統發展的過程中,只有在我們修複歷史遺留的問題時,才是真正對其進行了維護。如果我們使用一些極端的手段保持古老陳腐的代碼繼續工作的時候,這其實是一種苟且。例如為了臨時解決問題寫hotfix介面等等。

    在我們開發的過程中,一旦系統有了設計缺陷,咱們其實應該及時優化,否則會形成不好的示範,更多的後來者會傾向於做出類似設計,從而加速系統腐化。

總結

上述就是老貓對系統淪為“屎山”的一些看法,另外的,希望大家比較再提“防禦性編碼”這類概念。這種思想就不應該是一個合格程式員提出的。老貓對這類還是比較抵觸的。“難不成螺絲釘以為自己螺紋角度獨特就不會被取代了?”,咱們把自己負責的東西儘量做到完美,是金子總能發光的,小伙伴們,你們覺得呢?

我是老貓,10year+資深研發,讓我們一起聊聊技術,聊聊職場,聊聊人生~ 更多精彩,歡迎關註公眾號“程式員老貓”。 個人博客:https://blog.ktdaddy.com/
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 基礎與面試題:viewpoint 與 rem、百分比高度、px 一、定義 ​ 一個表總結: 名稱 定義 使用示例 viewpoint 是指用戶在網頁上實際可見和可交互的區域,通常指的是瀏覽器視窗或移動設備的屏幕尺寸。 width:100vw;height:100vh rem (root em)是相對 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 一、HTTP HTTP (HyperText Transfer Protocol),即超文本運輸協議,是實現網路通信的一種規範 在電腦和網路世界有,存在不同的協議,如廣播協議、定址協議、路由協議等等...... 而HTTP是一個傳輸協議 ...
  • it-tools —— 一個為開發人員提供方便的線上工具集合的開源項目,包含了加密、轉換器、Web、開發、圖片和視頻等十幾種工具,功能齊全,部署方便。 ...
  • 所有主要的瀏覽器都內置了一個XML解析器,用於訪問和操作XML XML 解析器 在訪問XML文檔之前,必須將其載入到XML DOM對象中 所有現代瀏覽器都有一個內置的XML解析器,可以將文本轉換為XML DOM對象 解析文本字元串 以下示例將一個文本字元串解析為XML DOM對象,並使用JavaSc ...
  • 0x01 概述 (1)簡介 Tailwind CSS 官網:https://www.tailwindcss.cn/ Tailwind CSS 是一個 CSS 框架,使用初級“工具”類創建佈局 如 Bootstrap 等傳統 CSS 框架,其使用的類通常與組件直接相關;然而,Tailwind 則採用了 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 一、前言 與link類似 在VUE項目中應用typescript,我們需要引入一個庫vue-property-decorator, 其是基於vue-class-component庫而來,這個庫vue官方推出的一個支持使用class方式來開 ...
  • 目錄前言無法調用析構函數的原因改進方法內嵌回收類智能指針局部靜態變數參考文章 前言 在《單例模式學習》中提到了,在單例對象是通過new關鍵字動態分配在堆上的情況下,當程式退出時,不會通過C++的RAII機制自動調用其析構函數。本文討論一下這種現象的原因以及解決方法。 無法調用析構函數的原因 在DCL ...
  • 目錄前言餓漢式懶漢式懶漢式DCLP局部靜態式(Meyers' Singleton)單例模板參考文章 前言 單例模式,其核心目標是確保在程式運行的過程中,有且只有存在一個實例才能保證他們的邏輯正確性以及良好的效率。因此單例模式的實現思路就是確保一個類有且只有一個實例,並提供一個該實例的全局訪問點。 單 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...