丁哥對如何做好軟件開發工作的思考(共識,復雜度,審查,重構,測試)
1??????共識
其實我感覺共識,并不是很復雜的東西。比如說一條船沉沒了,船上的所有的人都無法幸免。對于我們做項目也是一樣的。不是爭誰高誰低。還是想著一起把這個事情做好。
那么這個地方就有一個問題,怎么才算可以把事情做好?拿主意的那個人必須是個通才,?至少在面對當前這個問題的時候,能夠做出非常全面的把握。然后把想法兒說出來以后大家感覺可行,大家再去執行。
1.1????舉個例子:時間寶貴,不容浪費
人上100,形形色色。
打個比方說吧,你請一幫人來家里做客。大家都玩的興高采烈,感覺客廳也非常寬敞,非常明亮,非常干凈,外面的景色也很舒服。但偏偏有人喜歡跑到廁所里去看,然后拿廁所的狀況跟客廳里的狀況進行比較,說你的廁所沒有客廳干凈。
這個就沒法談了。根本就不在一個層面上,有的人喜歡去查看黑暗,有的人喜歡崇尚光明,這個是價值觀的問題。
有人就是關注那些黑暗的東西,讓自己不痛快,然后讓別人也不痛快。碰上這種事兒,實在太鬧心了,干脆,眼不見心不煩。惹不起,躲得起。
畢竟時間寶貴,有那么多有用的事情要做呢。
1.2????每一個軟件產品都必須要有一個靈魂
我覺得每一個軟件產品都必須要有一個靈魂。這個靈魂很多時候就來自于某個人。如果在軟件產品中缺少了這個靈魂,這個產品的高質量性就會大打折扣。
一個產品的理想開發狀況是這個人制定方向傳達指令,讓其他的人去實施去完成,如果其他人不懂他的意思,那么這個人就得親自上陣,把這個任務做出來,作為一個示范。
隨后大家可能會恍然大悟,原來是這么做。那一步步的去做自己螺絲釘的任務就可以了。這樣對每個人來說都是非常舒服的過程。
這正如一輛火車,如果牽引裝置向四五個方向發力,那這輛火車基本上就走不動了。所以只能有一個行進方向。
這個思想的靈魂可以是一個大的產品,也可以是這個大產品的一個功能。
根據不同的任務呢,可能有不同的靈魂把握者,一旦有個人能把握這個靈魂方向,我們團隊中的所有的人都向他看齊,他要什么幫助我們就提供,根本就不用操心其他的事情,讓這個人去把控就好了,這樣子事情就比較好辦。
如果做一件事情的時候,一直處在七嘴八舌的狀態,沒有一個統一的方向,任何事情都很難做成。
2??????軟件開發復雜度
軟件開發的難度跟硬件開發最大的區別就是軟件開發的不可預知性,有時候碰上很多問題,我們無法用以前的經驗來框制。
2.1????代碼相關的復雜度的控制
這個時候沒有別的辦法只能披荊斬棘先從開始到結尾畫一條線,一直找到一個可行的方案。
一條線代表一個功能需求的解決。接下來再解決其他的功能需求,那么這樣整個項目就會有很多很多條近乎平行的功能需求線,這樣復雜度就是線性的增長。
這是我個人能夠看得到的,在架構代碼和模塊代碼方面最理想的情況。
2.2????系統部署相關的復雜度的控制
其次就是系統部署和運行方面。越簡單越好。簡單到一步。一步完成部署,比如點擊一個按鈕,運行一條命令。開發調試部分也是越簡單越好。每個小模塊兒是一步,多個模塊兒集合在一起的系統調試部署也是一步。
2.3????新需求相關的復雜度的控制
我以前就碰上過這樣的問題。那是一個在線教育平臺,里面的功能有用戶管理(學生老師校長代理商),班級管理,課程管理,視頻直播聊天室,考試系統,試卷評估,課程購買等等。后來老板要求加的一個功能是實時上課提醒,上課前一小時提醒,上課前24小時提醒,提醒方式有短信和郵件。
前面這套系統已經跑了一段時間了,后來加的這個功能跟前面的系統有關聯,但是關聯度不大。主要是后端的工作,而前邊應用的后端主要是提供API的功能。這個提醒的功能,主要是后端的服務輪詢功能。如果在以前系統的后端上增加功能的話,勢必會增加系統的復雜度和不穩定性。所以我采用的方案是單寫一套系統,包含前端和后端,共享前套系統的數據庫。
這樣在不影響前套系統正常運行的情況下,也解決了新需求。?我們做軟件系統就是這樣,做的東西越多,經驗就越豐富,就越能夠對整個系統做出更全面的把握。
對,正如大家所想的,這就是微服務架構的一個具體實現。
3? ? ?代碼審查
對于代碼的修改,我們主要關注如下幾點:
3.1????代碼的復雜度是不是降到了最低?
先說一下代碼設計的復雜度。
代碼設計的復雜度應該是收斂的,而不應該是發散的。也就是說在起始點復雜度為10的話,那到終止點的時候復雜度不能超過10。
如果終止點的復雜度超過了起始點的復雜度,committer?需要對代碼的整個設計結構進行審視。
再說一下代碼行的復雜度。
有人為了減少修改代碼的行數,在一行代碼中寫上多個函數調用。比如通過在函數的參數中傳入另外的函數。這種編寫代碼的方式會提高單行代碼的復雜度,我們應該把參數中的函數調用提到前面去,先把參數算出來,然后把計算出來的參數值再傳入到函數調用中。
這是大道至簡,好的代碼要返璞歸真,每個人都能看懂。
3.2????如果有重復性的代碼,這種代碼的重復是不是必要的?
比方說,減少重復性的代碼會增加復雜度的話,我們一定要避免增加復雜度而允許這些代碼的重復。
這是兩害相權取其輕。
3.3????驗證是必要的。
一定要創造條件跑一跑所審查的代碼。比較簡易的方式就是寫好充足的單元測試和集成測試。
這是以客觀結果為前提,不要盲目相信自己的主觀判斷。
4??????軟件編譯與調試
4.1????增量編譯缺乏
現在編譯這一塊,大部分程序員最大的問題就是無法做增量編譯。這個主要是因為資源的問題,虛擬機,?docker都不夠用的。每次流水線觸發以后,都會把以前已經編譯過的內容全部刪除。這樣每次編譯都是在做全量編譯,就是你改一行代碼也是這樣。
跟很多人聊過,說這個問題是一個長期的問題。
4.2????調試難度大
還有的教練說,現在很多程序員寫完代碼以后,直接在實際的產品環境下進行調試。這個也是比較恐怖的,開發效率肯定高不起來。開發環境應該特別舒適,調試修改代碼,應該非常快。
這一步開始的時候沒有做,現在項目規模大起來以后呢,再做就顯得有點困難。
從各個教練反映的情況看,很多項目都是這樣的情況。
這也就涉及到一個問題,如何很好的做重構,重構絕不僅僅是代碼層級的。
5??????軟件重構
關于老產品整改的問題。如果只是縫縫補補的話,可能起不到化繁為簡的目的。其實做類似這種工作的話,有一個比較可行的方案。就是把現有的產品當做一個成型系統也就是現有運行的產品,不要做大的改動,頂多就是修改bug。
然后以這些成型的系統為基準,去寫新的系統。相當于參照一個大的白盒就寫一個小的白盒,這樣新的小的白盒質量上肯定比大的白盒性能上要有優勢。因為相當于開卷考試。
這樣子按部就班去做的話,就會比較靠譜。
有朋友會說上面的做法是重寫,字面意義上沒錯的。
5.1????重構還是重寫?
實際上不矛盾。區別就是重構的方式應該從下往上還是從上往下。比如說我們現在大部分的重構都理解為從下往上來做。也就是感覺這個文件里頭有壞代碼的味道,然后就改這個文件,這樣做是沒有問題的。
比如現在有些教練遇到的問題,就是發現上下文不是很清晰,這個代碼為什么要這么寫?為什么一個文件有1萬行或者3萬行,這個來龍去脈不是很清楚。
這個時候可能就需要從整個子模塊來進行一個自上而下的分析。梳理出這個子模塊的功能需求是怎樣的,需要有多少個公共接口?內部公共接口的實現方式是不是應該像目前這樣的?
一個文件能夠寫成1萬行或者3萬行,肯定是有一定歷史原因的,絕大程度是由于全局把握的編程能力不夠造成的。
像這種情況,如果從這個文件本身去做重構的話,難度非常之大,但是如果從上往下,從模塊的整個設計角度來做重構的話,可能就容易一些。
5.2????具體的參考步驟
這個時候需要做的具體步驟可以參考如下:
1.根據功能需求定義公共接口。
2.根據公共接口寫出測試案例代碼。
3.這個時候可以按照測試驅動開發的理念去填充代碼。
4.代碼可以從現有的代碼中抽取出來。
5.在抽取的過程中進行整理重構。
這樣,這個子模塊完成以后,就可以嘗試去替代現有的子模塊,看看能不能在整個系統中安全的運行。
這個是我理解的,從子模塊兒角度來看待一個重構過程。
5.3????依此類推
對于整個系統來說,我們又可以分成很多個子模塊。然后又可以對各個子模塊各個擊破,最終完成對整個系統的重構。
如果一開始對整個系統進行重構的話,也是可以從自上而下的角度來看的。
比如說開始的時候先把所有的子模塊看成一些占位符,假定他們已經完成他們的接口了。那對于整個系統來說,它本身就是一個子模塊,屬于提綱挈領的那個模塊。
這個過程,從字面意義上可以理解成重寫,實際上,它也是一個重構的過程,因為我們肯定會重用這個系統本身的一些現有代碼和現有的邏輯。
6??????軟件測試
軟件測試部分,我說說我對單元測試,集成測試,測試案例選取以及工作量問題的看法。
6.1????單元測試
說一下單元測試部分的思考。
關于測試案例的編寫,主要是有兩個方面,一個是代碼物理行的覆蓋率,一個是代碼邏輯的覆蓋率。
物理行的覆蓋率相對來說比較簡單,有工具可以直接報出來。經常說的,100%的覆蓋率,85%以上的覆蓋率,都是物理行的覆蓋率。
代碼邏輯的覆蓋率就相對隱蔽一些。
打個比方說一個函數里面有兩個條件判斷分支。每個分支有兩種條件: if-else。
要做到物理行的100%覆蓋,我們可以這樣做到:?寫兩個測試案例。一個是if同時成立,另一個是兩個else同時成立。
要做到代碼邏輯的100%覆蓋,我們需要創建4個測試案例。包括上面的兩個測試案例以外,還要加上另外兩個if else交叉的情況。
這也就解釋了為什么100%的物理行覆蓋率,無法杜絕bug的產生。
因為沒有做到代碼邏輯的100%覆蓋。
從上面的例子可以看出,如果做到代碼邏輯的100%覆蓋,工作量比較大。但是如果沒有集成測試做配合的話,這一部分是必須要做的。
6.2????集成測試
再說一下集成測試的思考。
針對上面的代碼邏輯覆蓋率的問題,一個折中的方案就是使用集成測試來結合物理行的代碼覆蓋率。
集成測試主要是用戶的需求功能單元。也就是通過某個測試案例,可以集中地反映在指定情況下用戶是如何獲得對應功能的。這一部分是模擬真實的用戶使用場景。
6.3????測試案例選取
關于測試案例選取的思考。
測試案例的選取主要有如下方面,一是邊界值的指定,用于測試一些不常用,但有可能會出現的用戶輸入,二是常規值的制定,這一部分主要是演示用戶在大多數情況下所提供輸入的處理情況。
6.4????測試代碼工作量
關于測試代碼工作量問題的思考。
一般情況下我們都承認沒有測試的代碼是不完整的代碼。因此測試代碼無論如何都是要寫的。
那么如何寫測試代碼才能最省時省力呢?
我的體會是在模塊或者項目編寫的時候,同時配置好測試框架。先針對一些成型的代碼進行測試案例編寫作為示范。如果代碼還沒有成型就寫測試案例的話,會帶來非常不必要的測試代碼修改工作量。所以這里有一個時機把握的問題。
除了最開始的測試框架代碼部分,一般來說大面積的測試案例代碼的添加是在項目已經成型的時候才開始的。案例代碼除非特別情況,不要有任何條件判斷。基本上都是平鋪直敘的一條直線的邏輯。測試案例代碼,由于其特殊性,可能存在很多重復的現象,這個都不是問題。
軟件開發 架構設計 單元測試
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。