入職的第一週:如何快速上手一個項目的軟體設計?
入職第一週,通常都在了解一個公司內的資訊與項目,關於軟體設計的部分,我們應該如何快速上手?如何辨快速地抓住當前軟體架構的要點?讓我們一步一步來拆解。
首先,先讓我們定義與了解軟體設計是什麼?
軟體設計是什麼以及通常要注意什麼?
我們學習了軟體設計到底是什麼,它應該包括「模組」和「規範」兩部分:
- 模組,是一個軟體的骨架,是一個軟體之所以是這個軟體的核心。模組的粒度可大可小。我們所說的「高內聚、低耦合」指的就是對模組的要求,一個好的模組可以有效地隱藏細節,讓開發者易於理解。模組是分層的,可以不斷地疊加,基於一個基礎的模組去構建上一層的模組,計算機世界就是這樣一點點構建出來的。
- 規範,就是限定了什麼樣的需求應該以怎樣的方式去完成。它對於維繫軟體長期演化至關重要。關於規範,常見的兩種問題是:一個項目缺乏顯式的、統一的規範;規範不符合軟體設計原則。模型與規範,二者相輔相成,一個項目最初建立起的模型,往往是要符合一定規範的,而規範的制定也有賴於模型。
SoC (Separation of concerns)
關注點分離(Separation of concerns,SoC),是將計算機程序分隔為不同部份的設計原則。每一部份會有各自的關注焦點。關注焦點是影響計算機程式程式碼的一組資訊。關注焦點可以像是將程式碼優化過的硬體細節一般,或者像實例化類別的名稱一樣具體。
關注點分離,是對只與「特定概念、目標」(關注點)相關聯的軟體組成部分進行「標識、封裝和操縱」的能力,即標識、封裝和操縱關注點的能力。是處理複雜性的一個原則。由於關注點混雜在一起會導致複雜性大大增加,所以能夠把不同的關注點分離開來,分別處理就是處理複雜性的一個原則,一種方法。分離關注點使得解決特定領域問題的程式碼從業務邏輯中獨立出來,業務邏輯的程式碼中不再含有針對特定領域問題程式碼的調用(將針對特定領域問題程式碼抽象化成較少的程式碼,例如將程式碼封裝成function或是class),業務邏輯同特定領域問題的關係通過側面來封裝、維護,這樣原本分散在整個應用程式中的變動就可以很好的管理起來。
舉例
CQRS (Command Query Responsibility Segregation) 是一種架構模式,它強調對於系統中的查詢和修改操作進行明確區分和分離。它將系統中的讀操作(查詢)和寫操作(修改)分離成兩個不同的模型,這樣就可以更好地設計和優化這些模型,以更好地滿足業務需求。具體來說,CQRS 模式通常涉及分離讀模型和寫模型,每個模型都有自己的命令和查詢協議,並且使用自己的資料儲存系統。由於 CQRS 提供了更明確的分離,這使得開發人員可以更容易地設計和實現一些複雜的系統功能,例如多項目同步或分散式的查詢分析等。
可測試性
軟體設計中要時必須考慮「可測試性」
我們知道需求可以分成:
- 功能性需求:滿足業務的功能
- 非功能性需求:
- 執行品質
- 延時
- 安全
- 吞吐量
- 演化品質
- 可測試性
- 可維護性
- 執行品質
主題:我們如何了解一個項目軟體設計以及他的架構?
程式碼是有生命的。他的基因來自所有貢獻過的工程師。
一個軟體工程師剛入職一個新公司,對於他來說等於是要熟悉一個新項目。很多人會選擇一頭熱進去看程式碼。其實這樣是不對的,剛要走進一片森林,如果你看到樹、草就靠近去研究,你很快就會迷路的。軟體項目也是這樣的,一頭栽進去很快就會迷茫地下班。
我們要有「套路」的去攻陷一個新項目。首先,先不要看到什麼就「過度評判」。一個項目有太多歷史了,在妳認為「不合理的」、「過時的」這些設計或程式碼中,可能參雜了無數的歷史、妥協與共業。所以,先讓我們保持耐心。
理解三步:解決什麼問題、入口與接口、實現方式
解決什麼問題
「解決什麼問題」通常是一個軟體的核心。整個軟體設計中最重要的就是設計與建構出「解決什麼問題」,而如果我們理解了一個設計中的「解決什麼問題」,可以幫助我們了解軟體樣貌。這邊的「解決什麼問題」的重點在於,透過這個問題,我們可以確定軟體的目標使用者、使用情境以及主要功能。在設計軟體時,必須聚焦於解決一個實際存在的問題,並提供一個有效、高效的解決方案。
因此,軟體團隊必須具備深入的市場調查、用戶分析和技術實力,以確保軟體設計的準確性和實用性。 一個成功的軟體建設必須始終關注最終產品的關鍵問題,並確保所有其他功能都服務於這個目標。我們可以從這個要素,反向追求到這個軟體要解決什麼問題。
入口與接口
一個軟體要將解決什麼問題的能力輸出出去,最直接的方式就是入口與接口,比如說:
- API :API 就像是一個軟體的表達能力,他知道如何解決問題,並且把這個能力輸出給其他使用者(可能是其他人或其他系統)
- CLI 入口:軟體也可能以 CLI 介面的方式輸出他的能力,與 API 目標一致,只是輸出的方式不同。像是我們常用的
Git
指令,就是透過指令的方式輸出他版本控制的能力。
實現方式
了解了「解決什麼問題」與「入口與接口」,我們就可以去了解是如何實現的。這是軟體發揮價值的根基,同時也是多人協作完成的軟體功能。
比如:
- 一個課程的上架申請,是把申請資料寫入資料庫,或者發到消息列隊中交給其他系統處理?
- 不同系統的連接,是透過 HTTP 還是 gRPC?
- 一個 API 的實現,資料流向應該是怎樣?Request → Controller → Data Mapper or Service ?
- 是使用 RDB 儲存資料或者 NoSQL?如何保證資料的ACID?
要注意的點
我們要注意的點,「解決什麼問題」與「實現」要拆開來看。比如說非同步任務,我們可以透過消息列隊系統進行處理。我們不能說是非同步任務,我們透過 RabbitMQ 來處理。當然這在日常討論是沒有關係,但我們要知道**「解決什麼問題」與「實現」要拆開來看**,尤其是在撰寫文件或者說明書的時候。
我們需要將「解決什麼問題」與「實現」的方式清楚地分開來。這樣可以讓讀者更容易理解我們的思路和解決方案。舉個例子,如果我們的目標是解決數據庫載入速度的問題,我們可以采用兩種方法:一種是增加資源,比如CPU、內存等;另外一種是使用更高效的算法或者緩存技術優化數據庫查詢效率。在最終的文檔中,我們需要清晰地表達我們要解決的問題和選擇的方案,以及每個方案所帶來的優缺點。這樣可以幫助讀者更快速地理解,也能夠更好地選擇最合適的解決方案。
總結
- 軟體設計包括模組和規範兩部分,高內聚低耦合是對模組的要求。
- 關注點分離是處理複雜性的一個原則,將不同的關注點分離處理,例如 CQRS。
- 可測試性是軟體設計中必須考慮的一個要素。
- 理解一個軟體項目需要解決什麼問題、入口與接口、實現方式三步。
- 需要注意區分「解決什麼問題」與「實現方式」,並清晰地表達解決方案的優缺點。
這篇文章主要介紹了如何了解一個項目的軟體設計和架構。首先,必須了解軟體設計包括模組和規範兩部分,模組是軟體的核心,而規範可以幫助維持軟體長期演化。其次,要注重關注點分離原則,將不同的關注點分離開來,分別處理以減少複雜性。最後,需要注意「解決什麼問題」和「實現方式」的區分,以清楚地表達解決問題的方案和所帶來的優缺點。文章簡潔明瞭,建議閱讀相關技術人員和軟體開發人員。
感謝大家的收看,最後以我第一天上班的感觸勉勵大家:
時勢逼人,珍惜程式碼中的生命:抵賴、償還技術債
程式碼雖然亂,但我看得出來,那是戰爭、戰鬥的痕跡。是扛著業務崩潰的風險,是戰士的勳章。所以我不會說這是「髒代碼」。因為我知道有多少個乾淨的代碼死在了抵達戰場前。
但他確實是技術債,是我們為了業務、為了生存而透支的代價。這些代價應該要在我們年富力強的時候照顧他,修復它。