又過了一年了, 2018 年只在這個部落格零零落落地加了幾篇文章,感覺自己似乎沒什麼長進。最近寫作的機會大多是在專案的文件上,對於技術知識的研究與自己內心的探討變得越來越少,所以應該是來寫篇心得感想的時候了。

老實說原本打算寫篇年底回顧,不過整理了一下手邊的隨手筆記和平常記在 Facebook 上的資訊後,發現想講的東西太多了,就隨性想到什麼寫什麼吧。

2018 年做的事

先粗略地記一下我在 2018 年做的事情:

  • 花了一年跟功能團隊完成了一起聽專案的新功能。
  • 將原有排程程式改成在 Docker 上運行的 Daemon 服務,以求更即時的反應。
  • 開發讓 Laravel 專案能跟公司設定檔系統更易接合的套件。
  • 建立內部服務串接系統,增強佈署後自動化測試的機制。
  • 改良了數個內部用獨立套件的架構,使其更易擴充。
  • 為大部份專案補齊缺少的文件。
  • 舉辦了程式碼研習會,學習一些值得借鑑的程式架構或寫法。

不過如果要把 2018 年的事做個簡單的文字總結,那應該就是「改善」。而「改善」不光只在技術層面的變化,同時也有持續維運的改良,以及思維觀念的調整。

我們團隊經常在微調程式架構,目的就是希望能因應不斷變化的需求,讓程式可易於維護。這些調整不僅只是應用程式層級,也包含了底下的輔助用套件。我們會花一些時間去討論怎麼設計架構才會好維護、程式介面才會好用;最重要的,是要讓團隊理解每個設計會有什麼優缺點,而不會止於「會動就好」的心態上。雖然前期投資了很多時間,但事實證明這些決定都幫我們節省更多時間。

除了自己手邊的專案外,跟其他部門合作上的改善也是重點。為了讓我們的專案佈署上線後,能夠驅動後續讓 SQA 能進行自動化驗證的步驟,我也做了個簡單的內部服務串接系統。這個系統活用了許多 Laravel 提供的機制,也讓我重新複習與學習不少前端開發的技巧。由於 BDD 目前已經內化成我開發時的流程了,所以這個專案在後端程式的部份我也是用 BDD 開發;但是 BDD 工具的部份我一直不太滿意;在花了一些時間研究後,終於被我找到還不錯的方法。

說真的,不管哪一項「改善」都很花時間,只是我們都是抓緊一些空餘時間來做改善;我們不求一步到位,而是一點一點地累積;因為今天你不做,明天你就會後悔。

那些對程式開發上的體悟

2018 年我對程式開發有一些新的體悟,雖然大部份都是軟體界很常聽到的觀念,但自己在實務上體會之後又是另一種不一樣的感受。

架構

我常常問自己:除了框架幫你定義好的架構外,你有辦法設計出能適應業務邏輯變化的架構嗎?

架構的彈性不是保留下來的,是隨著需求調整出來的。如果不時常從需求的源頭審視架構的設計,而一直頭痛醫頭、腳痛醫腳地 workaround 下去,軟體的腐敗將是可預期的。另外系統架構本身也跟程式架構有密切關係,很多時候 SRE 採用的方案也會間接地影響到我們怎麼去設計程式的架構。所以該擔心的不是需求與底層系統的改變,而是架構的模組間沒有做好隔離所導致的抽換困難;簡單來說,如果無法從某個點切開後,調整其中一邊而不影響整個服務,那就是有問題的架構了。

所以身為設計架構的人,必須學會從需求中理出一個易懂的規則,進而調整出易於實作與擴展的架構;而不是看到一個新需求,就在原先的架構樹中長出一個雜亂的分支。專案的起頭沒有將架構設計好,未來改架構所要花的工真的很大;尤其當同事已經照著這個架構寫出不少新功能的時候,得重頭理解同事的程式碼來重構它們。

測試

不得不說我們團隊已經把自動化測試 (大多數是後端) 列入標準開發流程了,至於是不是用制式的 TDD 流程來開發並不是那麼要求,重點在於我們寫的測試有沒有驗證到需求所要的結果。每次幫伙伴 code review 時,只要看他的 merge request 描述與測試是否符合,大致上就能確定該情境的程式碼邏輯對不對。

當然測試也不是萬靈丹,總是會有些情境你沒考慮到。有一次我發現某個主專案在更新了某個內部用套件的新版後,意外的導致程式反應速度變慢;一開始以為是系統效能不彰,後來追 code 追了兩個多小時才找到 bug 所在。這個套件有新舊兩個類別,舊類別是針對 legacy project 寫的,新類別是針對新專案寫的。而針對舊環境寫的類別,測試過,完美;針對新環境寫的類別,也測試過,完美。但問題就出在主專案在把套件裡的兩個新舊類別混在一起用,結果發生衝突。所以我得到一個心得:就算單元測試通過,也永遠不要預設別人會怎麼用你寫的程式。

Bug

在一起聽新功能上線的這陣子,我們很常遇到一些只有在上線環境才會遇到的 bug ,這時候才體會到什麼是:「 Log 到 debug 時方恨少」。像 2018 年最後一個上班日,我們就從 log 中找到某個 bug 的成因;伙伴也重新 review 程式碼裡相關的邏輯,終於在放假前把 bug 給解決了。

Bug 跟測試也是息息相關,我們在解一些只能在上線環境重現的 bug 時,會講求以下原則:

先求不傷身體 (不破壞原有功能) ,再講求藥效 (真的有解決問題) 。

也就是無論如何,我們所做的任何修正都不可以讓原有的測試失敗;換句話說,原有的功能不可以沒有測試!沒寫測試的程式 debug 起來就像《醉後大丈夫》中的劇情:隔天來上班的你只能從 log 裡的蛛絲馬跡中去一一回想你昨晚下班前到底做了什麼才導致這個 bug ,因為原有的程式碼邏輯已經不是你預期中的那樣了。

還有就是別幹蠢事。有次 QA 反應了一個 bug ,聽起來是後端這邊的問題;所以 PM 就問我們怎麼回事,我就想這上次不是修正了嗎?結果一查,有人幹了蠢事了 (就是我) 。後來開會時我把修正的方式告知了 PM 後:

「聽起來修正後的邏輯應該沒問題呀?」

「嗯,問題是它一直躺在測試環境沒上線。」

文件

2018 年也不時地在還技術債,其中一項就是文件。其實在寫文件的過程中,同時也是在檢討自己過往那些不成熟的思維。當初可能是因為專案趕時間,可能是因為邏輯不夠嚴謹;可能是因為想說口頭交接一下就好,可能是因為當初沒想過這玩意會變成大家都要用的東西。但無論如何,如果不能留點東西來讓別人瞭解自己做的是什麼,那你的成果到後面就變得跟垃圾沒什麼兩樣了。

只要是一家公司,人都會來來去去,在公司裡任何活著的程式不可能只靠一個人來延續它的生命。程式開發本來就不是我做一半你就能馬上接手繼續的事,其中的脈絡如果前人沒有保留下來 (註解、文件、測試) ,那麼我們就得花時間從頭看程式碼;而且就算看完所有程式碼,也不能保證就能理解當初為什麼要這樣寫。

永遠不要相信上星期五的自己有留下完美但未完成的程式碼給星期一的自己。程式之神可以保證當你過了個快樂的週末後,一定會忘了你上個星期寫了什麼玩意。所以就算只是寫給自己看的註解,也要記得寫下當初為什麼要寫這些程式碼。

如果有寫時間寫文件,那麼文件到底要寫些什麼呢?可以回想一下你從頭打造這個專案時的歷程,有哪些該注意的地方,有哪些該連絡的人;這些摸索的路徑,這就會是你新專案的文件大綱。然後調整心境,抱持著以往自己接手前人專案時的心情來寫,才不會覺得寫文件是件浪費時間的事,因為我們可以幫未來的自己活得更輕鬆。

那真的沒時間寫文件怎麼辦?而且這時候 TDD 就能派上用場了,那些針對情境所寫的測試案例,正好可以協助我們回憶這些程式碼的邏輯。就算用沒時間這個藉口不寫文件,測試案例多少也能算是我們在這個專案上對文件的掙扎。

今天的你,也許可以幫三天後的自己或接手你程式的人多做點什麼。

部門的伙伴們

必須說,我一直很慶幸我身處的部門是一個很棒的技術團隊;雖然我在部門裡扮演的角色是代理 leader ,但現在我們小隊成員已經可以接到任務後自動動起來了,該做什麼都很清楚,不需要我介入太多;而且遇到問題會自動自發地找大家一起討論來一起想辦法解決,而不再是埋頭自幹。事實上,我一直覺得我們部門的伙伴們有幾個不錯的特質。

理解自己打算要做的

每次收到需求,我們不會太早跳入細節,而是先仔細討論它的合理性以及影響範圍;多數時候我們可以花比較少的力氣去完成需求,而不會因為需求的不確定性而改來改去 (當然還是有機會發生修改) 。

像我的伙伴常會先把他對需求的理解做個整理,然後附上他認為可行的解決方案,最後請整個技術部門一起審視與討論。我的伙伴們就是可以這麼用心看待每項交予他們的任務,這就是這個團隊讓我很安心的原因。

持續改善已經做過的

我的伙伴們很棒的一點就是不會滿足於現在能動的程式碼,他們會在測試的保障中去尋找更易維護的方法來改善程式碼。改善的時機不限於程式上線,也會在開發中、 code review 時找時間做。

當遇到需求與現在架構衝突的狀況時,他們就會立刻思考並討論現在架構的缺點,進而提出改善的方案。接著就會跟 TPM 商議並安排時間來進行,完全沒有「這邊 workaround 就好」的想法。

不侷限在需求想做的

我們有時會做一些協助開發的小工具來讓團隊使用,而不是需求要什麼我們就只做什麼。乍看之下我們花了很多時間,但整體來說團隊會節省許多時間。

像是在做一起聽新功能時,我原本打算自幹一個提供給 client team 測試用的小工具;沒想到前端同事主動幫忙,才一下午就做出超乎我想像的介面了,而且這還包括了他研究了某個 UI framework 的時間!

勇於挑戰從沒做過的

曾經有個需求要用到一個我們不熟悉的技術,但我的伙伴們從研究、討論、製訂規格到實作完成並上線,前後只花了兩個星期的時間,而且品質也好到沒話說,由此就能知道他們真的很用心在面對自己的挑戰;這背後不論是他們堅強的實力或是敢於冒險的心態,都再再呈現出這是個能獨當一面的團隊,叫我怎能不愛他們呢?‬

‪然而我也不是把工作一股腦塞給伙伴,以下都是我一直嘗試去做的方向:

  1. 要先瞭解伙伴們是否有興趣與時間研究更深入的技術。
  2. 交接不藏私,任何自己想過的,研究過的都儘可能交代。
  3. 交接時也可聽取伙伴們的想法,找出自己的盲點。
  4. 伙伴想怎麼做由他,但要讓伙伴瞭解優先序。
  5. 相信伙伴能做好,少干預。

其實凝聚伙伴的向心力遠比學習技術還要難,當你身處一個優秀的團隊後,就完全不會想離開它了;這大概是我進 KKBOX 之後,最大的收穫之一吧。

一個真正的團隊

每次看到同事們在討論技術或是解決服務上的問題時,就會深深覺得自己真的只是個能力有限的小螺絲;如果沒有身邊及其他部門同事們的幫助,而是像以前一樣自己一個人從軟體架構設計、前後端程式開發到底層服務建置一條龍做完,所要花費的時間和精力不知道有多少。

2018 年花了一些時間記錄了一些跟團隊有關的點點滴滴。

讓團隊維持熱情

有時工程師提出功能逐步上線的建議卻很少被採納,常常是做完一大包後才上線;這不僅僅是曠日費時,而且常常會因為市場的變化使得這些努力白費。這樣一來只會打擊整個團隊的士氣,讓團隊漸漸對產品失去熱情。

某同事曾經說過:「我們不是沒有 Agile 精神,我們是沒有精神。」

其實不管有沒有 Agile ,團隊需要的是對於工作的熱情,對於產品的熱情。而這樣的熱情,必須從上而下地傳達,讓團隊成員明白自己的努力成果是有機會被使用者看見的。

要形成優秀的產品,別只做做敏捷的形,卻沒有貫徹敏捷的意。

那麼如果團隊有的是熱情,卻不知道該怎麼做時怎麼辦?就做給他們看呀,願意成長的人就會做得比你更好。在團隊裡我不是最厲害的一個,但我會儘可能把基礎建設做好,讓大家知道怎麼去打好根基,並設計出更棒的架構。或許我們可以用高額的薪資吸引到優秀的人材,但卻不見得能創造出優秀的團隊。只有信任及以身作則才能讓團隊成員願意更積極地去展現自己的自主性,因為他們知道自己的背後有其他伙伴可以信賴!

看得見的會議共識

偶爾在開會時,會看到有人講完簡報後,就要大家開始討論;但老實說這種會議很難達成共識,而一個沒有共識的會議只是浪費大家的時間。那麼該怎麼讓大家有共識?方向很簡單:創造讓大家能提出自己看法的機會,同時也讓每個人都看到彼此的看法。

曾經在年初組織的功能團隊裡,遇到一個技術問題需要討論;這時我試著利用白板加上文件的投影,讓大家對實作細節、問題釋疑還有規格的確認都有了共識,結果這個方法讓整個團隊在一個小時會議中搞定了三個問題。事後在檢討會議上,團隊裡負責實作 client 的成員也對這個方法非常讚賞。

我個人用的方式並沒有參考哪一種方法論,我只是思考了一下怎麼在白板上傳達大家的看法比較合適。但我個人還是建議學習一些相關的知識,例如「看板方法」或是參考像是《引導者的工具箱》這類書籍裡的技巧;當然,也要學著活用這些技巧,而不是照本宣科地去做。

面對變化

提起軟體界的需求改變,我想大概可以回想一下二師兄所講過的一些話。

前天他說:「從數據來看,我們的產品畫面應該要針對個別使用者做客製化!」

昨天他說:「我希望每個畫面的呈現都應該統一,這樣才有一致感。」

今天他說:「不要管數據說什麼,我們應該主動找出最好的使用體驗提供給使用者!」

剛剛他說:「別管什麼使用者體驗了!趕快想辦法給我衝註冊會員數!」

有時候需求的改變不是來自於使用者,而是人在無助或想不出好方法時產生的奇怪念頭,當然這些不論公司大小都有機會發生,而身為團隊的一分子,就必須適時地給予建議。

不過人生總是有無奈的時候,既然要吃,那就用自己的方式吃吧,總不能讓自己對於程式開發的熱情也沒了。

第一步我們從程式面下手,我們善用了框架的優點來建立良好的基礎架構,多數需求的變化都可以在很短的時間調整過來。第二步我們不再單方面接受 PM 傳達過來的解決方案,而是直接聆聽需求方的問題困難點;而直接聽完之後所想出來的方案,都遠比原來複雜很多的解決方案來得簡單又符合要求。這同時也給我一個新的體悟:

別一直覺得要用自己知道的專業來解決問題,要想想有沒有其他專業能夠解決同樣的問題。

很多時候利益關係人 (stakeholder) 都是三心二意的,或是想到什麼告訴你什麼,所以一定要好好思考他們問題的本質,你提出的方案才能真正解決他們的痛點。不過更麻煩不是每個利益關係人都有同樣的需求,很有機會這個需求是 A 想做的,結果在 B 那邊是會出問題的。所以原則上有個重點要保握:

‪每個需求都要確認利益關係人買單,‬‪避免實作完成後才發現有人不喜歡。‬

還有一種情況是 PM 給了超級複雜的規格文件 (PRD, Product Requirements Document) ,你做完條件 A 後,才發現跟條件 B 有衝突。然而要避免這個問題,一個很重要的方法就是請 PM 給實例。

與其把 PRD 寫得花花綠綠,不如表列出各種情境的實例。

這麼一來在討論需求實例時就發現 bug 的成本,遠比實作完才發現 bug 的成本低得多;前者可能只需要幾句話解決,後者可能要花幾個人週才能解決。

對自己的期許

2018 年其實我的倦怠感有點重,參與社群活動的意願也不高,很多時間都花在調適自己的心情上。會這樣的原因有很多,但我自己認為對產品新功能目標的不認同可能是主因之一。不過跟著一群好伙伴工作,多少沖淡了我被這些負面狀態的影響。

接下來的 2019 年,我期許自己做到這些:

  • 調適自己的心態,讓自己能更積極地看待事物。
  • 訓練自己的寫作與講話更有條理。
  • 把買的書看一看,把買的遊戲玩一玩。
  • 不要只問自己問題,還能要講出自己能接受的答案。
  • 學習新的東西,不要只侷限工作上的技術。

最後,再給自己一次這段話:

不要因別人做了什麼所以跟著去做什麼,‬而是要自己想做什麼所以用心去做什麼。

‬‪然後,成功了會有快樂,失敗了也會有體悟。‬

寫著寫著,年就在我手指敲擊中跨過去了。

新年快樂。