祖傳代碼與組織知識的傳承
在矽谷這邊許多公司宣傳說要工程師兩年換一次工作,像是領英平均年資是兩年多,滾石不生苔,理由是兩年換一次工作,學到的東西才多,進步的才快,我年輕的時候也真的就兩年換一次工作,做了許多不同的東西。
不過年紀漸長之後又發現,不管你學再快,真正在公司內有生產力,是一年之後的事了,當你了解公司的程式架構、商業模式、內部人事後、與團隊磨合好後,才真正的能夠達到高生產力,這時已經一年過去了,那為什麼公司要宣導要這些有高生產力的員工離開呢?
我認為一部份的原因是要減少「祖傳代碼」(Legacy Code)的數量,寫程式不管一開始的架構設計的再精良,免不了在種種的變更之後,開始出現一些不是那麼精良的部份,尤其是在「微服務」的架構下,兩個服務的溝通,可能一開始是在同一個主機上,像是帳號系統跟帳務系統,一開始是在一起的,但是後來才切開,在前端上還是假設兩者資料是同部的,但是在後端的實作已經是非同步,中間透過某種機制來交換資料,有時候為了趕上線實程,就會有很多「秘密的握手方式」來交換資料,像是兩個微服務對同一個資料庫做讀寫,這種「秘密的握手方式」通常只有實作的工程師會清楚兩者是怎麼互動的,只要人一走,那麼這個特殊的運作方式就沒有人清楚了。
「祖傳代碼」的時間越久,這種秘密越多,那麼要避免這個狀況產生,只有兩個方式解決,第一個是有超低離職率,第二個則是高離職率不斷的重寫程式碼。第一個方示是不切實際的,不管怎樣員工都是會走的,降低離職率只是延緩災難的產生,一個七個人的團隊,在兩成的離職率下,五年後可能只剩一個員工還在那,領英我在的部門的離職率在 18% ,我進去的時候部門已有二十多人,但到我三年半離職時,只有五人還在同一個部門。降低離職率,避免土地公土地婆離開團隊,在經營管理上是不切實際的。
另一個方式則是不斷的重構代碼,每五年就重寫一次,說的好聽一點是要清除技術債,但是從管理階層的角度來看,是把「組織知識」的傳遞做個總檢驗,雖然每一個新系統在開始前,都會寫「設計文件」(Design Doc)並交由團隊做審閱,除了看看設計有沒有問題外,還把這些知識傳遞給部門內其它的工程人員;然而在專案一直進行的狀況下,這些設計文件不免跟不上現況,甚至是許多的實作細節在設計文件上是沒有的。
例如: Scala 這個程式語言的規則書有 200 頁左右,但是跟據 Scala 編譯器的維護者 Paul Philips 的說法,語言的規則書只有寫清楚九成的規則而以,有很多細節是他在實作時制定的。例如 Scala 的
Map
有toList
這個函數可以使用,而List
上也有toMap
可以呼叫。但是Map
的實作有HashMap
跟TreeMap
兩種,在TreeMap
上呼叫toList
產生的東西的排序是如何?在TreeMap
上呼叫toList
.toMap
後,傳回來的Map
該不該還是TreeMap
呢? 這種規則不會寫在規則書中,但是在實作上會被做進去,而且只要公開給大眾使用後,就變成不成文的規則,不能再修改了。某銀行用的密碼產生器裡面有一行 sleep 1ms 的程式碼。接手維護的人,因為銀行業務一路從地區小銀行變成全國性的銀行,系統碰上瓶頸,一路追到這一行來,想不通為什麼要這麼做,於是把這一行拿掉,把系統的效能增加了數百倍。 沒想到過了幾個月後,發現有許多客戶的帳號被入侵,問題是什麼呢?問題是 Linux 的亂數產生器的最小維度是 ms ,在同微秒內跟 Linux 要亂數,要回來的亂數是有規則的。
要減少這些「祖傳代碼」在變動時產生的風險,只能夠靠不斷的重寫,在團隊的土地公土地婆還沒有離職前,強迫整個團隊重寫一次專案,把專案的細節一個個拿出來檢驗,把知識傳給新人,才能夠避免「組織知識」的流失。