測試的哲學
11 | 12,196 |
最近手上的一個專案漸入高潮,各方人馬分頭進行的各模組也開始進入整合階段,引發一個有趣的議題。
系統被拆解成多個模組分工開發,但模組間有很密切的相關性。例如: 模組A寫入的資料,要變成模組B報表的來源;模組C修改的基本資料檔,會左右模組A寫入資料的邏輯,也影響模組B報表產出的結果。
為求開發速度,開發初期各模組團隊是各自獨立進行的,準備測試資料時,以各模組自己可以運作為目標。由於尚未跟其他相關模組整合(例如: 模組A寫入資料前,要先經過模組C驗證資料有效性,但模組C根本還沒寫好,所以就先寫一段假邏輯替代或索性跳過驗證),寫入資料庫的資料在完整性及合理性尚未達到系統最終要求。加上開發期間程式修修改改,程式錯誤時也塞入了一些邏輯不符的資料沒有清除。
可以想見,現階段資料庫裡的資料千奇百怪,模組B產生的報表自然一塌糊塗,明明依著系統規格書的邏輯寫,因資料不合理,就跑出讓人吐血的結果。最理想的狀況當然是要求所有資料得符合系統規範,不該是NULL的就不得留白,數字大小也必須落在合理範圍。但從實務面來說,這等同於將整合測試的部分工作提前,要求重整資料勢必要先中斷各模組開發人員的工作,停下來協調各模組以產生合理資料,這個停頓時間看來不會太短,將嚴重影響各組的既定時程規劃。
看來是一個兩難抉擇,所以變成了可以討論的話題。大家討論了一下,發現彼此看法不盡相同,形成了有趣的對照,也反映了不同的開發哲學。
有人贊成依原先計劃,待整合測試階段再驗證結果正確性。理由是這樣較不會破壞各組既有的時程規劃,搞亂大伙漸入佳境的工作節奏,系統的完成進度也較能符合預期。再者,及時有具體的成果(不論結果對錯)產出,對於"安定人心"也有很大的指標性意義。(不要小看這一點,有實戰經驗的人應該會同意"心理層面"因素對專案成敗的影響並不亞於時程、功能、效能等議題)
而我,或許是受了TDD(Test Driven Development)的荼毒,深信程式應該一開始就要做對(Do Right At First Time, DRAFT),錯誤愈遲發現、愈晚修正,代價將呈等比級數倍增。例如: 現在因為測試資料不正確,在寫第一支報表時無法檢視結果,未察覺某段邏輯不正確,那麼同樣的錯誤邏輯觀念就會被複製到第二支、第三支報表裡,待進入整合測試階段時才發現,就得回頭重新檢查修改所有的程式。
而從另一個角度來看,先略過正確性檢查的開發方式在時程上的表現雖較亮眼,時程到了"東西都有如期交出",但其正確性卻不被保證,也許整合測試後還要花上可觀的時間將程式結果修到正確。換句話說,"時程一如預期"可能只是假象,因為當初時程要求的一定是指某個時點應是交付"正確可用的程式",而非"看起來可以跑的程式"。當外界對程式品質失去信心,降低了對開發人員的信任度,對開發團隊而言,會是一項危機。話雖如此,老執著於測試正確性、開發進度停頓、大半天程式連影子都看不到的開發團隊,實在也高明不到哪裡去...
這番分析下來,兩種做法實在沒有明顯的優劣,頗像傳統測試哲學對決TDD的泰勢。TDD如果只有優點沒有缺點,早就變成大家奉行不渝的鐵律,事實上,TDD測試優先的做法,撰寫測試付出的額外成本十分可觀,時程不易壓縮且人力耗用大,嚇走了不少決策者與開發者。
大家面對這樣的情境時,會採取何種策略呢?
Comments
# by steve
我會先花一點點時間,做出一些"正確的假資料",簡單驗證一下各模組的正確性,先做初步的評估 如果看起來狀況都不錯,就繼續開發下去 如果發現有邏輯錯誤,而且可能有發散的跡象 就趕快回頭把問題修正完再往下走 又或者,把DataSource分開,各模組有自己的一組DB及table,減少互相干擾的機會 這可以透過一些手段,例如config檔或者甚至用hostname欺騙Developer的電腦來達到 既然切了模組了,作出正確的output是該模組的責任 各模組都以"別人送進來的資料都已經是正確的"為前提,製造出所需要的"正確的假資料"去進行開發,以及開發過程中的單元測試
# by Wizard
Oracle 的 Stored Procedure 無法傳回「表格式」的資料 能否請問一下, Oracle 的預存程序,並無法像 SQL Server、Sybase 等資料庫一樣, 直接傳回「表格式的資料」,如 DataTable、RecordSet, 像這樣的預存程序就不行 : SELECT col1, col2, col3 FROM table1; 那請問大大在開發 ASP.NET 或其他 ap 時,在處理 GridView 的「分頁」問題時, 有撰寫 Stored Procedure 去處理嗎? 因 ASP.NET GridView + DataSource 的特性,是每次使用者按「下一頁」時, 是整個資料表全部重撈,因此才有需要撰寫一支 Stored Procedure,去資料庫 做過濾,亦即只撈回該頁真正需要的資料筆數, 而非 ASP.NET 預設的行為 - 每次都整個資料表全部重撈。 但 SQL Server、Sybase 的 Stored Procedure,都能直接傳回「表格式」的資料, 但 Oracle 不行(屌), 請問有用 Oracle 開發程式的大大,是否有解決方案,或相關資源? 另 Oracle 的這個特性,是否有其他解決方案,能傳回「表格式」的資料給呼叫端及 ap 程式, 或在 Stored Procedure 方面,Oracle 是否又有他自己「獨樹一格」的獨家做法? 謝謝。
# by chicken
要是我的話,我會在兩邊談定的 "介面" 這端下手。 TDD 的一個原則是先寫測試再寫程式,寫測試的對象就是將來要寫程式的人... 不過另一種搭配的用法是,用的人寫測試 (表達出他想怎麼用寫好的 LIB),寫的人得滿足自己跟另一組人寫的測試... 這樣才能過關。 再者,測試的人也會測到 BUG,人力夠的話每一個 BUG 也可以用單元測試來重現,這又是第三種測試的來源 (不過這部份就是事後補的) 所以套用到寫資料跟寫報表的兩組人,當然就是寫報表的那組先寫測試程式吧! 用 QUERY 簡單的寫或是用 C# 都是不錯的作法
# by Jeffrey
to Wizard, ORACLE是用Ref Cursor解決傳回Table的問題。http://msdn.microsoft.com/zh-tw/library/4s2zbbsz(VS.80).aspx
# by 劍心
steve--------------------------------------------------- 各模組都以"別人送進來的資料都已經是正確的"為前提,製造出所需要的"正確的假資料"去進行開發,以及開發過程中的單元測試 ------------------------------------------------------------- 我覺得 steve 的方法很可行,我前參與過的專案也是這樣做的 (不同的公司負責不同的部份)
# by ryan
認同chicken, 介面才是key. Project management最強調的, 就是定義deliverables.
# by Jeffrey
謝謝大家的意見,讓我有機會從其他角度回味一次這個問題,有些新的心得。steve說的【以"別人送進來的資料都已經是正確的"為前提,製造出所需要的"正確的假資料"去進行開發】跟chicken的【介面】背後意涵是相同的,都能切割出一塊較不受人干擾的發展範圍。 再回頭看文中的例子,看起來資料庫便是報表模組承接模組A結果的介面,而文中有爭論空間的點在於: 1.模組A程式出錯寫入錯誤資料時,要不要立即把屎擦乾淨? 因為它不影響模組A,卻會影響報表模組。steve的DB隔離法是種解決方案,但搞兩套資料並行要些額外成本就是了。 2.模組B發現到模組A的結果有錯,要不要協調模組A的開發人員,調查到底是真的有錯,還是模組B的開發者認知錯誤? 錯誤要盡早處理的原則應該沒人反對,我想這題的答案沒啥爭議。 3.模組B因為資料不乾淨而看不到預期的結果,應該盲目寫下去嗎? 大家都認為是否定的,可以靠隔離資料或切Interface的方式克服之。
# by Wizard
感謝明儒老師。 不過對岸有人用 ref cursor 寫「分頁」功能, 聽說效能不佳。 不懂 Oracle 為何不像其他資料庫, 提供讓預存程序,能直接 return 一個 ResultSet 的表格式資料,效能又較好。
# by 小熊子
我會先從人著手,先找到一位 Architect,熟悉程式語言與資料庫。 定義 Glossary ,讓大家的溝通許 再從 table 著手,會設定許多的限制式, 例如純日期欄位,不得填入時間欄位。 例如 foriegn key , unique index。 再從程式與預存程序,interface 著手,製定共同的溝通語言。 整合測試原本就是從專案起始到結束,不間斷的進行,通常會有一組 QA 人員或由 User 持續進行檢測作業。 重點是持續整合,而非分段整合(開發歸開發,測試歸測試),這樣子會容易發散。 如果 Architect 又要熟程式語言,又要熟 Domain KnowHow ,我現在只遇過一位,很難得一見的神人。
# by 路人喵
老大,請問您的文章和blog能不能多加一些facebook和plurk的推..不要只有funp推推王....這樣很難分享到我個人的fb和plurk上哩..
# by Jeffrey
to 路人喵, 好建議! 我會抽空研究加上,謝謝!