本文係投稿於 CNet / ZDNet Taiwan 的初稿,並分為上下兩篇文章刊出,未經 ZDNet Taiwan 編輯,其內容可能會略有差異。
軟體專案團隊在專案開發的過程中,常會面臨許多問題,例如需求的不斷變化、資源的短缺、時間的急迫性、以及技術的難以掌握等。這些事件雖然都將直接影響專案的產出與品質,並且會令開發者會感到相當困擾,但只要存在希望,問題都還是可以有解決之道的。然而,在什麼情況下,專案發生了什麼事會讓開發者完全失去希望,並且感到他的世界相當悲慘呢?
相信許多人都會同意,總要等到專案驗收前,才發現程式品質有問題是一件很令人沮喪的事情。而筆者根據軟體專案實務經驗也發現,對軟體開發者而言,最悲慘的事件莫過於在專案臨驗收之際,才發現程式沒有合乎品質上要求。
軟體開發者的悲慘世界
筆者用一個笑話來比喻這種開發者的悲慘世界。話說有三兄弟開車回家,就在車停妥在停車場時,突然發現大樓停電了。很不巧的是,他們住在五十樓,停電沒辦法坐電梯,於是他們只能用爬樓梯的方式回到他們居住的地方。
爬到十樓的時候,大哥建議每人講一個最悲慘的故事,並且從他開始。大哥說:「從前有一個人從小就沒有父親,是由母親含辛茹苦地養大,好不容易稍稍有了一點小成就想要報答母親時,母親卻病死了。」,說完時他們己經到了二十樓。
二哥接著說:「從前有一對情侶非常相愛,男孩要出國留學,女孩也發誓不管多久一定會等他回來,四年之後男孩終於學成歸國,女孩也堅貞如是,但是女孩卻在去接他的途中出車禍,當場死亡。」講到這裡時,不知不覺的已經到了四十樓。
這個時候,沒想到三弟只不過說了一句話,三兄弟馬上坐在樓梯上大哭。他說:「大哥,二哥,對不起,我忘了把鑰匙放在車上了!」
軟體開發者的悲慘世界就像這個笑話一樣,眼看目標就在眼前,這時卻發現最關鍵的地方,亦即軟體品質沒有達到要求而將導致前功盡棄。而更令人絕望的是,在最後一刻才發現這樣的窘境,此時要及時彌補缺失卻是相當困難的。
就像笑話中的三兄弟一樣,他們必須有人回車上拿鑰匙,而原來走過的路要再重新再走一次。軟體專案開發也是一樣,先前沒做好的開發作業必須回過頭重新把它們做好,而後續的開發作業也必須重做一次。但問題是客戶馬上就要驗收,開發者通常已經沒有足夠的時間來解決問題了。
對於開發者而言,這樣的悲慘世界可真是可怕的夢魘呀。然而,這樣的現象為什麼老是一而再,再而三地發生,到底是什麼地方出了問題呢?顯然問題多半出在開發者無法儘早發現程式瑕疵並及時因應,卻讓自己在茫然無知的狀況下,讓問題不斷地惡化下去。而依據筆者的實務經驗顯示,這種現象可以從開發者的紀律、確認與驗證的過程兩方面來理解。
開發者的紀律
可能有些人會把無法早期發現程式瑕疵歸咎於「無常」兩字,就像笑話中大哥、二哥所提供的故事一樣。得確,軟體專案的本質是充滿不確定性的,實際上會發生的問題是很難事先預料得到的。然而,但當我們經過深入地去檢討後卻常常可以發現,藉由良好的開發者紀律可以減少因為一時疏忽而產生不良後果。就如同笑話中三弟所言的疏忽一樣,許多程式的瑕疵是因此在剛開始分析或設計時就己經存在了需求或設計規格中,但卻直到最後一刻才會被發現。
依據筆者的觀察,一些軟體開發者在分析或設計時,經常不會事先思考需求或設計規格的驗證問題,而是等到程式實作出來過後才會開始思考測試該如何進行。由於在需求或設計規格上,並沒有思考到如何驗證的問題,其內容就常常就會因為不夠完備而顯得草率而馬虎,自然使得程式碼的產出常常會缺東漏西,甚至產生一些錯誤。
而等到開發者在開始進行編程時,規格上所缺漏的部分自然就不會被實作出來,而需求與設計的錯誤更會具體地被實作在程式碼當中。當然部分需求或設計的疏漏與錯誤,可藉由在實作的過程中被發現。但對於一些經驗、能力不足、或態度不夠積極的程式實作人員而言,他們通常只會按照規格來開發程式,而不會去進行溝通並發展良好的程式結構來解決工作上的問題。
另外,有些開發者會習慣於暫緩程式的驗證,他們總以為進行程式的開發遠比進行測試驗證還來得要有生產力,甚至在面對時程的壓力時,會選擇省略功能測試,期望以整合測試或系統測試來將測試問題延後處理。
因此,以上種種原因,使得測試作業太慢開始、程式碼之中散佈著因為需求或設計規格、或實作結構問題所產生的一些疏漏或錯誤,這些現象使得程式瑕疵擴散或蔓延的速度比修正的速度還來得快。當程式的瑕疵愈變愈多、除錯就會顯得更困難,對程式的除錯與測試都是個沉重的負擔,更不用說可以及早發現程式中的瑕疵了。
確認與驗證的過程
在軟體工程的領域中,確認過程代表確定開發產出滿足及符合原始的設計,也就是把事情做對。而驗證過程則代表檢查開發設計滿足或適合預期的使用,也就是做正確的事情。在台灣,一般大型軟體專案多半採用 V-Model 的軟體開發流程模式來進行軟體的確認與驗證。此開發模式展現了不同抽象層次觀點的開發作業與相關的測試作業之間的關係。
一般而言,我們會將軟體專案開發分為三個開發層次,高階的抽象層次為處理使用者的需求分析;中階的抽象層次則將重點置於將所了解的需求轉化為軟體架構;低階的抽象層次主要為系統功能的細部設計與系統實作。
在每個開發作業完成之後,開發者應當進行確認過程來確保開發作業符合需求及設計規格後才能進行下一個開發作業。而直到程式被實作出來之後,開發者必須依序按照不同開發層次的要求來進行驗證過程,以各種不同類型的測試作業來檢查軟體是否真能符合實際使用上的需求。如下圖所示。
此開發模式配置了良好的結構方法,讓每個開發作業都可以根據前一個開發作業的詳盡產出來進行作業。而測試計劃可以很好地提早在編程前就開始進行規劃,如此將為專案省下大量的時間。但事實上,採用 V-Model 在專案後期仍然還是會從程式碼當中出現不少瑕疵,似乎按照規格來開發系統仍然無法解決需求與設計在專案後期因為經常變動而影響程式碼品質的困境。
為什麼會如此呢?從 V-Model 的開發流程結構我們其實不難發現到,愈高階層次的開發作業是愈晚被驗證的,而在它尚未被驗證前,較低階層次的開發作業都會因為它的變動而受到影響。例如,在系統測試時,如果發現軟體無法通過驗證的原因是因為需求規格的瑕疵,如此就必須回過頭來修正需求規格的瑕疵,並重新進行設計與程式開發。
換句話說,愈高階層次的開發產出,其瑕疵是愈晚才會被驗證出來。而相較於低階層次的開發產出,其衝擊影響力又是相當嚴重的,因為這代表瑕疵將會在較低層次的開發產出中擴散與蔓延。因此在實務上要做到「早期發現、早期治療」,讓需求或設計的瑕疵盡早被發現與解決其實並不容易。除非需求與設計規格能夠儘早驗證完全無誤,然而,在程式在尚未實作出來之前,開發者又該如何做到這一點呢?
如何早期發現、早期治療?
如果對於需求或設計,開發者無法先驗證其可行性與正確性,而必須等待程式實作出來才能靠測試作業來加以驗證的話,那麼我們將會期望測試作業必須具備相當高的效率及足夠的涵蓋面。但實際上,測試的效率與涵蓋面會受限於專案的時程與成本,因此希冀測試作業能夠有效率地找出程式所有的瑕疵的想法往往是不切實際的。
一旦我們愈晚進行測試,因未驗證的分析設計而產生的遺漏或缺陷將會使程式中的缺陷不斷地擴散,如此將會使開發人員更窮於應付。換句話說,不良的需求或設計往往會加重測試的負擔與壓力。
因此,要用較低的成本與時間來達到最佳的程式品質,其關鍵並不在於測試的效率與涵蓋面,而是在於提昇需求與設計規格的品質。然而,我們該如何發展出較佳的需求與設計規格,並且能夠及早發現存在需求與設計規格的瑕疵以適時加以修正呢?
筆者認為,開發者在進行分析及設計的過程中,就應該同時思考需求規格與設計該如何驗證的問題,而不是等需求或設計規格完成後才去設計驗證的程序。同時,在需求或設計規格交付之前,應該讓團隊針對欲交付產出進行實質上的技術審查,以集思廣義的方式促進集體反思,以找出分析或設計者所忽略的潛在問題與瑕疵。
如此將使因個人盲點而產生之需求或設計的瑕疵會因此大幅減少。因為,為了要找出如何驗證需求或設計規格的方法,就會強迫我們客觀思考自己的想法是否完備、有沒有被我們所忽略的問題沒被考慮到,進而完善我們的思慮。另一方面,請別人來一齊檢查自己所分析或設計的開發產出,更可以站在更客觀的立場來看問題,透過不同的觀點來了解自己是否忽略了什麼。透過集體思考的過程,我們可以得到更為一致的需求與設計觀點,就不會流於個人的執著與徧頗。
在驗證需求或設計方面,在分析或設計過程就必須思考驗證需求或設計的具體方法。這代表了不一定要等實作設計的程式完成後,才能開始寫測試程式。如果我們無法依據設計來寫出測試程式時,其實正代表著我們設計的思慮多半是有問題的,我們對設計的想法可能還不夠具體,如此的設計是很可能存在許多我們所想不到的缺陷與瑕疵的。當然,先寫測試程式並不是唯一可以「在分析或設計過程中思考需求或設計如何驗證」的方式,不管採用任何形式的開發方法論,筆者認為都應該先想到如何以具體可行的方式來驗證需求與設計。
舉個例子來說,架構設計必須包含架構的概念驗證(POC,Proof of Concept)。架構設計者不應該省略驗證架構的程式,卻期待程式實作者來幫他實現未經驗證的設計構想。他必須自己親自驗證架構,如此才能透過驗證,使自己設計的架構趨於成熟,而不致讓開發團隊在使用架構的過程中出現問題叢生的困擾。
而在技術審查方面,在設計過程中進行 software inspection,除了可以提早發現需求或設計的瑕疵,更能促進團隊成員相互學習以提昇開發能力。品質不只要靠檢驗,而是不去設計有缺陷及瑕疵的系統。然而,不管開發者的分析或設計能力有多強,都不能保證其開發產出絕對沒有問題。在這種思維下,全員參與是一個好主意,於是讓同僚參與需求或設計規格的審查可讓系統設計更趨於完善,一來可以用比較客觀的方式來確保設計符合需求及使用者需要,二來也可以讓同僚更清楚我們在做什麼,相互觀摩學習並增進團隊的效能。
因此,在思考如何驗證需求與設計的過程中,會讓我們不知不覺地把焦點放在最主要目標的達成上,可以讓我們更有效地整合開發作業與測試作業。而讓同僚參與分析與設計的討論過程中,將有效撤除開發作業之間的藩離,透過同步的協同作業可得到截長補短的好處,如此將發揮一加一大於二的團隊綜效。其實同步與整合,正是讓程式瑕疵得以早期發現、早期治療的有效的做法呀。
聞君一席話,勝寫10年code
謝謝 wychi 的誇讚,不過文章要看,code 也要寫,期待下次您寶貴程式開發經驗的分享。
自動引用通知: 同人的生活派對 » 軟體缺陷的信用創造