新創工程師大哉問:如何在沒有資深工程師帶領的環境下訓練自己?

這篇文章適合誰閱讀:
1.甫入軟體開發領域的非本科系開發者
2.超小型新創公司菜鳥工程師(尤其是沒有資深工程師的公司)

一般而言,在新創公司的時間、金錢、資源皆非常有限之情況下,產品開發團隊建置可能十分精簡,極有可能負責某專業領域的團隊成員只有一位,例如:只有一位iOS工程師、只有一位後端工程師⋯⋯ 更糟的是該位成員在其專業領域甚至只是一位小菜鳥。如果你正是那位形單影隻的小菜鳥,別擔心,你不是孤獨的。因為這幾乎就是當初加入現在任職公司時,我所面臨的情況。

對於一位半年前加入公司後,才開始每天投入八個小時在iOS開發上的菜鳥工程師而言,第一次正式身為一個iOS專案的負責人,心中常會浮現一個超爆幹大的問號:我寫的程式碼品質好嗎?我寫的程式碼品質好嗎?我寫的程式碼品質好嗎?接著我很快地發現,對於我自己寫出來的程式碼品質如何,我毫無概念。是的,很有可能你會遇到跟我一樣的情況,不知道該如何判定自己的程式碼是好是壞,對於該如何有意識的持續精進自己的技術能力也充滿疑問。當時我問了一位前輩該如何判定自己程式碼的品質,他的回覆是,你覺得改起來不會太麻煩的程式碼,就是好的程式碼。

哦... 但什麼樣的程式碼才叫好改,但什麼樣的程式碼叫做難改呢?

由上述的討論可以衍伸出兩個問題:
1. 如何評斷程式碼品質好壞
2. 如何在沒有資深工程師帶領之下有意識的訓練自己

如何評斷程式碼品質好壞

從主觀及客觀兩個面向出發討論程式碼品質

若上網Google: Good code quality metrics、What's good code,大致上會分成兩大面向去談論一份程式碼的品質:主觀客觀

主觀的程式碼品質不外乎包含以下幾項指標:可讀性、可擴展性、易維護性、充分的說明文件、可測試性⋯⋯這幾項就是較為主觀的指標,幾乎每位開發者都會有自己對一份優質程式碼的定義,但是有一些共同指標是廣為大眾認可的,這也是為什麼當初前輩回答:「你覺得改起來不會太麻煩的程式碼,就是好的程式碼」的原因。

而客觀的程式碼品質通常會需要藉由一些工具輔助,使用科學化的方式去衡量,最簡單的可能就是程式碼行數(當然不是越多越好)、Code Coverage(a.k.a. 測試覆蓋率),除此之外還有很多指標例如Cyclomatic Complexity、Average Percentage of Faults Detected⋯⋯在此就不多說明這些指標,若想更進一步了解我有將相關資料附在文章最後。

由於客觀程式碼品質就是直接利用工具輔助,而這也不是一篇關於工具的教學文章,所以我們接著要談論的問題是:如何建構起對於程式碼品質的主觀意識。首先,造成無法自我衡量程式碼品質的根本原因是:你沒有充份的參考標的,甚至就算你有了參考標的,你也不知道該如何拿這個度量衡去與你的專案做比較。簡單來說,假設這個世界上沒有溫度計,也沒有攝氏和華氏刻度,請問:你要怎麼樣形容台北現在感受到的氣溫給你遠在雲林的阿嬤聽?恩,大概是一顆飲料店的冰塊放在室外隔5分鐘才會完全融化的溫度吧?聽起來很詭異吧?再拿氣溫的度量衡來當例子,假設你不知道華氏氣溫轉攝氏氣溫的換算法,95度F這樣的數字對你來講也是毫無意義的。也就是說,許多時候就算你參考了很多其他人的程式碼,有了度量衡之後,衡量自己的程式碼品質仍是一件如此抽象且弔詭的事,也因此常常會在靠北工程師上看到一些針對不懂程式合作者的嘲諷:程式碼行數 = 工程師產值、開發新的功能速度越快表示產值越高之類的工程師儒林外史。

身為一位Junior Engineer,若不刻意訓練自己,由於你參考過的程式碼非常少,導致對一個功能的實現方式想像空間十分有限。再加上新創公司總是在與時間賽跑的情況下,新的功能需求一直開,而另一方面你又需要找出瑣碎的進行重構、解Bug、自動化軟體部署流程、撰寫測試、開會(、聊天、上Facebook、看虛擬貨幣匯率、和同事在Slack上一起看Megu Megu Fire)等等。甚至得花時間關注新的技術blah blah blah...

在這種多重夾擊的混亂狀況下,你該如何有效率地訓練自己建立起對於程式碼品質的主觀?

如何刻意訓練自己

基本上,你不可能在沒有別的工程師的帶領之下成長。

我想對於所有的開發者而言,大部分的人都會同意Code Review帶給他們極大的幫助。但這篇文章的大前提是:沒有相同專業領域的工程師協助你做Code Review。這下該如何是好呢?此時你有兩個選擇,也同時可將我接下來將提供給大家參考的作法大致上分為兩類:

這樣的做法其實蠻顯而易懂,就是公司內沒有iOS工程師你就想辦法在外面找到厲害的iOS工程師。

a. Open Source Project
在Github上,你可以找到許多開源的程式碼,你可以試著去讀你正在使用的套件原始碼,這能協助你對於實現程式碼的方式有更多的想像空間。更甚至是在閱讀完之後試著對某些部分提出你的修改意見(pull request),這麼做的好處是當你的建議被採納時,某種程度上即代表這是一份適合的Code。就算被拒絕通常也都有機會能與其他參與這個專案的開發者或是擁有者有更進一步的交流。

b. 參與開發者社群
雖然這一點本人必須坦承做的不大好QAQ,但是不可否認參與開發者社群是一個能協助你改進自己開發方法及觀念的一大助力,因為在參與開發者社群及聚會的過程中,不外乎會有非常多的機會你能看到別人撰寫的程式碼,與他人能有非常多且深度的交流。

雖然專業領域不同,但很多軟體開發、架構的心法其實是非常類似的。這個方法比較像是你從資深工程師身上獲得20%的心法,利用這些心法搭配上80%有效的方法使你持續成長。其實我覺得對於菜鳥工程師而言,這樣的訓練模式是最直接的。所以我現在的做法是,每當要開始實現一個新的功能時,我會先詢問公司內另一位資深的Andriod工程師,他打算如何實現這個新的功能,以及為什麼選擇這麼實現?提出自己原本對於這個新功能的想法,詢問他這樣的想法有什麼差漏,或是好/壞處在哪。那得到心法之後,方法有哪些呢?

a. Test-Driven Development(TDD)
這是我現在正大量使用的方法,也是我最推薦的方法。一開始你不一定要先嚴謹地遵守TDD,比較像是埋一顆TDD的種子在心裡頭,在實現一個新的功能之前,把這件事放在心上:你要如何寫出一份好測試的程式碼?

若原本的程式碼幾乎沒有測試,抑或是在這之前你從未寫過測試,那面對一個已經長得有一點點肥的專案,應該從何測起?基本上開發者們各有各的看法,統整下來大概分成兩個流派:a. 從此專案的核心功能開始測 b.從接下來會改動到的功能開始測。但我的選擇既不是a亦不是b,現階段我採取的做法即是來自同事的建議:從新的小功能開始撰寫測試

而既不選a也不選b的原因:極有可能原本的程式碼架構本來就不適合撰寫測試。為了因應此情況,你會有兩種選擇:
1. 繞一大圈去寫一份適合原本程式碼的測試:風險是你的測試基於一份有很大改善空間的程式碼,進而造成撰寫測試時觀念或是方法錯誤
2. 重構原本的程式碼使之容易撰寫測試:風險是你有可能會將產品功能改壞,而且你不一定會馬上發現,再加上若該段程式碼牽扯到產品核心功能時千萬不可不慎。

從新的小功能開始撰寫測試,不但能盡可能地減少對專案造成的影響,且從頭到尾建立起較為完整且正確的測試觀念。

關於測試覆蓋率(a.k.a. Code Coverage,即為專案內程式碼被測試到的比例),基本上追求盡可能高的測試覆蓋率是沒有意義的。原因)是:
1. 就App開發來說,有很多是不用被單元測試覆蓋的程式(e.g. DB, API, View...)
2. 而且測試覆蓋率謹代表測試中有跑過某一段程式碼,因此有可能寫出一堆沒有意義的測試但覆蓋率高的程式。
3. 邏輯簡單或是經常性修改的程式區塊不需要追求測試覆蓋率,投入太多成本卻得到很少的成效
按照80/20法則歸納,要完成最後20%的程式測試,會需要花費非常高的成本。因此還是回歸到多少的測試覆蓋率適合公司以及專案。(感謝COLORGY偉大Andriod工程師Eric補充)

b. Think of making it as a module made for people
這個方法來自Carousell的Ben大大,想像你正在實現的這個功能之後可以包裝成一個套件給其他開發者使用,那什麼樣的實現方式會讓開發者容易理解、串接甚至基於你的實現方式進一步擴展?這樣的過程中,也非常有可能會收到來自許多不同開發者的回饋及意見,甚至是協助修改,這些都是能幫助你成長的方式。你可以試著慢慢將ㄧ些在公司內你實作的部分程式碼額外拉出來成一個開源套件,例如你自己設計了一個很方便使用於處理網路層傳輸的Model/Manager,當有一天你選擇要離開原本公司時,這些你所開源出來的套件即可當成你的作品集。畢竟你不可能將原本公司的程式碼通通翻出來給下一間公司的面試官看,而光是從AppStore裡載下你前公司的App也不大能看出程式碼的品質如何,因此這不失是個一兼二顧,摸蛤仔兼洗褲的方法。

總結

交流、交流、交流。這其實是訓練自己工程能力的最基本要求,只是你可以透過很多不同深度、不同面向的方式與其他工程師進行交流。儘管公司內可能沒有跟你專業領域完全重疊的工程師,也會有部份專業重疊的工程師!而如果公司內只有你一位工程師⋯⋯那就乖乖參加當地城市的開發者社群吧QQ

小公司的優點是,你可以對自己的Code有很高的掌控度以及自由度,開發速度較快且敏捷。缺點就是在沒有相對完整的軟體開發流程以及資深工程師的帶領之下,對於軟體部署流程、抑或是實現一個功能的Best Practice、軟體架構導入、Design Pattern應用、效能優化… 有時候想像空間實在非常有限!你很難想像到對於一段程式碼的實現可以有更適合的方式,抑或是現在的實現方式有什麼可能的弊端以及對於未來的可擴展性優劣等等。

順帶一提當時我正在考慮是否要引入新的軟體架構,這也意昧著需要大規模的重構,但大部分的時候,你不應該大規模重構軟體架構,而是基於現階段實現的軟體架構之下,逐步的做微調,若是想要嘗試導入新的軟體架構,也應該從新的小功能開始慢慢實驗,亦或是另外拉出一個小專案來嘗試。這樣的心法是不是非常類似?沒錯,就像是我們剛剛提到如何從無到有開始撰寫測試那樣!

絕大部分情況下,公司都會有相同專業的資深工程師帶領,再加上大部分足夠厲害的開發者都很會Google,大家一定有能力找到一個合適的方式訓練自己,只是時間長短和方法的問題而已。因此這篇文章很有可能也是淪落到一個沒人要看的下場(?),但還是為了自己或面臨類似挑戰的人留下一個短短的紀錄,讓大家能少走點冤枉路。

尤其對新創公司而言,沒有所謂好或不好的程式碼,只有適合或不適合的程式碼。

套句Mark Zuckerburg大大所說的話就是(感謝COLORGY神級後端工程師Yung補充):

DONE IS BETTER THAN PERFECT

參考資料:
Three CTOs Answer: What Is Good Code?
What Code Quality Metrics Should Management Monitor?

--

--

iOS Software Engineer in Berlin

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store