Cubie Messenger技術長陳彥任(圖中左二)表示,伺服器端程式使用的技術或是第三方套件,不要求新而要追求穩定好維護。

圖片來源: 

iThome

改版向來是系統營運人員的夢魘,尤其是開發平臺SDK的版本升級,只要稍有些微不相容,不只是服務不穩,甚至得大幅修改程式碼。不過,臺灣本土開發的即時通訊App程式Cubie Messenger團隊只用了1天,從Java 7順利升級到最新版本的Java 8,完成15萬行程式碼的後端伺服器平臺升級。

Cubie Messenger推出至今全球下載數超過1千萬人次,同時上線人數達百萬人,Cubie Messenger技術長陳彥任表示,升級過程服務完全不受影響沒有中斷,是一次無痛升級,選擇成熟技術以及養成良好開發習慣是關鍵。

談到想要將Java7升級成Java8的原因,陳彥任說,他們對新玩意充滿熱情,只要是新技術都會手癢的想要試試,尤其Java8是近年來的一次大改版,而他們專案後臺又是使用Java當作開發語言,因此在Java8釋出不久,他們就嘗試著使用Java8開發一些小專案,發現Java8新增的Lambda表示式語法讓人上癮,寫完Java8的程式後,再使用Java7的語法便極度無法適應,陳彥任直說「回不去了」。

Java8的Lambda表示式使開發者上癮

陳彥任強調,使用Lambda表示式的語法,其中一個效益便是能簡化for迴圈,不只程式碼行數大量減少,連程式的邏輯也變得更清楚,因為Lambda表示式能讓for之類的迴圈邏輯判斷與副作用(Side effect)得以分開,而使整體程式碼更加簡潔好維護,「Lambda表示式讓迴圈的語法變得像SQL語法一樣直覺。」他說。

這樣的效益在撰寫巢狀迴圈的程式碼時更加明顯,如存取資料庫的資料時,通常會使用到多層for迴圈。過去,開發者知道迴圈邏輯判斷與副作用分開的程式寫作方法是對的,但是當程式本身不支援Lambda表示式的語法,硬要用這樣的方法開發,將必須撰寫更多行的程式,程式可讀性也就更低了。而且陳彥任補充,不少語言都有支援Lambda表示式,但是其中有些語言使用Lambda表示式語法,有可能使程式效能降低,不過經過他實際測試,在Java8使用Lambda表示式語法並不影響效能。

而Java8最大的改變,陳彥任說,是引進函數式程式設計典範,如此更能方便地藉由平行化運算,增加程式的執行速度,以for迴圈為例子,函數式語言的邏輯判斷與副作用的程式能夠分開平行執行,因而能縮短運算時間。

不過,陳彥任也說,Java8的平行化運算並不好駕馭,函數式語言只是增加平行運算效能的機會,並非所有工作都能得到加速,因為處理器要將執行任務拆成多項子任務平行執行,需要增加額外的工作,所以陳彥任表示,開發者要非常清楚自己撰寫的程式碼所執行的任務,是否適合平行化,抑或是任務的運算量已達需要平行化運算,否則將白忙一場。

在Lambda表示式語法的驅使下,陳彥任著手計畫升級Cubie Messenger伺服器端的系統,他先建立專案分支作為測試版本,再將測試版本的執行環境從Java7升至Java8,但因為原本專案使用的Spring Framework 3並不支援Java8,因此也一併升級到Spring Framework 4。而在陳彥任意料中,升級過後的初次執行,果然出現了不少錯誤以至於專案無順利完成建置(Build),但是在他意料之外的是,錯誤都只來自於專案使用的Spring Framework,在稍加更改設定檔後,整個專案就能順利執行了。

不過,要在正式提供服務的伺服器上運作,還需要更嚴謹地把關,Cubie團隊奉行TDD(Test Drive Development)的開發方式,因此Cubie Messenger專案開發過程也累積了上千個單元測試,陳彥任表示,上千個單元測試全數通過,皆沒有錯誤之後,他大概就有9成的信心,認為系統可以上線了。不過,陳彥任希望能達到熱更新,不需要為了更新Java8而全數關閉後端服務伺服器來升級,而是能讓這些伺服器輪流升級,確保服務不中斷,因此,陳彥任還得測試新舊版本Java的Cubie伺服器是否能共存,伺服器間的溝通是否順暢。而Cubie的伺服器是非集權式的,每一臺伺服器擁有的功能都一樣,只要有一臺新的機器新加入伺服器群,伺服器間能自動互相溝通運作,不過,當一臺Java 8的Cubie伺服器加入伺服器群,卻與Java 7的Cubie伺服器無法相容,服務便會發生問題。

陳彥任先在Stage測試伺服器上,以正式伺服器的設定,測試Java 7與Java 8的Cubie伺服器共存的異質環境運作,結果完全正常,如此一來,便放心的讓正式伺服器陸續更新上線了。從Java7更新到Java8,陳彥任說,整體效能沒有太大的差異,只有Heap用量約下降5%。

歷經多次的系統更新,陳彥任認為,企業在選用技術時,應該考慮系統程式的生命周期,當程式的生命周期需長達3到5年,要用「以終為始」的作法來選擇能長久穩定的技術,且過去版本更新紀錄良好,前後版本相容性高。

伺服器程式講求長久穩定

陳彥任提到,現今的前端技術改變的幅度都十分劇烈,從Web 1.0到Web 2.0,到近年的行動裝置,也造成前端程式常面臨全面改寫的命運,但是伺服器端的程式比較不同,生命周期比較長,有時或許需要修改部分功能,但程式碼需全部改寫的機會微乎其微,所以,為避免將來維護成本過高,開發者應在一開始就未雨綢繆,選擇較穩定的第三方開發框架或函式庫。

不過,陳彥任說,有時候也很難確定這些第三方框架或函式庫前後版本持續維持相容,例如直譯式程式語言Python2與Python 3的改版就有非常巨大的改變,Python 3釋出已6年,卻仍然有很多專案因為不想處理升級時須面對的UNICODE問題,而依舊使用著Python 2舊版。「顯然,破壞性演進在軟體業系統維運上是完全行不通的」,陳彥任說。

「我不是說只能選擇Java,盡管Java是個好選擇」,陳彥任提到,要確認第三方開方框架能否依靠,以他自己的經驗法則,首先要看這些框架的專案貢獻人數,以判斷專案的健康與否,第二是看教學文件的完整度,尤其是專案1.0版本的文件越齊全的專案,其後續各版本的相容性越好。

TDD使程式品質更加可靠

另外,陳彥任也提到,促成此次更新快速成功的另一項要素是TDD,而TDD正是2014年4月的熱門話題之一,RoR之父DHH(David Heinemeier Hansson)在Railsconf開了第一槍,表示TDD已死,他寫程式已經不TDD,陳彥任也在當時提到,因為DHH寫程式已成精,對他來說,寫程式已經不需要TDD了,但是TDD確實是一項強大的工具。

陳彥任說,要是Cubie專案過去沒有建立了上千項的單元測試,他們也沒信心可以這麼快就讓Java8上線。一般來說,TDD的開發方式,便是要先寫出功能測試單元,而後才完成該功能的程式,因此每一支程式都會有對應的單元測試,儘管寫測試的時間要比真正開發的時間多出2到3倍,但這次升級時,只要新版本通過了所有的單元測試,也就可以確保程式碼不會出錯,也不會漏了每一項該做的測試,TDD效益在此次Java8的更新是顯而易見的。陳彥任說,當專案沒有TDD單元測試,通常不敢貿然進行更新作業,因為根本不知道問題會發生在哪一個環節。

Cubie Messenger更新Java8的例子,對於很多專案來說是很好的示範教材,團隊擁有良好的開發習慣,前期腳踏實地的建立測試單元,後期系統維護需要的人力以及時間成本便可以減少許多。

用Java的傳統語法與Java 8的Lambda表示式語法撰寫同樣功能的程式碼片段,發現Java 8的內部迭代只要6行程式碼就能完成,Java的外部迭代語法卻要21行,簡潔程度差異甚大。


熱門新聞

Advertisement