2012年12月25日 星期二

大道至簡 - 軟體工程實踐者的思想 內容整理

客戶不會用C,難道就會用UML嗎?客戶是因為他認為你理解了他們的需求,而在「需求確認書」上簽字,而不是因為你的UML畫的是否精確。

需求階段:
1. 確定了專案的實際目標,以及遠期的方向
2. 設計需求條目
我們開始在網路上查看相關的軟體系統的特徵以抽取客戶所關注的內容;瞭解該客戶的公司、經營理念、組織結構形式以及工作模式;瞭解同類公司的成功經驗和優秀的管理模式,以及客戶的競爭對手在做什麼和在關心什麼。經過上述的步驟,可以總結出產生需求的資訊點為:
1客戶在公司層面的外在表現、內部機制和運營管理手段。
2客戶在專案中既已明確的需求和可能發生的需求,以及客戶圍繞其公司行為(和方向)所提出的需求。

專案的歷史資料:
History是為整個專案而記錄的。一些參考的記錄內容有:
l需求階段:與誰聯繫,聯繫方式、過程、結果以及由此引發的需求或變更;
l設計階段:如何進行設計、最初的構架、各個階段的框架變化、因需求變更導致專案結構上的變化(有助於瞭解構架的可擴充性)
l開發階段:每一種技術選型的過程、每一種開發技巧的細節和相關文檔、摘引的每一段代碼、演算法、開發包、元件庫的出處和評測;程式單元的測試框架;每一個設計和構架變更所導致的影響;
l測試階段:還記得測試用例和測試報告嗎?那是最好的history之一。
另一件最重要的事,是記得在每一筆記錄後寫下時間和你的名字。

由於軟體工程的興起,工程被當成了藉口,掩蓋了我們做事的真正目的:實現。因此,我們在一個項目中常常聽到說工程要這樣做,或者工程要那樣做,而絕少聽到專案要求這樣做或者客戶的本意是那樣的

從成本的角度思考專案:
1. 不計成本的專案計畫不會得到經營者的支持;
2. 毫無目的地消耗成本是項目中的慢性毒藥;
3. 最致命的風險是成本的枯竭

成本因素包括:時間、人力、資金和客戶成本(客戶的數量及耐心)。


語言只是工具:
方法:是對既有行為的歸納總結。
過程(Process):過程伴生工程而出現。過程解決的是工程中角色間的關系問題。
工程:
組織:

軟體工程理論體系:
軟體工程三要素:流程(process)、方法(methods)和工具(tools)

2012年12月13日 星期四

軟體測試實踐:測試web MSN - 內容整理


測試用例是軟體測試的最小單位,是測試工程師的子彈。對軟體測試入門者來說,測試用例是第一位的,有了好的測試用例你就能發現別人沒有發現的bug。只有當你具有良好的、開放型的測試思維,你才能得到優秀的測試用例。

1. 我們要熟悉產品的需求規格說明書(軟件需求是測試的標準與範圍)。若需求不具體或者需求文檔過於簡略,這時測試應該去推動需求的制定。
a. 測試以需求規格說明書為基礎,但同時也要去發現它裡面的錯誤,推動需求的完善。
b. 測試工作是貫穿於整個軟體開發過程的,越早發現錯誤,修正這個錯誤的成本就越小。

2. 測試工程師要瞭解專案的整體安排(即專案的時程)
a. 測試是無窮盡的vs.實際測試是有限的 <= 測試的經濟面(時間、成本等限制)

3.預備好測試環境
a. 工作環境與測試環境要分開
b. 功能測試環境和性能測試環境要分開
c. 提前準備好硬體(伺服器、客戶端、網路設備)和軟體(作業系統、瀏覽器)
d. 測試支援平台也是測試環境的一部分。測試支援平台:一套測試的自動化辦功系統,例如測試用例管理系統、bug管理系統、測試報告產生系統等。
e. 把搭建測試環境時遇到的問題和相應的解決辦法記錄下來,形成文字,以備之後查詢。

<<測試常用專有名詞>>
黑盒測試:只知道功能的測試。 <= 功能測試
白盒測試:只知道程式碼結構的測試。 <= 單元測試
灰盒測試:知道功能也知道程式碼結構。 <= 執行某個功能中所有的單元測試??
功能測試:對產品的功能做測試。
性能測試:一般是檢驗在普通場景下產品的性能。
壓力測試:檢驗產品在極端條件下的性能(極端條件下的性能測試)
回歸測試:
1. 在開發人員修復一個bug後,去驗證這個修改是否正確所做的測試。
2. 在軟體開發後期,選擇否依部分重要的測試用例去驗證產品的某一個版本工作是否正常。
單元測試:函數級別的測試,一般都由開發人員來完成。
整合測試:將各模組代碼整合到一起,實現一個或一些功能。驗證代碼的整合是否正確。
系統測試:針對子系統做測試,也就是大一點的整合測試。
邊界值:是確定合法輸入與非法輸入的判斷條件(通常會在邊界值的左右在各選一個值來測試,也就是每一個邊界值得測試會有邊界左值、邊界值、邊界右值,三種值)
等價類:將涵意或影響相似的值分在同一類中,並為每一個類選一個代表即可。例如,在0~100中,如果以偶數奇數來分類的話,就是兩類,各選一個奇數和偶數來測試就可以了。
里程碑:軟體專案一般可分為多個階段,每做完一個階段,我們就說實現了或達到一個里程碑。
評審(Review)
bug重現(再現)不能重現的bug,它的嚴重性一般都不會很高。
BVT(Build Verification Testing)測試:在一個新版本出來後,先要做一個最簡單的測試,保證這個版本的基本功能工作正常。亦稱冒煙(煙霧)測試。
自動化測試:透過測試工具來實現自動運行的測試。

UI測試的關注點:
1.      界面元素要符合通用規範
2.      窗口能在不同的尺寸下顯示正常
3.      支持用戶不同的作業系統的設置
4.      支持用戶使用不同的解析度
5.      處理好焦點問題
6.      作語法檢查,避免文字錯誤
7.      對不方便人群的支持
8.      支持快捷建

測試計劃的關注點:
1.      測試時間的安排
2.      測試人員的安排及任務分配
3.      測試資源的安排,包括需要的軟體、硬體
4.      自動化測試的安排
5.      測試風險的分析以及對策
                                                                                                          
<<設計測試用例的一些思維>>
1. 一個測試用例只負責一個細小的使用場景,越細越好。
2. 軟體的基本數據也在測試範圍之內。
3. 檢查默認值是一種很好的測試思想和習慣。
4. 使用"排列組合"的方式編寫測試用例(測試是無窮盡的vs.實際測試是有限的)
5. 輸入框為空是一種特殊值。
6. 做軟體測試時,總有一些"附屬項"需要驗證。
7. 測試用例要有覆蓋到極限值(邊界值測試)的情況。
8. 登入驗證在安全性方面要多多考慮。
9. 懷疑一切,驗證一切。
10. 網頁得標題欄也是需要測試的。
11. 考慮一個測試點時,需更多的從動態的角度出發。
12. 快捷鍵的驗證。
13. 下拉式表單的每一個子項都要測試。
14. 即便功能類似,用例還是要分開寫。
15. 幫助文件的內容也是需要測試的。
16. 在測試一項複雜的功能時,可嘗試使用Bottom-Up的測試邏輯。
17. 不要忽視功能點,他們也需要被測試。
18. 所有不正確的需求、設計和程序錯誤都可以報告為bug,讓相關人員去修正。
19. 測試員的眼界要越過被測試的對象,可以考慮與之相互通信的兄弟軟體之間的協作。
20. 工具攔中的每項設置都需要遍歷;設置之間的組合可以隨機來做,不必遍歷。
21. 測試人員應站在最終用戶的角度上看問題(UX)。例如,輸入框得到默認的輸入焦點;快捷鍵等。
22. 在每一個軟體的需求之外,還存在著一些公理,不言自明的。需求規格書不可能面面俱到,測試員可以根據這些公理來擴展需求。
23. 不以機率小而不為。
24. 有些功能可能是界面上沒有入口、看似沒有的,但是在某些條件下卻會出現。
25. 盡量對可能交互或產生影響的產品都有所了解,這樣在考慮問題的時候思路會更開闊。
26. 再考慮複雜場景前,可先以基本場景為切入點,接著列一些提綱,然後再根據一個個的提綱去思考、去突破。
27. 數據不是靜止的,我們需要使用動態的思維方式來考慮問題。
28. 瞭解同事的工作,就能夠做一些跨模組的思考,把測試做得更深入。並避免報告重複的bug
29. 面對一個窗口的時候,從變量入手做測試是一個好的思路。既然它是變量,變成什麼就都有可能。
30. 除了琢磨模組自身內部包含的功能外,我們還要把它和其他相關模組放在一起測試。
31. 有效數據和無效數據都是需要驗證的(有時候他們被稱為合法的和非合法的數據),測試中需要正反兩方面的用例。
32. 拆解功能的流程,然後逐一分析測試,用以避免遺漏掉很多問題。
33. 狹義上的UI測試:專指對操作介面的非功能性的測試。
34. 文檔保持更新,測試保持更新,保持一種在動態前進的心理預期。任何文檔不可能是一勞永逸的。

2012年11月21日 星期三

活著~~


活著是由大陸的作家 余華 所著。
本書主要在講述主人翁福貴的一生。他如何從田僑仔,然後敗光家產,接著被抓去當兵,
後來又怎樣回到家中,直到最後剩下的孤單一人。

在敗光家產後,他想著如何養活自己母親和妻兒,於是向地主租了五畝田地來耕作。
在被抓去打國共戰爭時,他想著如何活著回家,於是在槍林彈雨中搶著小米及大餅。
在中國解放後,回到家的他,想著如何在超英趕美的大躍進中取得食物養活一家人。
在家人一個一個經他手落土於西村後,最後想著的只是如何單純的讓自己不會餓死。

這樣簡單、深刻的描述了福貴這一個小人物的一生,雖沒有引人入勝的精采情節,
但卻讓人愈讀愈無法釋手。

花了幾天時間看完後,在看完的當下讓我想起了雷洛探長最後在劇末問家僕的問題。
「人這麼辛苦是為了什麼?」
「為了吃飯。」

2012年11月16日 星期五

粗心可以殺死一條狗~~


這幾天發生一個事件,因為我的不細心及不夠完整的思維,讓我所屬的開發團隊,遭到二線人員的質疑,說我們的程式沒有quality。這讓我對我的團隊感到很抱歉,尤其是我的leader,因為他是首先第一個被質詢的人。

這件事情是這樣的,我們從B系統移植一個X功能到A系統中,負責人就是我。我在移植的過程中犯了一些過失:

1. 系統中提示文字的顯示迷思
因為A系統和B系統處理顯示的文字是使用不同的動態連結檔,剛好A系統的某個設定有問題,使得A系統會連結到錯誤資料夾中的檔案,也連帶讓X功能可能存在顯示不正常的機會。只是剛好我的電腦在那個錯誤的資料夾中,存在了對的檔案,所以移植到A系統的X功能,在我的電腦可以顯示正常,但測試人員的電腦就出現問題了。
è 我應該更細心的檢查程式碼,發現他們是使用不同的DLL,並檢查出A系統呼叫到錯誤資料夾中的檔案。這樣我就可以修改它,使其可以永遠顯示正常的文字。

2. 忽視一個重要錯誤的不應該
因為我的開發環境是Win7,而使用的開發語言是VB6,所以常常在發生由Win7建構出的程式,在執行時會造成一些錯誤。而我卻把這次的一個錯誤,誤認為是由於Win7所建構造成的,結果最後被發現其實是程式的bug
è 我應該要用另一台XP電腦來建構這個程式,然後再加以測試。這樣就會發現到這個問題並不是由於win7的建構環境所造成,而是我乎叫某個函式的先後順序有誤所產生。

3. 忽視測試過程中每個數值變化的情況
在執行我想得到的測試案例時,我沒有注意到所有使用到的數值的變化,使得我沒有發現到,在寫入歷史紀錄時會誤用到預設的帳號,而不是真正當時在操作的使用者帳號。
è 我應該要更細心的查看每個數值得記錄與更動,只要稍微把每個資料都看過一遍,就一定會發現這個錯誤,但我沒有。

4. 思考到的使用案例不夠全面的後果
在測試的過程中我只著重在X功能本身的測試,沒有思考到與這個X功能有相關的其他功能。根據原本的設定,在X功能中設定某些資料後,啟動Y功能時,Y功能應該要讀取在X功能中設定的資料,並用這些資料來更新資料庫的數值。但因為我不夠全面的思維,沒有發現到Y功能這樣的行為沒有被啟動。
è 我應該更主動去瞭解X功能及與X功能相關的其他功能,並盡可能的找出這些功能的所有使用案例,如果可以依循使用案例來測試,這樣就可以避免掉產出半殘的X功能。

總結:
雖然大部分的問題,很多是由於我對於整個系統的架構和機制還不是很了解所造成,但這不應該作為藉口,因為現在負責的人是我。我應該要想辦法去瞭解,不過我卻沒有做到,只有簡單的測試一下,然後覺得看起來很OK應該沒問題了,這真的是要不得的想法。這些天來我也看了許多測試的書籍,發現上面我犯的許多錯誤,其實書中都有提到,也註明了這是許多測試人員會犯的通病,沒想到就真的發生在我身上了(雖然我是開發人員)。最後,這次的事件對我來說真的是一個很好的教訓,但也是一次很好的學習機會。希望這次的學習,可以讓我更加的成長,並在下次或將來開發時都能更加注意、更加細心地去思考及處理。

2012年11月11日 星期日

曾遇到的DB問題 (一)


三個跟DB相關的問題,兩個是我還在android時遇到的;一個則是在我開始寫VB6以後看到的。

()
當時是有一個ANR(Application Not Responding)issue,後來根據log發現是因為發生DB lock,結果造成等待DB等到發生了ANR。那為什麼會發生DB lock呢?我記得當時我跟一位同事看code看了很久,看起來好像都沒有問題,直到一直查到源頭,另一個同事寫的存取DBlibrary,終於讓我們發現了一個問題。原本library的設計概念是把存取DB的類別使用singleton模式來實作,但是卻沒有將建構子的存取權限設為private,使得在開發Provider時誤用new來實體化DBHelper


所以當多執行緒操作DB時,就可能發生new兩次實體的狀況。也就是說當A物件先使用DBHelper,然後B物件又使用DBHelper,接著就會發生DB lock。使得B物件無法使用DBHelper,於是他只好等待到天荒地老到發生ANR。發現了這個root cause後,我們便將建構子的存取權限設為private,並把要使用到DBHelper物件的程式碼,改為以getInstance來獲取實體,這個issue也就這樣解了。


()
第二個也是DB的問題,這個問題是在第一次使用該AP時才會發生的issue,而且還必須依照某一特定的步驟才會發生。問題是這樣的,有一個應用程式A,還有一個應用程式A的外掛程式B。當使用者還沒第一次執行過A之前,先使用了B就會發生B無法外掛到A的問題。這個問題很特殊,而且可能跟上面DB lock問題一起發生。我試了很久才終於找到這個issue的重覆產生步驟,因為它只會發生在A從來沒有執行過的情況下,而這個情況通常只會發生在剛刷完新ROM的機子中。

主要的原因是這樣的:
1. 在第一次執行A之前,A所需要用到的資料庫是完全不存在的(我想這應該只會發生在Android)
2. 目前實作的機制是將可以外掛到A的來源資料儲存在DB中。因此,資料庫在創建時必須自動加入A可以接受外掛的來源,否則外掛程式皆無法外掛到A之中。

A從沒被執行過,DB還沒產生出來時。在執行B的時候,B會透過一些機制來使用AProvider,接著A會發現沒有DB存在,然後開始create一個DB。當DB建好後,再透過一些機制將外掛來源寫進DB中。也就是說,這是一個兩步驟的動作,所以當A只做到第一個動作時,B便開始想外掛進A,然後就會出現A發現DB中並沒有B可作為外掛來源的資料,於是拒絕B的外掛,並造成B外掛失敗。這個問題簡單來說,其實是因為多執行緒的時間差造成的問題。最後的解法是,當A確定DB建好且外掛來源也已經寫進資料庫中時,再發送一個訊息給B,讓B再做一次外掛即可解決。