iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 5
0
DevOps

CI 從入門到入坑系列 第 5

簡單的好習慣,是 CI 的一大步

前四天跟大家聊很多觀念與思考一些議題,今天要來聊聊 CI 該怎麼開始了!

頻繁驗證

要開始 CI 並不難,最簡單的方向:只要每次修改程式到一個段落都做驗證,這樣就是 CI 了。 Day 2 介紹 CI 有提到, CI 很像對程式做健康檢查。當健康檢查越頻繁的時候,就越容易知道病源在哪裡。比方說:昨天健檢身體很健康,今天突然發現腸胃有點毛病,這時可能會懷疑昨天晚上吃燒烤的味道好像怪怪的,但絕對不會懷疑前天吃的火鍋不新鮮。

是的,這就是頻繁驗證最大的好處:縮小並聚焦問題可能發生的範圍。很多寫程式的老手都會不自覺使用這個方法在除錯。比方說下面這段程式碼:

<?php
function foo($param)
{
    // many code

    $val = bar($paramBar);

    // many code using $val
}

function bar($param)
{
    // many code
}

$output = foo($paramFoo);

在執行 foo() 的回傳值或過程不正確。這時也不知道該懷疑 foo() 還是 bar() ,所以最快的做法就是在 bar() 上面加一行 code :

var_dump($paramBar);
$val = bar($paramBar);

接著再跑一次,確認 $paramBar 值是對的後,再加一行:

var_dump($paramBar);
$val = bar($paramBar);
var_dump($val);

確認 $val 值沒錯後,好了,可以確定是 foo() 後續處理的問題了!這正是頻繁驗證的一種。

完整地驗證

大家可能會想說,上面這招只要是有經驗的都會知道,還輪得到我講嗎?確實,也許大家都很常用,但只有單純做頻繁驗證的話,會有一個魔鬼細節:驗證範圍。以上面程式碼和驗證方法為例,它只能驗證在同一個 $paramFoo 下, bar()foo() 是正確的。但這個程式碼應該還要驗證:

  • 不同的 $paramFoo 也會如預期輸出嗎?
  • 不合法的 $paramFoo 也會如預期丟例外嗎?
  • 其他呼叫 foo() 的程式都全都有如預期執行嗎?

前兩點還好,改個參數丟一下,結果還算很快就出來了。第三個該怎麼辦,還要全域搜尋所有程式去一個一個驗證,正常人應該都會受不了,就跟要求要天天去全面性健康檢查,不管是誰都無法接受。

咦?我們的目的是要一直不斷做同樣的檢查,這不正是電腦所擅長的事嗎?所以我們可以寫測試程式來驗證程式是否正確,並讓電腦幫我們驗證,這就是「自動化測試」。當每次驗證的範圍都夠大的話,就可以確保程式在這個範圍下會如預期執行了。

記錄結果

當有了自動化,相信做驗證對任何開發人員來說都不難。但要記得,每次的驗證結果都應該要被記錄下來,供未來參考。可以回想上面頻繁驗證的例子,我們也是先驗證 bar() 功能正確,再依此結果去推論 foo() 是有問題的,因此記錄結果是有必要的。

要開始記錄前,必須要有一個系統可以做程式碼開發的歷程回顧。是的,就是 Version Control System ,也稱為原始碼版本控制系統,通常簡稱為「版控系統」或直接叫「版控」。這部分的實作有很多選擇,如 SubversionGitMercurial 等。使用版控系統的好處很多,當然最大的好處在資訊分享:可讓團隊成員取得軟體的原始碼、自動化程式碼和開發歷程。

那什麼時候該記錄驗證結果呢?其實答案也是呼之欲出:當提交程式碼到版控系統時,就能記錄了。版控系統的提交資訊也可以結合驗證結果的資訊,並分享給團隊成員,讓大家可以避免拿到驗證失敗的程式碼,同時也能取得足夠的資訊繼續開發。目前常見的 SaaS 版控系統都有做這一類的服務,如下圖是 GitHub + GitBook 的範例。

GitHub Commit Result

正確才能提交

Day 4 提到了「先要對,才會有」。而對工程師而言,程式碼要先驗證通過,才能提交程式碼進版控系統,這時就可以跟團隊成員說功能已經「有」了。

相反地,提交驗證不通過的程式碼,是在把 bug 分享給團隊成員。而其他人修改程式發生問題時,也很難去鎖定問題的範圍。比方說上例程式,如果不知道 bar() 是不是對的,就無法確定 foo() 是否有問題。對除錯來說,只要有越多的疑惑,障礙就越大。但只要養成良好習慣:驗證通過,才提交程式碼,這樣就能更有效率的開發,同時也避免風險擴大。

有錯立即修正

人並不完美,自動化是人寫的,或多或少會遺漏必要的驗證。如果已經知道取得的程式碼有問題了,最好的決策就是立即修復它,而不要在知道有問題的狀況下加新功能,因為這很有可能會讓 bug 擴散到新功能裡。

另外,還有一個重要理由是,只要團隊接受程式有任何小錯誤,接著可能會有人開始提交錯誤程式碼,反正有人會接受嘛!最終就會像破窗效應所說的,整個團隊會開始不在乎程式是否有錯。當這個文化被建立時,要做到頻繁驗證就會是天方夜譚了。唯有強迫團隊對任何錯誤都視為優先解決目標,才有辦法建立起良好的 CI 文化。

自己的程式自己驗

原始碼要包含所有能讓開發者可以自己執行驗證的資訊,如使用套件或驗證腳本等。主要是因為:要能讓開發者自行確認程式是否正確,並方便地在自己開發主機上做頻繁驗證。除此之外,另一個原因是要能讓程式碼在不同的地方都能執行驗證,如新進成員的電腦、或是 CI Server ,甚至是產品上線環境裡等。

常常提交與更新程式碼

上面已經提到很多有關驗證除錯的好習慣。最後,就是要養成常常提交與更新程式碼的習慣了!這背後有很多重要的原因:

  • 因為要正確才能提交,所以常常提交的另一個含意就是頻繁驗證
  • 有錯立即修正有提到自動化驗證也有可能遺漏,如果不常提交程式的話,問題的範圍可能會非常大,難以偵錯。
  • Day 2 有提到 CI 要整合程式碼與環境。除此之外最重要的,就是要整合團隊成員們的程式碼。同樣地,常提交並更新做程式碼整合的話,就算有問題也只會是小問題。

參考書籍

前面提到的一些要領,是參考自 CI 的經典名著-- Continuous Integration 並用個人想法表達出來的,原文裡面有提到開發人員所要遵守的七大要領:

  • Commit code frequently
  • Don’t commit broken code
  • Fix broken builds immediately
  • Write automated developers tests
  • All tests and inspections must pass
  • Run private builds
  • Avoid getting broken code

有興趣的話,可以翻這本書了解原作的想法與細節。

七大要領的說明也可以參考 Teddy 寫的開發人員應遵循的七項持續整合要領

今日回顧

  • CI 先從頻繁驗證做起,且驗證要夠全面才會有效。
  • 常常提交驗證成功的程式碼給團隊成員,盡量不要讓衝突太多以致無法解決。
  • 大數據正夯,驗證完記錄結果也是一定要的!
  • 驗證正確,就能提交程式碼!驗證失敗,就要立馬改!
  • Bug 最愛躲在不常健檢的團隊裡了,而 CI 就是要團隊用盡各種方法讓 bug 躲不下去!

當然,驗證不能只是說說,團隊必須要決定驗證什麼樣內容,才有辦法做持續驗證,因此:

下一篇: CI 起步走

相關連結


上一篇
還記得第一次寫程式嗎?
下一篇
CI 起步走
系列文
CI 從入門到入坑30

尚未有邦友留言

立即登入留言