您好,登錄后才能下訂單哦!
本篇內容主要講解“系統設計之怎么降低復雜性”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“系統設計之怎么降低復雜性”吧!
熵的概念最早起源于物理學,用于度量一個熱力學系統的無序程度。熱力學第二定律,又稱“熵增定律”,表明了在自然過程中,一個孤立的系統總是從最初的集中、有序的排列狀態,趨向于分散、混亂和無序;當熵達到最大時,系統就會處于一種靜寂狀態。
通俗的講:系統的熵增過程,就是由原始到死亡的過程。“熵”是“活躍”的反義詞,代表負能量。
非生命,比如物質總是向著熵增演化,屋子不收拾會變亂,手機會越來越卡,耳機線會凌亂,熱水會慢慢變涼,太陽會不斷燃燒衰變……直到宇宙的盡頭——熱寂。
在軟件開發、維護過程中。軟件的生命力總是從最初的理想狀態,逐步趨向于復雜、混亂和無序狀態發展,直到軟件不可維護而被迫下線或重構。這種損壞軟件質量的因素的逐步增長,叫做軟件的熵增現象,也即本文討論的軟件復雜性。
代碼混亂、新人不易上手
代碼高度冗余,復用性低,開發效率低
擴展和修改困難,牽一發動全身
業務數據錯亂
程序性能低下
系統難以移置
BUG率居高不下
其它……
復雜性的第一個征兆是,看似簡單的變更需要在許多不同地方進行代碼修改
復雜性的第二個癥狀是認知負荷,這是指開發人員需要多少知識才能完成一項任務。較高的認知負擔意味著開發人員必須花更多的時間來學習所需的信息,并且由于錯過了重要的東西而導致錯誤的風險也更大。
復雜性的第三個癥狀是,必須修改哪些代碼才能完成任務,或者開發人員必須獲得哪些信息才能成功地執行任務,這些都是不明顯的。
復雜性的三種表現形式中,未知的未知是最糟糕的。一個未知的未知意味著你需要知道一些事情,但是你沒有辦法找到它是什么,甚至是否有一個問題。你不會發現它,直到錯誤出現后,你做了一個改變。更改放大是令人惱火的,但是只要清楚哪些代碼需要修改,一旦更改完成,系統就會工作。同樣,高的認知負荷會增加改變的成本,但如果明確要閱讀哪些信息,改變仍然可能是正確的。對于未知的未知,不清楚該做什么,或者提出的解決方案是否有效。唯一確定的方法是讀取系統中的每一行代碼,這對于任何大小的系統都是不可能的。甚至這可能還不夠,因為更改可能依賴于一個從未記錄的細微設計決策。
復雜性是由兩件事引起的:依賴性和模糊性。
依賴關系是軟件的基本組成部分,不能完全消除。實際上,我們在軟件設計過程中有意引入了依賴性。每次編寫新類時,都會圍繞該類的 API 創建依賴關系。但是,軟件設計的目標之一是減少依賴關系的數量,并使依賴關系保持盡可能簡單和明顯。
當重要的信息不明顯時,就會發生模糊。
一個簡單的例子是一個變量名,它是如此的通用,以至于它沒有攜帶太多有用的信息(例如,時間)。或者,一個變量的文檔可能沒有指定它的單位,所以找到它的惟一方法是掃描代碼,查找使用該變量的位置。
晦澀常常與依賴項相關聯,在這種情況下,依賴項的存在并不明顯。例如,如果向系統添加了一個新的錯誤狀態,可能需要向一個包含每個狀態的字符串消息的表添加一個條目,但是對于查看狀態聲明的程序員來說,消息表的存在可能并不明顯。
不一致性也是造成不透明性的一個主要原因:如果同一個變量名用于兩個不同的目的,那么開發人員就無法清楚地知道某個特定變量的目的是什么。
復雜性不是由單個災難性錯誤引起的;它堆積成許多小塊。單個依賴項或模糊性本身不太可能顯著影響軟件系統的可維護性。之所以會出現復雜性,是因為隨著時間的流逝,成千上萬的小依賴性和模糊性逐漸形成。最終,這些小問題太多了,以至于對系統的每次可能更改都會受到其中幾個問題的影響。
大多數程序員日常以戰術編程的心態來進行軟件開發。例如新功能或錯誤修復。乍一看,這似乎是完全合理的:還有什么比編寫有效的代碼更重要的呢?但是戰術編程幾乎不可能產生出良好的系統設計。
與之相對應的是戰略規劃,成為一名優秀的軟件設計師的第一步是要意識到僅工作代碼是不夠的。盡管代碼當然必須工作,但不應將“能跑通的代碼”視為主要目標。戰略設計的主要目標必須是制作出出色的設計,考慮后續的可維護性及擴展性。
戰略性編程需要一種投資心態。盡管前提投入會比戰術編程花費更多的時間,但隨著系統的迭代,戰略編程的優勢就開始逐漸顯現。
當然既然是投資,就要考慮投入產出比,不應該吹毛求疵,只要發現一點不合理的地方就整體大重構。推薦的方式小步快跑的方式,在日常開發中留出5%-10%的時間來做戰略設計。
開發一個新模塊,如果有不可避免的復雜性。兩種設計思路哪個更好:1、應該讓模塊用戶處理復雜性,2、應該在模塊內部處理復雜性?如果復雜度與模塊提供的功能有關,則第二個答案通常是正確的答案。
作為開發人員,很容易以相反的方式行事:解決簡單的問題,然后將困難的問題推給其他人。如果出現不確定如何處理的條件,最簡單的方法是引發異常并讓調用方處理它。這樣的方法短期內會使您的生活更輕松,但它們會加劇復雜性。大多數模塊擁有的用戶多于開發人員,因此此模塊還會有許多人來維護。作為模塊開發人員,您應該努力使模塊用戶的生活盡可能輕松,即使這對您來說意味著額外的工作。另一種更好的方法是,模塊具有簡單的接口比簡單的實現更為重要。
模塊是設計應該是深的,最好的模塊是那些其接口比其實現簡單得多的模塊。這樣的模塊具有兩個優點。1、一個簡單的接口可以將模塊強加于系統其余部分的復雜性降至最低。2、如果以不更改其接口的方式修改了一個模塊,則該修改不會影響其他模塊。如果模塊的接口比其實現簡單得多,則可以在不影響其他模塊的情況下更改模塊的許多方面。
編寫注釋的原因是,使用編程語言編寫的語句無法捕獲編寫代碼時開發人員想到的所有重要信息。注釋記錄了這些信息,以便后來的開發人員可以輕松地理解和修改代碼。注釋的指導原則是,注釋應描述代碼中不明顯的內容。
注釋的最重要原因之一是抽象,其中包括許多從代碼中看不到的信息。抽象的思想是提供一種思考問題的簡單方法,但是代碼是如此詳細,以至于僅通過閱讀代碼就很難看到抽象。注釋可以提供一個更簡單,更高級的視圖(“調用此方法后,網絡流量將被限制為每秒 maxBandwidth 字節”)。即使可以通過閱讀代碼推斷出此信息,我們也不想強迫模塊用戶這樣做:閱讀代碼很耗時,并且迫使他們考慮很多不需要使用的信息模塊。開發人員應該能夠理解模塊提供的抽象,而無需閱讀其外部可見聲明以外的任何代碼。
名稱是一種抽象形式:名稱提供了一種簡化的方式來考慮更復雜的基礎實體。良好的名字是一種文檔形式:它們使代碼更易于理解。它們減少了對其他文檔的需求,并使檢測錯誤更加容易。相反,名稱選擇不當會增加代碼的復雜性,并造成可能導致錯誤的歧義和誤解。
命名需滿足以下幾個要求:
名稱最常見的問題是名稱太籠統或含糊不清。結果,讀者很難說出這個名字指的是什么。讀者可能會認為該名稱所指的是與現實不符的事物,如上面的代碼錯誤所示。考慮以下方法聲明:
/** * Returns the total number of indexlets this object is managing. */ int IndexletManager::getCount() {...}
術語“計數”太籠統了:計數什么?如果有人看到此方法的調用,除非他們閱讀了它的文檔,否則他們不太可能知道它的作用。像 getActiveIndexlets 或 numIndexlets 這樣的更精確的名稱會更好:因為使用這些名稱,讀者可能無需查看其文檔就能猜測該方法返回的內容。
在任何程序中,都會反復使用某些變量。例如,文件系統反復操作塊號。對于每種常見用法,請選擇一個用于該目的的名稱,并在各處使用相同的名稱。例如,文件系統可能總是使用 fileBlock 來保存文件中塊的索引。一致的命名方式與重用普通類的方式一樣,可以減輕認知負擔:一旦讀者在一個上下文中看到了該名稱,他們就可以重用其知識并在不同上下文中看到該名稱時立即做出假設。
一致性具有三個要求:
始終將通用名稱用于給定目的;
除了給定目的外,切勿使用通用名稱;
確保目的足夠狹窄,以使所有具有名稱的變量都具有相同的行為。
選擇名稱的目標是在讀者的腦海中創建一幅關于被命名事物的性質的圖像。
一個好名字傳達了很多有關底層實體是什么,以及同樣重要的是,不是什么的信息。在考慮特定名稱時,請問自己:“如果有人孤立地看到該名稱,而沒有看到其聲明,文檔或使用該名稱的任何代碼,他們將能夠猜到該名稱指的是什么?還有其他名稱可以使畫面更清晰嗎?” 當然,一個名字可以輸入多少信息是有限制的。更泛化一些,能根據幾個名字構建起一個模塊的視圖,根據模塊的名稱構建起單個系統的視圖,根據單個系統命名構建起整個業務的視圖。
敏捷開發是一種軟件開發方法,它是在 1990 年代末期出現的,其思想涉及如何使軟件開發更加輕量,靈活和增量。
敏捷開發中最重要的元素之一是開發應該是漸進的和迭代的概念。在敏捷方法中,軟件系統是通過一系列迭代開發的,每個迭代都添加并評估了一些新功能。
現代的敏捷開發思想已經融合進了devops、持續集成等工具當中,在企業中可以使用現成的工具來實現軟件開發的快速驗證及迭代,開源工具也有很多。比如Jenkins。
持續集成工具中集成了很多有用的工具,比如靜態代碼檢查、單元測試、自動化測試、預合并、自動部署等功能。
Coca是一個用于系統重構、系統遷移和系統分析的瑞士軍刀。它可以分析代碼中的 badsmell,行數統計,分析調用與依賴,進行 Git 分析,以及自動化重構等。
借助coca工具,可以實現快速掌握系統整體的情況,比如重點方法調用圖、類之間關系、系統命名健康情況、代碼質量評估等。
示例一:類依賴關系
示例二:方法調用圖
示例三:變量命名出現次數統計
+------------------+--------+ | WORDS | COUNTS | +------------------+--------+ | context | 590 | | resolve | 531 | | path | 501 | | content | 423 | | code | 416 | | resource | 373 | | property | 372 | | session | 364 | | attribute | 349 | | properties | 343 | | headers | 330 | +------------------+--------+
示例四:代碼質量評估
+--------------------------------+-------+-----------------------+-------+-----------+ | TYPE | COUNT | LEVEL | TOTAL | RATE | +--------------------------------+-------+-----------------------+-------+-----------+ | Nullable / Return Null | 0 | Method | 1615 | 0.00% | | Utils | 7 | Class | 252 | 2.78% | | Static Method | 0 | Method | 1615 | 0.43% | | Average Method Num. | 1615 | Method/Class | 252 | 6.408730 | | Method Num. Std Dev / 標準差 | 1615 | Class | - | 7.344917 | | Average Method Length | 13654 | Without Getter/Setter | 1100 | 12.412727 | | Method Length Std Dev / 標準差 | 1615 | Method | - | 20.047092 | +--------------------------------+-------+-----------------------+-------+-----------+
到此,相信大家對“系統設計之怎么降低復雜性”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。