關於合格工程師素養的一些思考

一個引子

碼農和程序員有什麼區別?

我認爲,碼農可以做一些簡單的編碼工作:實現某個腳本,拼裝某條 hql,“寫完”某個函數。往往有一定語言知識,有一定的編碼經驗;但是很少對需求細緻分析,缺乏“恰當”意識。他可能會用一條 sql 完成整個功能,也可能用一個 for 循環遍歷所有接口,甚至爲了某個不重要的 update 加鎖、加事務…… “爲了目的,不擇手段”,而且並不確切目的是什麼。

而程序員,他知道自己要做什麼。可以把一個函數寫的性能優良,可以把一個模塊設計的很“恰當”。他熟悉 MVC, 熟悉設計模式,可以讓他的模塊整潔、完美。甚至,可以創造性的解決一些產品問題,讓代碼充滿靈性。但是,往往全局觀不足。

那麼全局意識指的是什麼呢,我們應該怎樣培養我們的全局意識?

肯定不是 pm 讓我做什麼,我只要寫代碼把它實現就好了。而是要首先明確爲什麼要做這個,做這些的價值是什麼。

我們有義務幫助產品找到最恰當的解決方案,然後用合理的方式把方案嵌入到代碼中。同時,要讓保證架構活力,要可以快速定位bug、解決bug。清楚上線流程,要保證上線後不會產生任何的消極影響。

一個合格的工程師,可以讓產品需求平穩地落地。那麼我們應該怎樣做到呢?我認爲可以從以下幾點出發。

1. 明確需求細節,少做無用功、廉價功

我們應該首先應該明確產品需求是什麼,但更重要的是爲什麼。產品爲什麼要這麼做?預期的目標是什麼?哪些數據表明這些目標達成了?如何去收集這些指標?

然後,去判斷需要哪些人配合,高優先級去協調資源。如果判斷人力成本過高,或者收益有限,可以說服產品延後部分需求的實現。集中精力做最重要的事情,少做無用功。同時,積累工作經驗、數據經驗,鍛鍊自己對“性價比”的敏感性,讓自己的判斷變得客觀、有效、權威。

2.代碼的執行可視化

在開始設計功能前,應該先考慮怎麼去做監控。不能讓功能迷迷糊糊地在線上跑着,“它應該是對的吧”……越實時的反饋,越可以早得發現問題,越可以早得爲項目止損。同時也是對工作的負責,更是對自己汗水的負責:誰也不想自己辛勤寫出來的代碼,直到下線那天才發現一直沒有運行“對過”。

  • 哪些指標,證明功能是 ok 的
  • 哪些報警,證明這是個 bug,那裏肯定掛了
  • 哪些指標,證明這個需求是有價值的 (比如:某個功能數據過低,此功能的後續迭代就應該適當降低優先級)

3.出現反饋如何應對,出現 bug 如何修復

產品的 feature 不可能讓所有人都喜歡,甚至有時爲了產品調性會做些對用戶打壓的事情。這樣的功能如何讓用戶接受?如果不接受,產品應該如何去引導;技術應該如何輔助產品定位問題。

舉個例子,首頁 feed 會過濾掉用戶屏蔽的條目。如果用戶屏蔽了話題 A, 綁定了 A 話題的條目不會分發給用戶。這是一個很合理的產品 feature, 但是用戶會經常誤以爲對 XX 內容限流。運營就會要求我們查 bug。像這種需求,我們要做的不只是開發功能,更應該考慮後期如何應對反饋,提高響應效率。

某個關鍵功能出了 bug。我們應該如何跟用戶解釋?應該如何修復數據?修復如何快速?那麼我們可能要考慮,我們要不要準備修復腳本,我們是不是需要操作冪等,數據操作該不該記錄審計 log……

4.確保代碼沒有腐化架構

依照上面兩步,我們意識到了要對業務指標可視化實時監控,要考慮問題的應急方案。然後,就可以着手設計我們的功能框架。所謂的實現需求,不是寫個 function 把邏輯寫完就行,更不是一個 sql 把數據丟給用戶。所謂的架構,就是爲了完成一套完整的功能,合理組合的多個模塊。要讓你的代碼更好的被人看懂,要在恰當的地方完成業務監控,要用恰當的邏輯爲應急提供方便。

如果發現現有的架構不能恰當的融入你的需求,千萬別打個補丁硬推上去。“邏輯”誰都能寫完,但是要讓別人覺得,這塊代碼本來就應該在這裏。衡量代碼質量的唯一有效標準:WTF/min —— 出自《Clean Code》。

我們應該努力拽着自己的項目,讓它離“屎”遠一點;而不是增加一坨。寫代碼時,應該考慮的是怎麼用,別人怎麼讀,而不是我怎麼寫!只對作者友好的代碼絕對是垃圾。面向工程,面向合作。要讓用的人舒服,讓用的人心理成本低。

5.邀請大家進行 CodeReview

本着一個工程師的素養,我們應該努力拽着自己的項目,讓它保證架構的清潔;但是,這只是一廂情願的。在代碼真正推上線前,我們需要讓更多的人 code review,以求達成共識。

我的經驗是,如果涉及架構調整,我會先提交一個初版,讓一些有經驗的工程師幫忙評審架構設計。這個階段我們千萬不要追求代碼完成度、單測覆蓋率。因爲很可能架構設計不合理,可能會引起大量的返工,部分工作可能會直接作廢。所以,我認爲一個合理的 CodeReview 可以分爲四步:

  1. 按需求調整代碼架構,儘早提交框架 diff。評審者主要關注:改動是否污染了架構,調整後的架構是否易於新人學習,新增模塊是否容易 debug (比如,方便構造 bug 現場)
  2. 填充架構細節,“優雅”地實現各模塊邏輯。評審者主要關注:功能拆分是否清晰,類是否抽象合理、是否符合語法習慣 (如python, 是否可以適當使用列表表達式、lambda)
  3. 確認各模塊邏輯無異常、無 bad case。評審者主要關注:功能是否完全覆蓋單元測試、是否已經完成了聯調、是否進行了完善的功能測試
  4. 確保代碼細節。評審者主要關注:是否合理的捕捉了第三方工具的異常,是否有合理的功能降級、模塊降級,循環是否合理(嚴防死循環),變量命名是否表義、變量作用域是否過大……

所以,我認爲 code review 不是一次性的。如果你突然收到了一個 100+ 文件變動的 merge request,那作者肯定只是想讓你給他 approve:停留在形式上的 code review,至多隻是因爲作者想找個人“共同背鍋”。合理的 code review 應該把握大框,逐步細化,漸入佳境。

其實,一步步按着上面的思路來,每一步都有特定的焦點,並不會花費大家太多時間。

6.確認好依賴,讓改動平滑上線

相信經過上面嚴格的 review, 我們可以拿到一份大傢俱有共識的優良代碼。但是,代碼優良不代表可以部署上線。除非你在寫 print "hello world", 否則,你的功能與各種上下游服務勢必會有千絲萬縷的聯繫。我們必須在上線前,確認好所有的依賴不會阻塞我們。

首先我們要檢查自身是否有先驗邏輯未就緒。比如:知乎首頁需要新增加一種卡片樣式。要先確保版本兼容邏輯已上線,否則舊的客戶端收到不識別的卡片可能會 crash。再確保數據庫數據初始化,數據庫裏沒東西上線沒有意義。

其次要檢查下游邏輯是否已經就緒。下游服務功能是否正常上線,是否能承擔我們的請求壓力;數據表 schema 是否變動、是否已上線,數據庫容量是否足夠,數據庫是否能承受壓力;相應緩存是否應該預熱……

然後,需要通知我們的上游服務。我們的改動是否不兼容,是否會引發上游調用出錯;我們的改動是否影響了性能,是否需要上游調整 timeout……

7.最小化驗證儘量止損

前期做足了準備,大家足夠警惕地關注着自己的指標變動。然後,我們就可以上線了。

但是,正因爲各種指標可能會出現難以預期的變化,我們需要逐步擴大功能的影響範圍。比如,先用辦公室環境,然後放量給 10%、20% …… 的用戶,同時觀察指標變化。

當然我們應該“事先”明確應該觀察哪些指標。比如,接口的 QPS、P95、5xx;依賴我的服務是否正常,我依賴的服務指標是否異常;存儲服務、業務指標是否正常… 發現異常及時回滾。

小結就是:

  • 在上線前,先想好自己應該關注哪些指標
  • 上線過程,注視指標,逐步放量
  • 遇到任何異常、疑似異常,及時回滾

尾聲

代碼編寫其實沒有難度。哪怕是個小白,在培訓班學呆半個月,就可以實現個小功能:打印個 hello world, 轉置個數組,甚至實現個快排……面試寶典、leetcode 可以幫你順利的通過面試。

但面試通過只是說明面試官覺得我們不錯,不是證明我們可以勝任之後的工作。常言道,“面試造火箭、工作擰螺絲”,面試題目與工作實戰還是有相當大的差別的。不過,只要用心體味,你會發現,實際上工作要比面試的“火箭”複雜度更高。工作造的“火箭”與面試的“火箭”不在一個維度,工作的“火箭”是在幫我們從碼農演變成工程師。

而工程師素養,纔是衡量我們能不能在這個行業走深走遠的關鍵。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章