這就是那句著名的「要嘛把事情做好,不然就別做」;每個工程師都應該從學習一開始就尊重這句話。
我想每次看到一位初階工程師,我的第一個念頭都是:培養「負責任」的時機,其實就是職涯一開始的現在。舉例來說:我還是 Junior 的時候,接到任務、寫程式、送出 Pull Request,然後被合併,開開心心去睡覺。三天後問題又回來了,一模一樣,那你猜最後誰又得去處理?我。多年來我一直這樣做,卻忘了那句老掉牙的話:「30% 的工作其實才是程式碼本身。」那麼,其他的 70% 到底是什麼?
當我開始思考這件事,我才真正明白:多年來我交付的只是程式碼,卻沒有真正解決一個問題。今天我們要談的就是這件事。
我很常用 ownership 這個詞。我老是說「你可以負責這個嗎?」「你能接手這件事嗎?」「交給你了,好嗎?」但我很久沒有停下來解釋,對我來說 ownership 到底是什麼了。那就開始吧,今天要談的就是這個。
當我問你「你可以負責這個嗎?」時,請注意:我不是要你寫一段程式然後送出 PR。我是在要你成為某個問題解決方案的負責人,從頭到尾。從「我們有個問題」開始,到「這件事再也不用被想起來」結束。
而且,這會徹底改變一切。接手一個任務,是交付程式碼;接手一個問題,則是確保它已經不再存在,甚至連你自己都不需要再回頭想它。當你說你正在「解決」某件事時,期待的是你把下面這整套事情都做到位。這不是管理層那套空話;真正掌握這件事,才會讓團隊開始放心把越來越大的問題交給你。這基本上就是成為真正資深工程師的作弊碼,而不是只是在公司待久了的資深。
在寫任何一行程式之前,先確定你真的知道自己在解決什麼。
最常見的錯誤,就是從解法開始。你大概已經腦中有一個答案了,卻沒有先停下來想五分鐘:我們真正想解決的是什麼。如果你覺得「問題就是我們需要從 X 遷移到 Y」,等等,兄弟,那不是問題,那是解法。真正的問題應該像是「效能爛透了」、「不穩定」、「客戶 X 會壞掉」。
「把 MySQL 遷移到 Postgres」是解法。
「社群成員搜尋要 8 秒」才是問題。
懂了嗎?好。當你手上有真正的問題之後,下一個問題是:還有沒有其他可能的解法? 想一想。加索引能解嗎?快取能解嗎?先重寫那段很爛的查詢,再考慮整個資料庫搬家,行不行?每條路都有各自的取捨。綜合來看,哪個最好?
如果你跳過這一段,你很可能花兩週做出一個完美的解法,卻是針對錯的問題。那樣就算再怎麼努力也救不了。
我們的案例(8 秒搜尋): 問題不是「遷移到 Postgres」,而是「成員搜尋要花 8 秒」。在換資料庫之前,先問問是不是加索引就能解掉。
很多正式環境的問題,都是在這裡出生的:在開始之前,沒有人先問那些該問的問題。所以現在我們來問。
先想 edge case。 有哪些?哪些很重要?哪些可以刻意忽略(並且把忽略的理由記錄下來)?沒有頭像的成員、名字裡有 emoji、空清單、伺服器時區不同。選擇忽略某些情況,是一種有意識的決策;沒意識到就忽略,那就是等著爆炸的 bug。
先想失敗情境。 例如網路失敗,這幾乎是必然會發生的。那我們怎麼處理?重試嗎?那重試頻率是多少?要持續多久?Webhook 掛了:要用 backoff 重試嗎?重試三次?之後是直接丟棄,還是送進重處理佇列?
先想資料流程。 會牽涉多少資料?需要遷移什麼嗎?要清理什麼嗎?你要怎麼拿到真實資料來好好測試?資料裡有哪些不變條件(invariants)?最重要的是:你對資料格式有哪些假設,但其實還沒有確認?「每個成員都有電子郵件」——你有真的查過資料庫,還是只是自己假設然後很開心地往下做?
先想你要怎麼測試。 你怎麼知道自己做對了?自動化測試夠嗎?需要人工操作確認嗎?畫面會以截圖呈現差異,還是要錄影片?Dark mode 的 bug 不會出現在單元測試裡,我的朋友。它會出現在截圖裡。
先想怎麼對外說明。 我們會怎麼公告?你能想像公告內容嗎?這會怎麼融入更大的 road map?這部分有沒有疑慮或擔心?提出問題、發問、適度反對。 如果你連公告都無法用兩句話寫出來,那這個範圍大概率還是亂的。
我們的案例: 如果成員沒有頭像怎麼辦?如果搜尋結果是空的呢?如果一次進來 5 萬名成員呢?這些都要在寫程式之前先記下來。
這是描述起來最短、但真正經歷起來最長的階段。原則只有一個,而且很簡單。
把工作做得精準、細心、帶著緊迫感,但同時保持冷靜。不要做半套。這裡說的緊迫感,不是慌慌張張趕工,而是不讓問題繼續等你,同時也不犧牲細節與品質。
在合併之前,還有一個我最喜歡的檢查:
我會為這個成果感到自豪嗎?
如果我把它拿給 John Carmack(《毀滅戰士》與《雷神之鎚》的傳奇程式設計師)看,我能說:「這就是我在這些限制與取捨下做出來的東西」嗎?
如果答案是否定的,那很抱歉,代表你還沒完成。
我們的案例: 我加上索引,重寫那段很爛的查詢,在本機測試。從 8 秒降到 120 毫秒。我會為這個成果感到自豪嗎?會。
程式寫完,不代表事情結束。結束的定義是:問題已被解決,而且正在運作、真的在環境中跑。把這句記下來。
手動測試。 沒錯,已經有自動化測試了。但 Daniel,既然有自動化測試,為什麼還要手動測?因為測試通過,不代表功能就沒壞,我的朋友。大多數情況下,你都可以親手確認你做出來的東西真的能用:自己跑一遍、請一個 agent 走完整個情境、在前後比對資料、截圖、錄 demo。你真的有把問題解掉嗎?把整個流程當成使用者跑一遍:建立帳號、觸發動作、確認資料庫結果。
確認已部署到正式環境,而且在那裡真的能用。 已經部署了嗎?部署有沒有失敗?是不是需要啟用某個 feature flag?那個 flag 真的有效嗎?正式環境能用嗎?你能確認它真的已經上線嗎?「合併了」不等於「正式上線」,你懂吧?打開正式環境,自己實際使用這個功能。
我們的案例: 我把它上到正式環境,自己打開,搜尋「daniel」。8 秒真的變成即時,而且是用真實資料,不只是我本機上很爽而已。
沒有人知道存在的程式,就會變成沒人能解釋的 bug。溝通是工作的一部分,不是有空才做的附加項。
你的同事需要知道嗎? 這是一個大家都應該測試的新功能嗎?是一個新的程式碼慣例嗎?是一個大家都得知道的棘手變更嗎?那就通知。不要低估團隊的周邊視野:知道某個人昨天改了 Z 的行為,可能會替明天的另一個人省下三小時的除錯時間。快取機制改了?今天在團隊頻道發一則訊息,可能就是明天少三小時除錯。這是免費的,請做。
客戶需要知道嗎? 是誰回報了這個 bug?是誰在等這個功能解除阻塞?通知那些人。回覆提出 issue 的那條討論串:「今天的版本已經出來了,可以再試試看。」
整個世界需要知道嗎? 公告它已經上線了。變更紀錄、公告頻道貼文、推文,或任何符合這個變更規模的形式。
我們的案例: 我在團隊頻道發:「成員搜尋原本要 8 秒,現在已經即時了,之前有反映的人可以試試看。」並回覆提出 issue 的討論串。
Ownership 不會在部署那一刻結束。它會在沒有人、包括你自己,還需要再想起這件事時才結束。
還有後續事項嗎?你需要看一下 logs 來確認剛上線的東西運作如何嗎?一週後也許要看一次?設個提醒吧:「週五確認新 API 的錯誤率」。只有當你確定問題真的解決,而且持續被解決,這個循環才算真正閉合。
我們的案例: 下週五我會回去看 log,確認搜尋在資料量持續成長後仍然維持快速。到那時,整個循環才算真正閉合。
對,事情很多,我知道。老實說,這裡面一定還漏了一些專案。
但兄弟,這就是小團隊做產品的方式。我們沒有 PM,也沒有 QA 部門可以把事情往外丟。我們人少,但我們很能幹,而且我們就是有辦法把這些事都做完。
而且,開口求助永遠都是可以的。發問也是可以的。重做與反覆確認三次也完全可以。真正不可以的是:在心裡默默假設,卻不跟任何人說,認為別人會去做你根本沒想到的那些事。
從社群來,到社群去。
多喝水,追蹤我的社群媒體,我們下篇文章見!
原文出處:https://dev.to/he4rt/ownership-do-temos-um-rojao-na-mao-ate-nao-precisa-mais-pensar-nisso-3ki7