Culture
(圖片來源︰Scott Beale)

前言

去年在 Quora 上看到一個有趣的問題︰Software Engineering: What makes a good engineering culture? (是什麼造就了好的軟體工程文化?),那時候看到大家投票第一名,由前 Quora 工程師 Edmond Lau 所回答的答案,覺得非常不錯。也有在 Blog 有做分享︰[Quora] 好文分享: 是什麼造就了好的軟體工程文化?

距離那時候已經過了一年多,最近總算有點動力,想說乾脆來把整篇答案內文給完整翻譯出來好了,順便在翻譯的過程中,把答案中的一些作法,和自己過去一年的心得做一些印証。

因為原文的答案有點長,所以翻譯上也分成上、下兩集分別翻譯。本文為上集,下集應該最晚會在下週貼上來 (事實証明跳票了...)。當然英文好的朋友,也可以直接閱讀原文,不用再等翻譯。

一樣有任何翻譯上的謬誤都歡迎提出喔!

翻譯正文

在面試工程師時,我最喜歡問的其中一個問題是︰請面試者告訴我,他們在前公司工作時,最喜歡和最討厭的工程文化各自為何?在經歷了幾百人的面試經驗後,這個題目讓我了解到,一個工程師想追求的好文化、想逃避的壞文化各自為何?我自己也在回顧了過去六年在 Google、Ooyala 和 Quora 等公司的工作經驗後,萃取出一些團隊可以用來建立工程文化的準則︰

一、迭代速度的最佳化 (Optimize for iteration speed)

快速的送代速度可以提升(工程師)對於工作的動機和激情。在我面試的過程中,使得來面試的工程師想離開目前公司,最常見和令人沮喪的理由,常常是原公司在基礎建設和官僚上的種種障礙,阻礙了程式碼的部署和功能的上線啓用。

從組織的角度來看,快速迭代的速度意味著給予工程師和設計師(足夠的)靈活性和自主性,可以對一些每天都要遭遇的問題做出決策,而不需要尋求主管的核可。之前當我在 Google 工作時 (譯註︰原作者之前在 Google 的 Search Quality team 服務),所有會影響到用戶看到的搜尋結果的功能變更,即使是低流量的實驗,也都需要等待 Marissa Mayer (譯註︰前任 Google 副執行長、現任 Yahoo! CEO) 在每週 UI 審查會議上的批准。

不消說,這樣的舉動可以讓 Google 保護其品牌名譽,但這種方式也會顯著地阻礙創新。優化迭代的速度也意味著,對新產品的上線有良好定義的流程,使得新產品不會在大量的時間投資後,被無預警的取消上線。(譯註︰意思是像這種低流量的 A/B testing,也應該在一開始的上線流程中被定義,不需要每次都申請許可)

從基礎建設的角度來看,優化迭代速度意味著以快速部署流程 (fast deployment process) 來建立持續部署 (continuous deployment);以高測試覆蓋率來減少構建和站台的毀損可能;具備速度快的單元測試,讓工程師可以快速執行它們;利用快速、增量編譯和重新加載,以減少開發時間。其中關於持續部署的技術 - 也就是在程式碼後,就立刻將程式部署到線上環境 - 特別值得一提。

之前我在 Quora 使用此技術,這技術的好處對我來說一直很難內化,但它提供了與站台損壞的風險相比,利大於弊的迭代速度提升,至少對於小工程團隊來說更是如此。人們對於新功能的開發更興奮,對於臭蟲的修復更覺得受到激勵,因為很快就可以看到因為程式變更所帶來的流量變化。這種部署方式,跟歷經數週的大量程式開發,再將程式部署上線相比,也讓系統在出錯時,更容易在有限的系統提交中,推理和精確定位出錯誤的原因。

從團隊的角度來看,快速的迭代,意味團隊擁有一群強而有力的領導者,來幫助協調和推動團隊的努力。關鍵利益相關者(Key stakeholders) 需要快速的做出決定,並提交他們的選擇。在此我引用 Bill Walsh - 帶領 49人隊贏得 3 屆超級杯的名教練 - 的話︰堅強的領導者需要「提交,引爆,回復」(commit, explode, recover),這表示領導者應該要提交一套攻擊計劃,確實地執行它,然後針對結果做出回應。一個團隊如果過度優柔寡斷,將只會導致個人的努力化為烏有。[1]

二、不停地朝自動化方向推進 (Push relentlessly toward automation)

Instagram 聯合創始人 Mike Krieger 在他的 "Scaling Instagram" 技術座談中提到,「為最小化作業負擔做最佳化」(optimize for minimal operational burden),是他和他的 13 人團隊,在擴展他們的產品以達到千萬級用戶量時,所學到的重大教訓。[2]

當產品開始增長時,加諸在每位工程師身上的作業負擔也會跟著增加。(工程師的作業負擔) 可以用戶數與工程師數的比例,或是功能數與工程師數的比例等指標來做衝量。以 Facebook 為例,就是以吹噓每位工程師可以支援超過一百萬的用戶這種指標為大家所知。(譯註︰如果一位工程師可以支援更多的用戶,表示每位用戶帶給工程師的作業負擔越小)[3]

自動化解決方案和腳本化重複性的瑣碎工作是很重要的,因為它們釋放出工程團隊的生產力,以從事真正的產品開發工作。確保服務會在失效時自動重啟,與服務可以方便快速地在流量到達高峰時自動複製節點,是在管理系統擴展時,降低複雜度的唯一理智辦法。在短期內,總是會有像使用 ok 繃一樣手動解決這些瑣事的誘惑,而不是為了長期考量,進行這些瑣事的自動化與相關測試。

Etsy 的箴言「度量任何事,度量所有事」(measure anything, measure everything) [4],這樣的需求可以使用 open source 的監控與圖表工具 - 像是 graphite [5] 與 statsd [6] - 來達成,而這句箴言也揭示了自動化的一個重要面向︰自動化必須由數據與監控來驅動。如果沒有監控機制和日誌,來讓我們知道什麼壞了、怎麼壞了或者為什麼壞了,那要談自動化是困難的。這句箴言應該可以改為︰「度量任何事,度量所有事,並儘可能將所有事給自動化」。

三、建立正確的軟體抽象化架構 (Build the right software abstractions)

MIT 教授 Daniel Jackson 以下面這段話,說明了軟體抽象的重要性 [7]︰

挑選正確的(抽象結構),則程式開發將會自系統設計順暢地開展出來;系統模組都將具有小而簡單的介面;新功能也將更有可能在不大量影響現行模組的前提下被加入。挑選錯誤的(抽象結構),則在這架構中進行開發將會發現一堆惱人的意外:模組介面也將成為像巴洛克風格那樣的複雜,因為它們被迫適應彼此無法預料的交互作用,這導致系統將連最簡單的變動也難以實現。

(Pick the right ones, and programming will flow naturally from design; modules will have small and simple interfaces; and new functionality will more likely fit in without extensive reorganization. Pick the wrong ones, and programming will be a series of nasty surprises: interfaces will become baroque and clumsy as they are forced to accommodate unanticipated interactions, and even the simplest of changes will be hard to make.)

使 Google 數千名工程師可以建立出延展性高的系統的部份原因是,他們擁有像 Jeff Dean、Sanjay Ghemawat 這樣的聰明工程師,可以建立出像 MapReduce[8]、SSTable[9]、protocol buffers[10] 這樣簡單而又通用的抽象層。

使 Facebook 的工程師可以延展他們系統的部份原因是,他們同樣專注在核心抽象層的建立,像是 Thrift[11]、Scribe[12] 和 Hive[13]。

而使得 Quora 設計師可以有效率地建構產品的部份原因是,Webnode 與 Livenode[14] 的簡單易懂,使得他們容易在其上建構產品。

保持核心抽象層的簡單,通常也會降低客制化的需求,使用業界慣用的抽象化機制,也會提升團隊的熟悉和專業程度。像是使用日漸普及的 Memcached、Redis、MongoDB 等系統,可以降低了需要客制化建立儲存和快取系統的需要。將團隊的重點轉移到少數核心抽象層,而不是將焦點分散到許多臨時性的解決方案。這也意味著,團隊共用的函式庫將更加強固,監控也會變得更加智能,而抽象層中的性能特性將可以得到更好的理解,並且測試範圍將會更加的全面。上述所說明的這一切,都將對團隊建立更簡單的系統、降低人員作業負擔有所助益。

四、採用程式碼審查(code review) 的方式,使團隊聚焦於高品質的程式碼 (Develop a focus on high code quality with code reviews)

維持一個高質量的程式庫,可以提升整體工程團隊的生產力。整潔的程式碼有助於理解,也可以增加開發速度,易於適應功能的變化,也更不容易產生非預期的臭蟲。而一個健全的 code review (譯註︰此處因為使用原文比較達意,下文都將直接使用 code review 這個詞) 流程,將使提高程式碼質量的這件事成為可能。

建立及時的 code review 流程 - 不管是在 commit 前(pre-commit) 或是 commit 後(post-commit) - 可以從幫助我們在多個面向來改善程式碼的品質。首先,當您知道您的程式碼將會被某個同事 review,而寫得不好的程式碼將會浪費您同事的時間,這樣的同儕壓力將使您不會寫出硬幹 (hacky)、無法維護 (unmaintainable) 或未測試過 (untested) 的程式碼。第二,code review 可以提供一個良好的機會, 讓得程式碼審查者與程式的作者可以彼此間互相學習,以在未來寫出更好的程式。

如果 code review 對於團隊的成員來說是很容易舉辦的話,則 code review 也可以自下述的面向中得到助益︰1. 增進團隊對於及時進行 code review 責任的落實、2. 使得團隊成員 - 尤其是新人 - 可以從其他成員的良好 code review 過程中學習與 3. 加速團隊中對於程式開發的最佳實踐 (best coding practices) 知識的散播。

針對 code review,有些反對的意見指出團隊沒有足夠的時間來做 code review,這些論述忽略了技術債(technical debt) 都是源自於從寫得不好的程式碼被累積出來的。在 Ooyala 的草創時間, 當時聚焦的焦點是儘可能實作出越多的功能越好,忽略了 code review 的實施。最終的結果是,我們的最初商品也許是可以更快的推出到市場上,但對於產品程式碼的修改變得非常痛苦,而我們花費了超過一年的時間來重寫這些糟糕的程式碼,以消除技術債。

以 Google 這麼大的公司為例,他們所有的代碼在 commit 前都必須通過 code review (pre-commit code reviews),但對於較小的團隊,則不需要這麼全面和嚴格,而且不是所有的程式碼都需要使用相同的審查標準。

當我在 Ooyala 公司服務時,我們在後期透過 Email 的方式,針對核心或有風險的程式變更,採用程式碼提交後審查 (post-commit) 的方式進行 code review。

而目前在 Quora (譯註︰作者當時在 Quora 服務)),我們在 Phabricator[15] 平台上進行所有 code review,主要是在程式碼提交後進行 code review (post-commit)。對於 model、controller、view 等不同作用的程式碼,使用不同的 code review 標準;對於較為敏感的代碼或是針對新人的程式碼,我們未來將在程式碼提交前做 code review (pre-commit),或試著要求團隊,在程式碼提交後的幾個小時內進行 code review。

五、維持一個彼此尊重的工作環境 (Maintain a respectful work environment)

同儕之間的互相尊重,是形成不受限開放式溝通的基礎。一個鼓勵人們自在地挑戰彼此想法的環境,也會是一個讓原始的小構想,可以透過理性辨論後再發揚光大的環境;一個使人們容易感覺被冒犯的環境,也是使得重要的反饋信息被隱瞞不說的環境。(Respect among peers forms the foundation for any type of open communication. A place where people feel comfortable challenging each other's ideas is one where sound ideas get forged through debate. A place where people easily get offended is one where crucial feedback gets withheld.)

如同在 1948 年,Alex Osborn 所提出,並在過去幾十年裡蔚為流行的「腦力激盪法」(brainstorming approach),這方法要求所有參與者聚集在一起,大家針對一個議題,提出他們的創意,並不准參與者針對別人的想法提出批判和負評 (negative feedback),如此大家就可以安心地提出意見,而不用擔心他們的想法被評判。[16]。

這種腦力激盪會議成功的關鍵,是它尊重任何潛在創意,並延後對於創意的評判。(Respectful deferment of judgment is key to this type of brainstorming session.) 而最近的心理學研究已經開始推翻 Osborn 的做法,這些研究結果顯示,鼓勵成員在腦力激盪會議上進行良性辯論,實際上有助於避免團體迷思 (譯註︰groupthink,引自 Wikipedia 的說明︰團體在決策過程中,由於成員傾向讓自己的觀點與團體一致,因而令整個團體缺乏不同的思考角度,不能進行客觀分析。),並可以因而產生更有效果的創意。根據上述的研究,一個可以彼此尊重的工作環境將更為關鍵,針對想法的批評應該聚焦於想法本身,而不是流於人身攻擊。[17]

(軟體)在工程上牽扯的領域非常廣 (系統、機器學習、產品等),並且不是所有人對於每個領域都具備同樣的專業。事實上,一個強大的團隊,應該是由許多專精各領域的個人所組成,即使這會使得他們對於其他領域的涉獵有所不足。這樣(專業分工)有時候會造成,您無法讓一個系統工程師來協助評估一個產品工程師的專業水平。但更重要的是,在一個健全的工程文化中,您應該要尊重這些專業上的差異,而不是僅僅是使用自己的強項來做出判斷。

Reference List

[1] Bill Walsh. The Score Takes Care of Itself: My Philosophy of Leadership
[2] Scaling Instagram
[3] Scaling Facebook to 500 Million Users and Beyond
[4] Measure Anything, Measure Everything
[5] Graphite
[6] StatsD
[7] Daniel Jackson. Software Abstractions: Logic, Language, and Analysis
[8] MapReduce: Simplified Data Processing on Large Clusters
[9] What is an SSTable in Google's internal infrastructure?
[10] Protocol Buffers
[11] Thrift
[12] Scribe
[13] Hive
[14] LiveNode
[15] Phabricator
[16] Your Creative Power
[17] Groupthink

(下集待續......)