[TOC]
【讀後總結】程式設計師修煉之道---從小工到專家
一,個人讀後總結
本書相對比較基礎,不是那種大規模程式設計、高併發設計等等,主要是針對程式設計師的一些基本素質和一些基本常規程式設計設計做一些梳理和規範,對於初入職的程式設計師,養成這些良好素質是非常有必要的;對於已經入職多年的程式設計師,回顧一下本書,然後結合自身情況看看是否能夠基本達到本書中的一些素養也是有必要的。
整體而言,有一定的經驗性總結,相對來說比較基礎,對開發者也有一定的作用;對我個人而言,裡面很多的素養、設計規範之類都有一定了解,不過可能平時做的不夠徹底,因此看完之後,還是有一定的收穫,至少有了這樣的文件性的總結,方便後續快速檢閱檢視。
二,程式、架構設計方面
1,避免重複,進行復用
複用可以減少程式碼臃腫,也可以降低改動風險(一個改動,要改動多處,容易遺漏),增加開發效率。如下幾個情況可能會使得有重複的程式碼,需要注意儘量避免:
- 程式碼模組功能類似
- 不同語言要實現同一功能
- 不同開發者實現同一個類似功能
2,靈活的設計、隔離性
專案開發中,經常會遇到某個功能需求改變,或者某個底層資源改變,或者資料結構的改變,要做到撤銷的最小代價,注意專案永遠沒有最終最確定的抉擇
程式碼架構的設計要保持靈活性、隔離性、可替代性;如某種負載均衡演算法的替換,如istio資料平面的替換等。
這個架構設計需要:
-
解耦
-
介面抽象
- 抽象出各種不同介面,如虛基類、純虛基類、介面和實現
-
隱藏細節
- 介面暴露的方式,需要隱藏一些私有的細節處理,對外暴露統一的外部方法
-
隔離
- 如何保證互不影響,互不管理
-
後設資料方式
3,解耦合【正交性】
劃分出細粒度的模組,然後各個模組之間解耦合,比如有一個函式的得墨忒耳法則.得墨忒耳定律也叫做“最少了解原理”,是一種軟體設計原理,尤其是應用到物件導向的程式設計中,基本原理為:
- 每個物件對其他物件只能有最少的瞭解:只有總體才能接近個別物件;
- 每個物件只能和自己的朋友對話:不要和陌生人說話;
- 只和自己最親密的朋友對話。
一定儘量不要開發設計出強耦合的系統,要劃分模組、分層設計,這樣可以提高效率,也能降低風險,否則,會牽一髮而動全身。最簡單的如MVC架構模型,上層應該可以支援多種形態,改動一個模組應該隻影響另外一個模組的呼叫而不是影響全域性
每個模組的設計需要有暴露給外部的,同時也會需要有私有的。解耦合的設計的理念就是:
- 分層
- 分模組
- 抽象
4,分層架構設計
程式架構要分層,分而治之,劃分不同功能的子模組;劃分模組之後,就要考慮模組(子服務)之間如何通訊問題,常用的方案如:
-
pub/sub:釋出訂閱模式
- 只對感興趣事件進行訂閱
-
MVC模式
- Model-View-Controller
5,後設資料的設計
用後設資料(metadata)描述應用的配置選項、引數、使用者偏好等,很多程式設計中都用到了後設資料,尤其是一些開源的大型專案中,那麼後設資料到底是啥?後設資料是指資料的資料,廣義上就是任何對應用描述的資料。如資料庫schema或資料詞典。schema含有名稱、儲存長度等屬性進行描述的屬性,我們應該要可以訪問和操作這些資訊,就像對資料庫中任何其他資料一樣。
典型情況系,後設資料應該在執行時而不是編譯時被訪問和使用。優雅的方式是使用後設資料進行資料配置和驅動應用,達到這樣的目標:宣告式思考,也即是規定要做什麼而不是怎麼做,並建立高度靈活的程式。核心設計思想就是將抽象放進程式碼,細節放進後設資料,這樣的優勢在於:
-
設計必須要解耦合,這樣會更靈活
-
需要建立更健壯、更抽象的設計;細節的處理推遲到程式之外
- 這個,我還沒有理解明白
-
可定製,如外掛化,無需修改程式
6,軟體程式的併發和次序
時間是軟體架構的一個經常被忽略的方面,這裡的時間指的是程式自身的時間因素:
- 併發:同一時間發生多個事件
- 次序:事件在時間中的相對位置
尤其是網際網路的開發設計中,併發是一個不可忽視的因子,設計之初就必須要考慮進來;如何防止併發衝突?如何保證高併發?
防止併發衝突,改善併發性,一個可能的原則就是分析工作流,可以通過UML活動圖去分析。
另外,併發方面的程式設計,要考慮到多程式、多執行緒、多協程;服務端架構設計還要考慮高併發,如何擴縮容等
7,原型->基礎框架->逐漸填充
當需求並不明朗的時候,或者當需要從0到1的時候,可以先快速搭建一個基礎框架,實現一個最簡單的訴求,當然需要劃分模組、分層等基礎設計,不用太過複雜,先實現效果,然後逐漸填充和豐富,小版本重構和優化,最終形成一個大的專案
前期一定需要原型的配合,先構建原型出來,然後再逐步迭代優化,需要注意:
- 正確性
- 完整性
- 健壯性
- 風格
原型設計中需要考慮:
- 元件的定義和責任劃分是否清晰
- 耦合是否最小、是否細粒度
- 介面定義、約束是否滿足訴求
8,進行預估和評審
任何專案都需要進行預估,預估一下整體時間、風險點、專案大小等;預估完了之後,進行初步設計,設計了之後需要再進行評審:
- 拆分元件、拆分模組
- 細粒度元件、子模組的預估
- 專案進度的預估
- 專案風險的預估
- 需求的評審
- 專案的評審
- 架構設計的評審
三,程式編碼方面
要不斷批判所有程式碼,包括自己的和別人的!!!
1,理解程式碼的工作原理
-
不要盲目的寫程式碼,要先理清原理、需求、設計等等,最後才是編碼
-
要制定階段性的規劃
-
思考所有可能的邊界並處理好所有邊界條件,不要靠猜
-
每一行程式碼都要清楚含義,確保自己寫的程式碼就是自己要表述的流程,對程式碼白盒化
-
嚴格的測試用例、正常條件、異常條件
-
copy原有程式碼的時候,想想,是否能夠優化?原有程式碼是否合適?
2,理清系統效能
要時刻估算程式的執行情況,QPS=10w如何,QPS=100W如何? QPS=1000W的時候又當如何?因為隨著變化,大多數情況下都不是線性變化的。估算的範圍包括但不限於:系統的處理時間、佔用記憶體、CPU、磁碟io等
那如何估算?除了已有知識和經驗能夠幫助估算外,還可以進行建模估算:
- 迴圈
- 巢狀迴圈
- 二分法
- 分而治之
- 組合
3,程式碼隨時重構
架構需要優化,程式碼也隨時需要優化,前期的程式碼總會有優化之處
當程式碼出現重複、過時的知識、效能問題、耦合性太強的時候就必須要進行重構;而且我們需要經常性的重構並且要早早的開始重構,否則越到後面,歷史包袱越大;每次迴歸自己的程式碼,都要考慮,能否重構,可否更優?
如果後面一個專案copy或者沿用前一個專案,那麼後面的專案,一定要比前面的專案架構要更優,一定要做出改變,否則就不會有成長。
重構的時候需要注意一些技巧如:重構的時候不要新增功能,重構之前需要有較為全面的單元測試用例,重構完了之後需要全面測試
4,編寫易於測試的程式碼和豐富的測試用例
單元測試、整合測試
小模組的測試
豐富的測試用例
示例程式碼
5,按合約設計(DBC)
人不可能寫出十分完美的軟體,不符合預期的程式、介面時有發生,我們需要防衛性的編碼,因此就是對方的都不可信任,比如輸入引數。
按合約設計的思想在於充分利用前置條件、後置條件、類不變項。其實意思就是一切要按照事先約定的合約進行,如何保證呢?那麼必須在設計的時候考慮:輸入域的範圍、邊界條件是如何、輸出資料是怎樣、可以輸出什麼不可以輸出什麼。
一些好的姿勢包括:斷言、預處理、提前返回錯誤和崩潰。關於提前返回錯誤和崩潰的意義在於對於輸入的檢測上,要保證最初輸入的異常就返回而不用等到程式開始計算執行之後才返回
6,程式發生奔潰的處理
程式發生錯誤、奔潰是無法避免的,但是我們需要知道,如果錯誤已經發生,那麼代表程式一定在某些地方存在問題,尤其是一些無法必現的問題,那麼就需要我們在錯誤發生之後能夠有足夠的資訊去分析它並fix它。檢查每一個可能的錯誤,尤其是意料之外的錯誤是一種良好的實踐。
如果程式發生一些極端錯誤之後,如果沒有終止程式,很有可能導致後端資料產生髒資料或者後端請求出現批量異常等等。因此需要及早丟擲異常
通過斷言來檢測輸入引數,在c、c++中是常用的優雅姿勢,但是不要用斷言去處理真正的錯誤流程
處理好錯誤流程和異常處理流程、捕獲異常並進行處理,但是需要區分什麼情況下才是真正的異常,這個可能需要根據實際情況去分析
7,解決疑難雜症問題的思路
要知道,任何問題都有解決方案,只是你暫時沒有找到,或者沒有找到合適的。排查問題的方法:梳理出所有可能的路徑,先不要排除任何東西,然後逐一檢查並排除。
對於疑難雜症的重要的思考點:
- 這個問題是思路是否正確?注意力在這上面是否正確?
- 是否有更容易的方法?
- 為什麼如此難以解決?
- 必須是這種方式解決嗎 ?
- 這個為什麼是一個問題 ?
- 真的必須解決嗎 ?
四,專案管理相關
1,需求相關
專案是否能夠成功?專案的各種需求?
業務專案而言,會有產品經理提需求;基礎專案而言,需要我們開發人員自己挖掘需求、蒐集需求,其中最重要就是挖掘需求
一個典型例子:
- 只有指定人員才能檢視檔案【good】
- 這樣的需求過來,開發人員會設計一套許可權管理系統,方便後續擴充套件
- 只有領導和人事部門才能檢視檔案【bad】
- 這樣的需求過來,開發人員可能只是做一個簡單的配置,進行前置靜態檢測
- 只要需求改變,就可能無法滿足,甚至需要修改程式碼
因為這就告訴我們幾點:
- 需求很有可能是經常變動的,需求是否合理,如何滿足日益變化的需求
- 需求的陳述表達
- 設計的時候一定要考慮後續的相容性和擴充套件性
- 抽象很重要
2,思考清楚再開始啟動專案
如果有疑惑,一定要反覆思考清楚,等一起都思考清楚,準備就緒後再開始編碼、專案設計。
因為一旦沒有思考清楚,很可能導致返工,或者是無用功,就怕就是折騰一兩個月後發現前面都做錯了!
3,程式的規範
程式需要有一定的規範,尤其是多人協作的程式
4,自動化工作流程
工作流程自動化、專案自動化,構建、編譯、部署等;這個在我們目前現有系統和工作中基本已經都是自動化了,如CI、CD等
5,各種型別的測試
自動化測試,早測試、常測試,測試佔編碼很大一部分;專案需要單元測試、整合測試;需要有一定的覆蓋度。主要測試種類包括:
- 單元測試
- 整合測試
- 驗證和校驗
- 效能測試
- 可用性測試
- 資源耗盡、錯誤和恢復
6,文件和註釋
關於文件方面,很重要,但是經常會發現文件跟不上程式碼節奏,可以將程式碼生成文件。另外就是程式碼註釋,註釋也經常跟不上程式碼節奏。因此需要注意文件和註釋的編寫、及時更新等
五,其他零散經驗
-
物件屬性的讀寫不要直接暴露欄位,應該用方法封裝,方便未來調整,也能夠保持一致性
-
檢查每一個可能的錯誤,尤其是意料之外的錯誤是一種良好的實踐。
-
通過斷言來檢測輸入引數,在c、c++中是常用的優雅姿勢,但是不要用斷言去處理真正的錯誤流程
-
後設資料的設計