今天的文章來自Jerry的同僚,曾經的搭檔鄭曉霞(Zheng Kate)。鄭曉霞是在Jerry心中是一位很有實力的程式媛,2011年從西安某軟體公司跳槽到SAP成都研究院。當時,成都研究院的CRM團隊剛剛成立,Jerry和鄭曉霞都在一個大組。
2012年夏天,我們接到任務,要把SAP Customer Briefing這款已經釋出的iOS應用移植到Android平台。因為隻有1年的期限,老闆組建了一隻特殊的開發團隊,由Jerry, 鄭曉霞和另外兩位男同僚組成。是的,因為需求很清楚,就是把iOS版本上的功能移植到Android平台,是以這隻團隊沒有産品經理,沒有架構師,鄭曉霞擔任了開發人員和Scrum Master的雙重身份, UX也是項目中後期從上海找了一位同僚遠端加入項目組。由于我們4位以前都沒接觸過Android開發,是以也是邊學習邊幹活。這個微型團隊的學習氣氛非常好,一個人遇到困難,其他三位都會積極熱心參與讨論和提供幫助。

Jerry印象最深的一件事是,當時我負責實作一個company profile的功能,即客戶可以從一個下拉清單裡選擇一個企業,進而進入該企業明細頁面,顯示該企業的概述,包含文字簡介,企業人數,财政收入等等。概述資訊通過消費wikipedia提供的Restful API,傳入企業名稱,傳回響應,其中需要顯示在明細頁面裡的關鍵資訊得通過程式設計人員自己寫正規表達式提取出來。
Jerry當時的想法是,把iOS版本裡解析正規表達式的Object C代碼直接改成Java代碼,因為不同程式設計語言裡使用的正規表達式,其文法雖然稍有差異,但語意是相同的。但當我閱讀了一段時間iOS代碼那些操作正規表達式的Object C代碼後,已經頭昏腦脹了,我的Java代碼寫好後進行測試,發現并不能保證對所有測試輸入的company, 都能夠用正規表達式正确地解析出關鍵資訊。
然後Jerry說,算了,我不參考iOS代碼,我直接自己從頭寫吧。寫完後測試,發現仍然不能保證對于所有的測試資料都能正常工作。
看到Jerry陷入進退兩難的境地後,曉霞同學像女神一般出現在我面前,說:“我來試試”。一個下午過去,曉霞同學送出了一段代碼到perforce上,那是一段結構清晰,并且能夠完美使用正規表達式完成關鍵資訊解析的Java代碼。我使用了一百多個company進行測試,全部工作正常。實際上,直到最後發版,曉霞同學這段代碼也沒有發現任何bug。
當時曉霞同學在Jerry心中的形象和這位潇灑的警察一樣:
這件事讓Jerry從此對曉霞同學刮目相看,一直到現在。
下面是曉霞同學的正文。
大家好,我是鄭曉霞,現在是SAP成都研究院Hybris Enterprise Commerce Platform開發團隊的品質工程師(Quality Engineer, 下文簡稱QE)。今天我想和大家聊聊我在這個崗位上工作一段時間之後的一些心得和體會。
在靈活開發模式下,團隊需要有持續快速的傳遞能力。那麼在持續傳遞過程中,如何保證産品品質呢?大家的答案可能是自動化測試。
但是自動化測試是否足夠、有效,即使足夠、有效,就能說明産品品質好嗎?測試結果隻是一個名額,這個名額代表的隻是在目前的測試環境下,現有測試執行個體的運作結果,是我們保證品質的下限。
軟體品質不是測試出來的,而是在開發過程中建立起來的。控制開發過程中的品質有助于提高産品的品質上限。
Shift Left Testing,通俗了解就是把位于傳統軟體開發流程中最後階段的測試往前提。提到哪一步呢?開發?設計?需求?我個人的了解是越往前越好。這意味着在整個開發周期内需要持續測試,持續關注品質,這一切都是為了提高品質的上限。
這會帶來什麼好處呢?
1. 減少測試和開發的成本, 提高投入産出比ROI(Return On Investment)
在軟體開發的整個過程中,越早發現問題,修複的成本越小。
試想在所謂的內建測試階段發現一個bug,花時間部署測試環境,準備測試資料,執行測試,重制bug,跟開發人員溝通,将bug配置設定給開發人員後,他/她們可能需要重新部署開發環境,重新開發,重新做代碼審查,最後再走一遍測試流程。如果能在代碼審查或者單元測試階段發現這個bug,得節省多少時間?
2. 提高測試效率
如果能在需求,設計階段能發現并阻止bug,可以節約很多開發生命周期的反複,同時在了解需求、代碼的基礎上進行測試,可以更有重點和針對性地面向業務和風險測試,而不會陷入測試細節,有效提高測試效率。
3. 提高品質
在需求層面保證并優化需求以及需求傳遞的品質,在代碼層面保證設計的靈活性,代碼的整潔性, 在開發過程中控制品質,提高産品内部品質。
Shift Left Testing是需要整個靈活開發團隊作為一個整體去遵循的。那麼在一個靈活開發團隊中,作為一位QE,在整個産品的開發生命周期中需要怎麼和團隊合作呢?
1. QE作為靈活開發團隊的一員,可以做任何能幫助團隊提高品質的事情, 沒有界限,目的是為了幫助團隊發現問題,解決問題,提高産品傳遞品質。
QE要能做到沒有界限地提供品質保證,需要自身做出兩個重要的改變:
(1) 全方面地提高自己的技能
如果缺乏相關的技能,比如業務能力和一定的代碼能力,很難想象QE能夠高效地參與到各個開發環節的讨論中,更談不上能給出建議和意見。當然這不意味着必須讓QE成為一名全棧工程師。QE需要去找到學習的平衡點。有些技能可能不是必須的,但是如果具備這些技能,會讓QE以更加高效的方式做事。
(2) 深入到軟體開發生命周期的各個環節,緊跟團隊的開發節奏
如果不深入到開發的各個環節,有些品質問題的根源沒法找到,那麼提前阻止bug也就無從談起。隻帶着耳朵聽,是沒法深入的。需要思考,從品質的角度去思考,但是如果技能差距太大,能勉強跟上節奏也就不錯了,談不上思考。是以深入軟體開發周期各個環節需要QE自身技能的支撐。
同時,QE在參與的過程中,需要把握好平衡,能發現問題,也需要讓團隊各個角色能夠各司其責,維持健康的團隊工作模式。
2. QE需要教育訓練團隊,讓團隊能夠擁有測試技能和品質意識,并能夠自己解決問題,同時不斷提高品質。
産品品質由靈活開發團隊來保證,經常聽到有同僚說,”我們的QE還挺厲害的,測出了不少問題”。在一個靈活開發團隊中,隻有一個QE,靠一個人的英雄主義,測這麼多問題,如果QE休假了怎麼辦?能對團隊的品質放心?
QE的成就感不在于“我有多麼重要,測出了多少重要的bug”,而是“沒有我,團隊的産出仍然是高品質的”。要達到這個目标,QE的任務就是挖掘團隊的品質需求,教育訓練團隊,讓QE變得越來越“多餘”,使團隊成為一支“去QE化”的靈活團隊。
這兩點看似沖突,實則第一點(幫助團隊發現問題)是為了有方向性地支援第二點(如何教育訓練團隊自己解決問題)。随着團隊越來越成熟,這兩點也就慢慢地越做越少。
那麼品質是不是越高越好呢?品質是要付出代價的,需要控制成本和産出。舉個溫伯格提到的例子,MiniCozy公司的文字處理軟體,在對一整本書進行排版時,會出現漏詞的錯誤,而這個錯誤确實發生在一個作家的處女作上。但是MiniCozy公司的回應是,在數以十萬計的使用者中,或許都找不到十個人會把這樣大規模的任務用單獨的一個檔案來組織,修正這個錯誤可能會花很多時間和成本,并且還有可能引發更大的錯誤,進而影響到幾百甚至是幾千位使用者。MiniCozy認為他們的取舍是正确的。是以品質不是指毫無纰漏,而是有其相對性。
下面我列出了在軟體開發生命周期的各個環節裡,QE能夠做的事情,但是QE不是一定需要參與,參與的目的是為了發現問題,最終是需要教育訓練使得團隊能夠具備品質和測試相關的知識和思維,通過改進流程,行為讓團隊自己保證品質,并不斷改進。
根據每個組不同的成熟度和QE技能的高低,事情可能會有所不同。
為了圖表的簡化,隻列出了事情本身,下面會有簡單說明做這些事情的目的。
Before coding - 開發開始前
1. Involve requirement discussion early
在做産品開發前,我們應該了解需求背後的原因,客戶遇到什麼問題,我們能夠幫客戶解決什麼問題。我們測試的不僅僅是産品功能,更是業務價值。提前參與需求的讨論對決定測試的重心,優先級都有極大的幫助,避免陷入辛苦的測試細節中。這樣我們就可以有效的利用Pareto的20/80原則,提高測試效率。
2. Ask negative questions
每個人都可能受慣性思維影響,我們可以通過問負向問題來優化功能性需求和非功能性需求的測試, 比如産品标準和GDPR(General Data Protection Regulation)等。
3. Collaborate with testable and executable acceptance criteria
Acceptance criteria主要關注的是業務價值,建立user story的功能範圍,并能指導開發。通過各個角色合作讨論的方式列出acceptance criteria,能夠避免對需求範圍的誤解,同時參與的每個人都能很清楚的知道要測什麼,要怎麼測。
4. Work out test plan in sprint
在靈活開發的每一個sprint内,我們也需要基于sprint目标制定測試計劃,包括哪些功能需要手動測試,哪些功能需要自動測試,哪些功能需要回歸測試,是否需要做性能測試/安全測試等。同時還需要計劃對之前的測試做維護。這個測試計劃會影響到sprint planning meeting對任務的分解和時間估算。
5. Join estimation proactively
在sprint planning meeting中,基于制定的測試計劃,積極參與對任務的分解和時間估算,包含相關測試的開發、維護和執行時間。
6. Design and prepare test points with good test data including automation test
這些實際是傳統的瀑布開發模式需要的測試相關的專業知識,同樣也适用于靈活開發模式。通過各種方法論的使用,設計出測試點,來指導、優化測試執行,提高測試效率。在靈活開發模式下,QE需要讓所有成員都具備這種測試設計技能。
7. Define KPI/Dashboard
團隊需要定義如何來度量品質,KPI(Key Performance Indicator, 關鍵績效名額)的路徑成本能直接回報出團隊的外部品質,并可以通過根源分析幫助團隊認識問題,解決問題。
During coding - 開發過程中
1. Join or familiar with design
雖然靈活開發模式并不像瀑布開發模式那樣具有專門的軟體設計階段,但是小的功能點設計在每個sprint确實存在。不同的設計有不同的測試考慮,比如通過事件來觸發訂單流程,或是通過背景作業來觸發訂單流程,測試要驗證的點肯定是不一樣的。如果采取背景作業方式,還需要驗證作業資訊和計劃的執行時間是否正确等等。
同時我們需要在設計時考慮可測試性。軟體的可測試性是指軟體發現故障并隔離、定位其故障的能力特性,以及在一定的時間和成本前提下,進行測試設計、測試執行的能力。James Bach 這樣描述可測試性:軟體可測試性就是一個計算機程式能夠被測試的容易程度。
比如,為了測試一個類的方法,首先我們需要建立這個類的執行個體,需要引用必須的内部依賴,同時還要隔離外部依賴。有的場景下做到這些并不是那麼簡單,由于開發人員容易局限于考慮自己負責的功能的具體技術實作而忽略了設計的可測試性,而QE參與功能設計則可以提高開發人員對確定其設計的可測試性的意識。
2. Guide/coach/pair to develop testable code and effective test code
可測試的代碼是寫測試代碼的前提條件。測試代碼的作用絕不僅僅是用來滿足測試覆寫率的,測試代碼需要基于測試設計和測試資料來測試軟體的功能,是以需要QE能和開發人員一起保證測試代碼的有效性。一旦發現bug,除了修複bug本身,還需要評估是否需要改進現有的測試代碼來覆寫這個bug。
3. Go through code for both functional code and testing code
以QE的角度檢查代碼,比如需求是否比對,是否考慮了SAP産品标準等等,從這個角度檢查既有助于發現問題,同時可以提高測試效率。比如,代碼添加了新方法來擷取目前時間,時間和格式是否做了本地化處理?這個新方法是否被調用了?如果都沒有符合,那還需要繼續功能測試嗎?在這些缺陷彌補之前,當然沒有必要進行功能測試了。後面我們還會追溯為什麼會有這種情況發生。
4. Safeguard DoD compliance
因為我們是做産品,隻有滿足了DoD(Definition of Done, 完成的定義,靈活開發裡的一個術語,表示工作是否完成),user story才能算完成。我們必須要嚴格遵循,這樣才能持續傳遞,并且避免技術債務。
5. Utilize continuous integration environments
通過內建各種代碼掃描工具,利用持續內建來發現問題,提供品質的快速回報。
6. Test an uncompleted user story
通常一個user story不會太大也不會太小,在團隊還不夠成熟的時候,QE還是需要測試user story。為了不在sprint末期出現測試的“驚喜”和大量測試任務的湧現,我們可以和開發商量,讨論出哪部分功能可以先開發。等這部分功能開發結束後就可以開始測試,即使這個user story還沒有完成。
7. Provide fast feedback
除了持續內建之外,QE需要對開發的bug提供及時快速的回報,因為開發人員熟悉業務和代碼,能夠比較快速地解決問題。另一方面這也可以作為考慮如何提高品質的on-job教育訓練的一部分。
After coding - 開發結束後
1. Test user story based on business value and risk
在團隊還不夠成熟的情況下,QE還需要基于業務價值和風險來測試user story,測試的粒度和範圍可以根據團隊的具體情況進行調整。
2. Hold another bug hunt or other manual exploratory testing session
基于user story的KPI,重要性和風險程度,我們需要決定是否再需要一輪測試。
3. As problem solver to analyze issue and find how to resolve issue
QE發現了bug,報告給開發後,QE的任務就完成了嗎?QE可以通過現象,日志等分析問題,定位問題,提高問題的解決效率。
4. Reflect AC/DoD/Test plan/test case/test data
回顧之前做的一切和測試相關的活動,從中總結經驗教訓,做到持續改進。比如上個sprint的test plan實際執行情況如何?設計的test case覆寫到了所有場景嗎?準備的測試資料品質如何?測試活動中有哪些方面下個sprint可以做得更好?
以上僅僅是個人觀點,歡迎共同探讨學習。
要擷取更多Jerry的原創文章,請關注公衆号"汪子熙":