一.軟體構造的檢視和質量分析
1.軟體系統構成的三個維度:
按階段劃分:構造時/執行時檢視;
按動態性劃分:時刻/階段檢視;
按構造物件的層次劃分:程式碼/構件檢視。
2.軟體構造多維檢視:
Moment維度關注程式在某一時刻的表現,而Period關注的是程式在一段時間內的表現;Build-time維度關注程式還未被投入執行,編碼階段的表現,而Run-time維度更關注於程式執行時的表現。
(1)Build-time:構造程式碼的過程,程式碼分為邏輯結構和物理結構。
Moment,code-level view:基於詞彙的半結構化原始碼,AST(徹底結構化,將原始碼變成一棵樹,對樹的修改等價於對原始碼的修改)
Period,code-level view:程式碼變化,被定義為在版本迭代中程式碼內容的的增刪改查。
Moment,component-level view:原始檔的組織方式:package(包),library(庫),包括別人提供的庫和你自己積累的庫。
尋找庫的命令:javac -classpath ./lib/*.jar
靜態連結:發生在構造階段,庫被拷貝成程式碼,執行時無需提供庫檔案。
Period,component-level:Version Control System (VCI),版本更新。
(2)Run-time:執行時,程式被載入記憶體,開始執行。
程式碼層面:邏輯實體在記憶體中如何實現?
構建層面:物理實體在物理硬體環境中如何呈現?
動態連結:庫檔案不會在build階段被加入可執行軟體,僅僅做出標記;程式執行時,根據標記裝載庫到記憶體;釋出軟體時,記得將程式所依賴的所有庫都複製給使用者。
分散式執行程式態:需要多個執行程式,分別部署於計算機的多個物理環境。
Moment,code-level view:程式碼快照圖:描述程式執行時記憶體變數層面的狀態(debugger)。
Period,code-level view:執行跟蹤:用紀錄檔記錄程式執行的呼叫次序。
Moment,component-level view:硬體部署圖。
Period,component-level:系統層面的事件紀錄檔。
3.軟體構造:不同檢視的轉換
①從無到寫出程式碼,就進入了Build-time維度,開始只是單個的沒有任何聯絡的程式碼檔案,所以是在moment+Code-level維度;
②此時隨著時間的推移,程式碼刪刪改改,就屬於Period+Code-level了,而程式碼越寫越多成為了一個包,甚至形成了一個庫,於是就屬於moment+Component-level維度了;
③但是隨著時間的推移,庫檔案由於需求的變化發生了變化,所以就屬於Period+Component-level;
④程式碼寫好了,投入執行,進入Run-time維度,觀察的如果是某一句程式碼的執行後結果,那就是moment+Code-level維度,但如果看的是程式碼執行的軌跡,那就是Period+Code-level維度,而如果看的是一個庫檔案的連線情況等,那就是moment+Component-level維度了;如果看的是執行緒或程序的執行過程,也就是通過紀錄檔等手段檢視一段時間內系統都做了什麼事情,那麼就是Period+Component-level了。
4.軟體系統質量評價標準
外部質量因素影響使用者,內部質量因素影響軟體本身和它的開發者。
外部質量的因素:
(1)正確性:按照預先定義的規範執行,是最重要的質量指標。
防禦性程式設計:在寫程式的時候就保證正確性。
形式化方法:通過形式化驗證發現問題。
(2)健壯性:對正確性的補充,出現規約定義之外的事情時,軟體要做出恰當的反應。
Spec範圍越大,規約定義越好。
(3)可延伸性:對軟體的規約修改的容易程度。規模越大,擴充套件起來越不容易。
簡約主義設計和分離主義設計。
(4)可複用性:一次開發,多次使用;發現共性。
(5)相容性:不同的檔案是否能夠相互容易的整合。
保持設計的統一性,即制定標準化。
(6)效能:需要與其他特性進行結合。過度優化可能導致軟體不再具有其他特性。
(7)可移植性:軟體可方便的在不同的技術環境之間移植。
(8)易用性:容易安裝,監控的軟體。可以給使用者提供詳細的指南。
(9)功能性:指系統提供的可能性範圍。增加功能需要其他小屬性不增加範圍。
(10)及時性以及可驗證性,完整性,可修復性和經濟性等。
內部質量的因素:程式碼的耦合度,內聚度(LOC)
折中處理:
(1)正確的軟體開發過程中,開發者應該將不同質量因素之間如何做出折中的設計決策和標準明確的寫下來;
(2)當某一項滿足的足夠好的時候有可能其他項的表現極差,此時需要做權衡,使得各部分的表現都較好,在某些特定要求下也可以放棄優化其他項而做到某一項的極致;
(3)雖然需要折中,但正確性絕不能與其他質量因素折中。
最重要的質量因素:
Correctness and robustness:reliability
Extendibility and reusability:modularity
Correctness:封裝、去中心化
Robustness:封裝、錯誤處理
Extendibility:封裝、資訊隱藏
Reusability:模組化、元件、模型、模式
Compatibility:標準化模組和介面
Portability:資訊隱藏、抽象
5.五個關鍵的質量指標:
Elegant and beautiful code:程式碼要容易理解,通過統一變數/方法的命名標準、程式碼的風格、註釋、包組織結構、必要時重構程式碼等方式讓程式碼儘可能的容易理解。
Design for/with reuse:ADT/OOP、介面、繼承(Overload、Override)、多型、泛型、框架等技術可用於提高程式碼的可複用性。
Low complexity:當複雜度較低的時候,程式碼就容易被擴充套件新的功能,所以要高內聚低耦合,遵從SOLID原則、OO設計模式、使用VCS控制程式碼版。
Robustness and correctness:使用測試驅動的開發、例外處理、Assertion機制、防禦式程式設計等技術保證程式的健壯性和正確性。
Performance and efficiency:使用設計模式、並行/多執行緒等技術提升效能。
二.軟體測試和測試優先的程式設計
認可「測試」的價值,搞清楚「測試優先」的哲理;
學會用等價劃分和邊界值分析方法為模組設計測試用例;
可用工具度量一組測試用例對程式碼的覆蓋度;
各種各樣的測試都有初步瞭解。
1.測試:在規定的條件下對程式進行操作,以發現程式錯誤,衡量軟體品質,並對其是否能滿足設計要求進行評估的過程。
(1)沒有最好的測試方法,所有測試方法都有缺陷。
(2)測試跟其他活動的目標相反:破壞、證錯、「負能量」,即我們希望發現「錯誤」。
測試種類:單元測試,整合測試,系統測試,迴歸測試(後面測試之後再測一遍前面的測試)等。
白盒測試:對程式內部程式碼結構測試。
黑箱測試:對程式外部表現出來的行為的測試。
2.測試用例 = 輸入+執行條件+結果
最好的測試用例:能發現錯誤,不冗餘,有最佳特性,不復雜也不簡單。
3.測試優先的程式設計
先寫spec,再寫符合spec的測試用例,寫程式碼執行測試,有問題再改,再執行直到通過測試用例。
spec:包含函數引數,其他變數,返回值以及程式碼中方法的解釋。
先寫測試會節省大量的時間。需求也可以被轉換成特定的測試用例,然後更新軟體。
4.單元測試:針對軟體的最小單元模型開展測試,隔離各個模組,容易定位錯誤和偵錯。
可以針對單元測試建立驅動(接受測試用例資料並傳給元件)和樁(替換元件從屬的模組),這樣可以對任何單獨輸入傳給測試程式進行測試。
5.整合測試:Junit
斷言方法:AssertEquals,AssertTrue,AssertFalse(AssertThat不好用)
6.黑箱測試:檢查程式碼功能,不關心內部細節。
用盡可能小的測試儘快執行,並儘可能快的發現錯誤。
(1)等價類劃分:將被測函數的輸入劃分為等價類,從等價類中匯出測試用例。
針對每個輸入資料需要滿足的約束條件劃分等價類。
每個等價類代表對輸入約束加以滿足/違反的有效/無效資料的集合。
假設:相似的輸入將展現相似的行為,所以從每個等價類中選一個測試樣例即可。
(2)邊界值分析方法:對等價類劃分方法的補充。
大量錯誤發生在輸入值的邊界,可能是邊界突變或者邊界條件特殊。
解決方法:把邊界值單獨作為等價類中的一個類。
兩種覆蓋原則:
笛卡爾積:全覆蓋,多個劃分維度的多個取值組合起來,每組合至少一個樣例。
只覆蓋每個取值:每個組合最少被覆蓋一次,最多不超過5個。
前者完備,但用例數量多,代價高;後者代價低用例少,但覆蓋度不一定高。
7.白盒測試:考慮實現細節,根據程式執行路徑設計測試用例,一般較早執行。
獨立路徑測試:對程式所有執行路徑進行等價類劃分,找出有代表性的最小路徑,設計測試用例,保證每個路徑至少被覆蓋一次。
8.程式碼覆蓋度:已有的測試樣例有多大程度覆蓋了被測程式。
分為函數覆蓋,語句覆蓋,分支覆蓋,條件覆蓋,路徑覆蓋。
測試效果以及測試難度:路徑覆蓋>分支覆蓋>語句覆蓋。
9.自動測試和迴歸測試:
自動測試:自動呼叫被測函數,自動判定測試結果,自動計算覆蓋度。
迴歸測試:一旦程式被修改,重新執行之前的所有測試。
一旦發現bug,寫一個可重現此bug的測試用例,並將其加入測試庫,達到自動化迴歸測試的結果。
10.編寫你的測試策略:
測試策略(根據什麼設計測試用例)需要在程式中顯示記錄下來。
在程式碼評審過程中,其他人可以理解你的測試,並評價你的測試是否充分。
三.軟體構造過程和設定管理
1. Software Development Lifecycle(SDLC):軟體發展生命週期
2. Traditional Software Process Models
兩種基本模式:線性過程,迭代過程。
模式:瀑布過程,增量過程,V字模型,原型過程,螺旋模型。
選擇模式的依據:使用者參與度(適應變化的能力),開發效率/管理複雜度,軟體質量。
(1)瀑布過程:線性推進,階段劃分清楚,整體推進,無迭代,管理簡單,無法適應需求增加/變化。
(2)增量過程:線性推進,增量式(多個瀑布序列執行),無迭代,比較容易適應需求增加。
(3)V字模型:瀑布過程的擴充套件,對模型的結果進行驗證與確認。
(4)原型過程:在原型上持續不斷的迭代,發現使用者變化的需求。
迭代:開發出來後由使用者試用/試評,發現問題反饋給開發者,開發者修改原有的實現,繼續交給使用者審評。迴圈往復這個過程直到使用者滿意為止。時間代價高,但開發質量也高。
(5)螺旋模型:多輪迭代基本遵循瀑布模式,每輪迭代有明確的目標,遵循原型過程,進行嚴格的風險分析,方可進行下一輪迭代。
3. Agile Development
敏捷開發:通過快速迭代和小規模的持續改進,以快速適應變化。
敏捷開發=增量+迭代,每次迭代處理一個小規模增量。
極限的使用者參與/小步驟迭代/確認與驗證。
4. Software Configuration Management (SCM) and Version Control System (VCS)
SCM:軟體設定管理:追蹤和控制軟體的變化。
軟體設定項:軟體中發生變化的基本單元(比如檔案)。
基線:軟體持續變化過程中的穩定時刻(比如對外發布的版本)。
(1)代表多個原始碼檔案的一組版本。
(2)代表檔案的一個穩定狀態。基線提升:檔案大修改的更新。
CMDB:設定管理資料庫,儲存軟體的各設定項隨時間發生變化的資訊+基線。
VCS:版本控制系統
(1)本地VCS:無法共用和共同作業,儲存於開發者本地機器。
(2)集中式VCS:倉庫儲存於獨立的伺服器,支援多開發者之間的共同作業。
(3)分散式VCS:倉庫儲存於獨立的伺服器+原生的伺服器。
5. Git as an example of SCM tool
組成部分:原生的CMDB,工作目錄(本地檔案系統),暫存區(隔離工作目錄與git倉庫)。狀態包括已修改,已暫存,已提交。
物件圖:git專案的歷史,是一個有向無環圖。
本地庫:使用git commit提交;遠端庫:使用 git push 提交,使用 git pull 下載。
6. General process of software construction
(1)Programming(coding)
從用途上劃分:程式語言(C,C++,Python,Java),建模語言(UML),設定語言(XML),構建語言(XML)。
從形態上劃分:基於語言學的構造語言,基於數學的形式化構造語言,基於圖形的視覺化構造語言。
Integrated development environment (IDE):整合式開發環境。
包含:原始碼編輯器,智慧程式碼補全工具,程式碼重構工具;檔案管理;庫管理;軟體邏輯實體視覺化;圖形化使用者介面構造器;編譯器,直譯器;自動化build工具;版本控制系統;外部第三方工具等。
(2)Review and static code analysis(程式碼分析/評審)
結對程式設計,走查,正式評審會議,自動化評審。
(3)Dynamic code analysis / profiling
動態分析:要執行程式並觀察現象,收集資料,分析不足;對程式碼的執行時狀態和效能進行度量,發現程式碼中的潛在問題。
(4)Debugging and Testing
測試:發現程式是否有錯誤。偵錯:定位錯誤,發現錯誤根源。
(5)Refactoring
重構:在不改變功能的前提下優化程式碼。
7.build過程:Validate Þ Compile Þ Link Þ Test Þ Package ÞInstall ÞDeploy