當工程師十年的心得感想
從 2010 年底開始當工程師到現在,不知不覺也過了十年。回想起來在過程當中,有些事情我覺得很幸運地做對了些什麼。它們都是些看起來簡單的道理,但做起來有一點眉角。在這篇文章裡,我把這些記錄下來跟大家分享,讓這份幸運的果實可以傳遞出去!🤗🤗🤗
設定目標,動態的那種
想像你在買早餐的時候,老闆突然問你說:「帥哥,現在在你的工作上,你的目標是什麼呢?」你會怎麼回答呢?
回顧過去,我認為「要隨時可以回答這個問題」這個要求,是我在很多地方學習成長的開始。當然,每個人對於「設定目標」的想像都不同(畢竟它太像新年新希望了),這邊把我自己的版本,和它怎麼幫助我的分享給大家。
在工作一年,原先的團隊以結束收場之後,我的目標是:成為一個獨當一面的工程師。在面臨生死存亡的團隊下工作,是一個充滿壓力但很棒的學習。當時我們努地想找尋各種存活下來的機會,但卻苦於各種過去、現在的技術瓶頸而無法前進。我第一次見識到:阿!原來這就是 code quality 的重要性阿。所以在加入下一個團隊的時候,我想要成為「可以建立很好維護的 code base,可以解決各種問題的那個人。」當然,以現在的標準來回顧,這個想法似乎太狂妄了點。但當時的我,從這個目標出發,開始想「我現在跟這個目標差在哪裡?有哪些是我知道我不知道的事(known unknown),又有哪些是我不知道我不知道的事(unknown unknown)呢?」於是我想知道怎樣是好維護的 code、怎樣是可以容納改變的架構、為什麼看起來單純的事總是變得那麼複雜、為什麼 PM/Marketing 和工程師常常是對立的?這些疑問幫我鋪了一條學習的道路,通往各種軟體工程的知識,進而朝向「獨當一面的工程師」前進。
在加入 Codementor 之後,當時的我們是個小團隊,最大的目標是希望高速成長。當時我的目標是:在沒有特定 title 下,成為一個 10x 工程師。我希望透過我的加入,可以讓這個工程團隊的生產力變成 10 倍。於是我開始探索,是什麼讓工程師的生產力無法和人數線性成長、為什麼有些明明理論上看起來很好的作法,但大家總是抗拒。當然這指向了更多的軟體工程知識,還有一些心理學、行為科學等等。於是在這個環境下,我們嘗試各種東西、量測成果、調整作法。
隨著團隊的成長,我扮演的角色也有所調整,成為了帶領工程團隊的人。我的目標變成了:塑造一個「沒有我也可以自我成長的團隊」。於是乎,要怎麼了解每個人的想法、每個人是怎麼做決定的、為什麼在同樣的動機下卻還是會指向衝突的結果等等的這些問題開始出現。這指向了更多管理的知識、更多抽象的「做出決定的思維模型(mental model)」等。同時更重要的,先前那些工程的知識開始發酵,我開始體會到原來軟體設計的很多核心概念,像是 low coupling/high cohesion、TDD 中的 feedback loop 等,其實在團隊的運作上也派得上用場。
透過上面這些,想傳達的並不是說我設定的目標內容好或不好。而是想說,
- 隨時有個明確的目標,可以讓我們隨時問自己:我現在還差多少、差在哪、為什麼。於是我們可以有個前進的方向。
- 團隊、時機等環境因素,對於人的目標設定有決定的影響。常常是環境遇到了某個問題,所以讓我們有了機會去探索並練習。所以在「環境」跟「個人目標」當中取得平衡是一個重要的課題,也是考量轉職的一個重要因素。
- 理想上,團隊會前進,然後會遇到新的問題,於是我們的目標常常也會演進。定期去檢視自己的目標,我覺得是重要的事情。換另一個角度,如果我們現在的目標跟三年前的一模一樣,那我們可能可以想一下發生了什麼事。
在往前進的路上,有個很重要的關鍵是「學會我們現在還不會的事情」。運氣好的時候,我們會有些前輩在前面帶領我們。但更多時候,我們要靠自己摸索出一條路。這是我第二個想分享的點:學習。
學習,有策略的那種
我們都知道,如果每天變厲害 1%,一年之後就會變強 37 倍。但是我認為比較難的部份是:有這麼多東西,我該學什麼?該學多深?
在這之前想先跟大家分享,我覺得不同類型的主題,往往可以在意想不到的時候產生連結。想像我們學會單一個主題後,我們得到了一個點。但是如果有不同領域的學習,這些點就會連成線、網,進而產生更快的連結。
再者,學習是一件複利成長的事情:當我們學會越多東西,我們可以學得更快。因為我們腦袋裡面可以拿來 pattern matching 東西越多,在面對新的知識的時候,越有機會類比之前學過的東西,而只需要專注在不同的地方就好了。所以長期下來,有持續在學習的人的速度會比沒有的人快上許多。
該學些什麼呢?該學多深?
在我們找到自己現在跟理想狀態的差距後,下一步是想辦法透過學習去達到這個目標。那該怎麼選擇要學習的主題呢?或者說,該怎麼決定它們的優先順序呢?我的方法是,把各種主題用「和核心專業的相關性」跟「理論 vs 實作」兩個維度分類。
其中越高相關度的主題,越可以直接為我們帶來幫助。但通常是那些比較低相關度的東西,可以在意想不到的時候有神來一筆的連結。越偏向實作的東西學了可以直接拿來用(像是 library/programming language等),而理論的東西則像是內功一樣,可以延伸到更廣的領域,也可以加速其他東西的進步速度。
好比說如果我現階段的目標是成為「獨當一面的工程師」,那麼「React」或「Ruby on Rails」就是「和核心專業高相關」並且「和實作高相關」的主題、「演算法」就是跟專業高相關,但比較偏向理論類型的知識。而統計學則是和核心專業比較遠一點、偏向理論的類型等。如此一來,我們可以把各種知識甚至每一本書、每一個課程,放在這個二維象限的某處。
有了這樣的框架之後,通常我會記錄一下最近學的東西、讀的書,儘可能在每個象限都有一些發展。當然還是要看自己的興越啦。另外,特別是第四象限的東西很需要實際的應用情境。所以如果最近剛好用到某個不會的東西,好比說有個新專案要用新的程式語言,那趁機把相近的知識學起來會是蠻有效率的做法。
至於深度的話,我自己的做法是,首先先以使用情境為原則出發,在學習一一個東西之前,先有個想像:我預計我要可以做到什麼事情。好比說我想對統計學有更多的了解。以一個電機系出身的門外漢來說,我希望可以做到的程度是,在利用 data 做決定的時候,可以知道自己在幹麻。像是「做 a/b Testing 時候,要多大的 data 量 + 多少差距,我們才可以放心的斷定某一組比較好而不單只是巧合呢?」、又或者像是 Selection Bias、Base Rate Fallacy 這類的問題。要了解這些,其實不用成為統計學大大就可以有個基本的概念。更重要的是,有了這些基本概念之後,我們可以在正確的時機會認知到:阿!這個地方是因為我的統計學深度不夠,把 unknown unknown 轉變成 known unknown,於是我們可以有進一步的學習方向。
最近三年多來開始用這樣的步調和選擇方式,加上帶小孩、打電動、跟小孩一起打電動,我一年大約讀 25 本書左右。以量來說絕對稱不上是多的,但即使在這樣普通的量之下,就已經可以感受到不相關的知識發生的正向交互作用。類型有各式各樣,像 Software Architecture, SRE, 教養小孩的書、心理學、統計、莊子(對,我個人很愛)、管理、溝通等等都有。通常 Amazon 推的都還蠻準的。喔對了,如果可以的話,我覺得看原文的書通常可以得到更精準的知識。身為在台灣土生土長的台灣囝仔,我看英文也不是特別快。但我個人的感想是,特別是在技術領域的書,看原文的版本的好蠻多的,很鼓勵大家試看看!
用工程師的方法切入問題
這幾年來,另一個點我覺得體會蠻深的就是:工程師的訓練可以用在蠻多工程以外的地方的。特別是切入問題的方式。這邊我會一一列出。
對付變化
大部份的時候,我們在軟體工程上做的努力都是為了應對變化。可能是可以預期的變化(像是「下星期有個 marketing campaign,預計會有三倍的 user 在某段時間內湧入」),或者是不能預期的變化(好比說 AWS 突然倒掉兩個小時)。所以我們做各種技術決定的時候,常常以「假設某個變化發生了」為出發點,來探討一個決定的好壞。好比說我們想要用某種方式實作「用 Stripe API 付費」的功能。要檢視這個做法的好壞,我們常用的作法會是:假如某一天付費的人突然變多三倍、假如 Stripe 的 API 突然倒掉、假如 server 在付到一半的時候被重開…等等的各種「變化」,來在腦中壓力測試一個想法的優劣。
而這樣的概念,其實在做各種技術以外的決定的時候也蠻實用的。例如說「現在 PM、設計師、工程師的合作方式是好的嗎?」我們可能可以用「如果今天是在產品前期探索階段,那人力會有閒置或是瓶頸嗎?」、「那如果是在實作階段呢?」「如果工程師的量變成現在的兩倍呢?」等等各種我們想得到的變化,去驗証一個決定或現況的好壞。
用科學方法(Scientific Method)去解決問題
所謂的科學方法的概念是,在面對一個問題的時候:
- 先建立一個假設
- 設計並執行一些實驗,去驗証這個假設
- 如果驗証失敗了,那我們來分析失敗的原因。接著回到第一步,修改我們的假設。
其實仔細想,大部份我們在 debug 的時候就是用這樣的方法去解決的:為什麼程式的行為跟我想的不同呢?在看了 code 之後,我猜是某某檔案的某幾行(建立假設)。接著我把 code 改了一下,跑測試(做實驗)。如果測試的結果是 bug 沒有被解決(實驗失敗),我們再回頭看一下 code 找看看其他地方(修改假設)。
而這樣的方法其實也可以用在很多工程以外的地方。倒不是說這個方法本身有什麼神奇的魔法,而是如果我們有意識的問我們自己或團隊:「在解決這個問題的時候,我們的假設是什麼,我們怎麼去驗証我們的假設?」這樣的過程會避免掉很多溝通的困難,像是「我以為的假設是你認為的客觀事實」這類的。而在問我們自己「我們怎麼驗証這個假設」的時候,也可以避免決策者不小心的「我就是覺得這樣」的通靈行為。
假設我們今天有個產品,在某個市場 A 的表現很棒。於是我們想要切入另一個市場 B,因為我們認為市場 B 的競爭者很少,而既然我們在市場 A 的表現那麼棒,那麼進入市場 B 一定沒問題。再加上如果把現在市場 A 的表現帶入 B 試算的話,那公司的營收簡直一飛沖天發大財!所以我們做出了一個決定:現在所有人放下手邊工作直衝市場 B!
上面的每句話都有可能是對的,在一切都如我們預期的狀況下。但是我們要撩落去之前,可能可以先認真拆解這些因果關係中,哪些是事實,哪些是假設:上述的故事裡,我們假設了「現在的產品在市場 A 表現很好,它的成功可以被帶入市場 B」,甚至我們也假設了「市場 B 是真的存在的」:會不會競爭者很少的原因是因為這個市場根本就不存在呢?或者是有什麼更根本的問題沒有被解決呢?
而在我們透過科學方法去定義出假設、實驗、驗証方法後,我們可以更有意識地透過建立產品或其他更快的方式,先驗証這些假設,或者提高我們對這些假設的信心。讓我們不會在投入大量成本之後發現是誤會一場。
寫在後面
上面差不多就是我覺得這幾年來很幸運可以體會到的東西。而跟世界上大部份的事情一樣,它們絕對不是唯一的方法,而只是在特定狀況下的眾多解法的其中之一。而比幸運更幸運的事,則是從離開學校開始上班到現在,每一個待的團隊都給了我很大的空間去探索跟體會這一切。我相信任何人在任何團隊下的學習或成就,絕對不只是由個人就能完成的,而是那個人和所處環境的交互作用下而產生的結果。
希望這些對讀這篇文章的人有一點點幫助,也希望下個十年後的我自己回頭看,會覺得「矮由,這些東西也太基本了吧!」