做技術是打怪獸不是養寵物,為什麼要打怪獸?因為難;為什麼難很重要?因為難的事情才能帶來成長;為什麼要成長?承認吧,因為「如何成長」是當代人,包括你我他在內焦慮的源泉。
過去幾個月內我在寫一系列主題為「NodeJS實戰」的文章,內容來源是過去兩年獨自開發和運維 site2share 網站的經驗,本篇文章是對這個系列的一個暫時收尾。
今天我不聊程式碼,聊些更重要的事情
從兩件事情開始說起
其一是在此之前,我直接或間接聽到了一些來自早已離開專案同學的聲音,陳舊的專案技術棧和程式碼是驅使他們離開的原因之一。
其二是在偶爾瀏覽掘金網站的內容過程中,有一類讓我印象深刻的文章標題,大意諸如「教你用xx + xx + xx 打造一個開源系統」,因為我關注前端領域的關係,標題裡的 xx 通常是圍繞某個前端框架的時髦技術棧,從點贊和評論數來看它們頗受歡迎。
對於前者我當然理解:一方面脫離當下容易讓自己喪失競爭力,不管你願不願意承認,簡歷驅動型開發是所有程式設計師祕而不宣的默契;另一方面陳舊程式碼給開發工作帶來的挫敗感不言而喻,我相信每個程式設計師面對「屎山程式碼」都有寧願把它重寫也不願意修改一行的衝動。第二件事的出現也就順理成章了:我想毫無負擔地學習新技術,還能拋開白天工作中的螺絲釘角色,體驗一次愉快的專案實戰經歷。
我把從零開始做新專案比喻為「養寵物」,因為它能給你帶來無與倫比的掌控感。假設一個程式碼庫完全是由你一手搭建的話,那麼關於它的一切,例如如何啟動、如何部署、它適用於什麼場景又無法解決什麼樣的問題你都心中有數。如果你恰巧又在Thoughtworks 工作,那麼Thoughtworks 工作體驗更增強了這種掌控感的正當性:對於有壞味道的程式碼我們允許用工作時間進行重構,對於程式碼內不懂的知識點,只要提出問題就一定可以得到回答。
也許是我運氣不夠好,我的工作經驗告訴我,「養寵物」般的工作機會是可遇而不可求,在大廠晉升靠造輪子而不是填坑是公理人盡皆知,但造輪子的機會屈指可數。維護遺留系統依然是我們大部分人的工作。這也就是我接下來想說的「打怪獸」,此時我們面對的系統哪怕只上線一年,原始碼也可能是滿目瘡痍。
這裡是對於下面不中聽的一些話的免責宣告,我不是在否定精通
React 沒有價值,我也不認為簡歷驅動開發有什麼錯,只不過要小心它們讓我們的眼界變得狹隘
真正的常態是我接下來想說的「打怪獸」。
之所以把它稱為「打怪獸」,不僅僅因為你接觸的程式碼會超出你的預期,你甚至想象不到你會遇到什麼樣(啼笑皆非亦或是讓你無從下手)的困難:
- 這個一千行程式碼的檔案應該從哪開始讀起?
- 我如何才能讓程式碼進入這個分支?
- 你發現專案用到的一個框架沒有任何檔案,在 github 上也找不到原始碼,原來是上一個離職的老大自己寫的
- 專案的打包工具用的既不是webpack 也不是 grunt ,而是 shell 指令碼
- 現在需要你優化一個超過包含上百個元件的 React 應用的效能
「怪獸」依然是一個友好的比喻,此時此刻你至少還能夠把它具象化,將它和某些電影或者遊戲裡的角色聯絡在一起,這意味著它造成破壞的手段和範圍是可以預知的。但工作中我們實際遇到的問題無法預測。
你一定想象不到在編寫 site2share的過程中,困擾我最久的問題背後的罪魁禍首竟然是 ExpressJS 裡的 trust proxy 引數,它導致 API 從來無法存取到部署在 Azure App Service 上的後端服務
實際的出發點正如上面所說,如果我們工作中絕大部分人、絕大部分時間面臨的都是怪獸,那麼逃避它就是自欺欺人。
說點不實際的,是因為打怪獸比養寵物更難——為什麼「難」重要?因為難的事情才能帶來成長。為什麼要成長?承認吧,因為「如何成長」是當代人,包括你我他在內焦慮的源泉。
除此之外,我還想強調的是它在鍛鍊解決問題能力本身
隨著工作的深入,越來越發現我的角色從「解決技術問題的人」變成「解決問題的人」:從 Javascript、SQL Server 到程式碼設計、程式碼規範,再到團隊方向、團隊培養。整個過程其實不允許你循序漸進地去適應,可能明天醒來新的問題就擺在你面前,你也永遠也沒有準備好的那一天。也許可以把團隊管理當作一門新技術用學習程式語言的方式去學習,也許求助對的人是當務之急,也許有的問題壓根可以不解決。但無論如何,思路不會有如神助般憑空出現在你腦海裡,舉一反三需要的是練習。問題的多樣性在練習的過程中起到非常大的作用,解決新問題會帶給你明確的反饋:我的經驗可以移植到這個領域,亦或者我的工作模式需要調整。
或者忘掉我上面的長篇大論,通俗點說,打完怪獸以後你就是見過「地獄」的人了,還怕什麼。我想起來大二時候為了製作這款軟體程式碼被推翻了無數次,從那之後就再也不怕重構了
另一方面,養寵物的風險在於,它讓我們不自覺地陷入舒適區中。
我曾經有差不多有一年的時間可以自由選擇技術棧來開發各式各樣前端應用。最流行的框架和搭配起來最時髦的全家桶便成了我的不二之選。在熱門冷門嘗試了個遍之後最終我難免會對自己產生懷疑:我似乎永遠都在被輸入,我永遠都在給某個工具打工,如果今天哪個框架告訴我它是業內明日之星那我就要去學它,因為 fear of missing out 是每個技術人的通病。我似乎能做的也只有如此了,但這就真的足夠了嗎?
工具正在變得自動化,並且「幫助」我們專注於業務開發這件事帶有迷惑性。這裡的陷阱在於他能替你做很多事,會讓你以為你具備同樣的能力的錯覺。例如雖然 Parcel 可以無須任何一行設定就把指令碼打包得漂漂亮亮的,但你可能對背後的快取策略一無所知。當每個人都在簡歷上強調「精通 xx 框架」的今天,我們應該問自己除了框架我還有沒有更有力的競爭力?
這類陷阱還有另一種變形是,在團隊內你只做業務開發。身處大型開發組中會讓你以為你有獨立駕馭一個相同體量專案的能力,但實際遇到的問題會非常受限,因為功能性需求和底層設計已經交給你們團隊的 Tech Lead 甚至是團隊前成員去做了。(公允地說這不是完全負面,而是一件需要把握平衡的事情。雖然這會給團隊成員的成長帶來不利,但另一方面卻可以讓專案風險變得可控)
「打怪獸」也是在打破你的烏托邦
「教你用 xx 打造 xx」這類系列教學的前置條件太美好了:你有無限的業餘時間投入其中,你就是你自己的產品經理。但實際工作中我們永遠是戴著鐐銬跳舞。例如糟糕程式碼不一定是個人能力的結果,考慮到當時的交付壓力,團隊狀態和歷史包袱,換做你不一定能做得更好。所以大部分技術決策其實是在惡劣環境下做出的,然而如何學習在不同環境中作出恰當的反應,我不認為這是脫離實踐可以達成的。
另一個問題是它缺少對方案的閉環驗證:我不確定有多少此類專案投入到真實的商業運營中,如果沒有,很遺憾它的程式碼就不一定是有效的。例如它設計有異常捕獲功能,異常捕獲的目的之一是幫助我們在實際運營過程中排查問題,那當異常發生時它可以提供什麼樣的資訊幫助我們定位到錯誤程式碼?通常在捕獲異常之後緊接著要把資訊作為紀錄檔輸出,有相當一部分公司其實購買的第三方紀錄檔系統,那整合難度如何?如果只有零星的使用者上報了此類問題,我們可否在實際生產環境下,在每秒上千條紀錄檔增速的紀錄檔海洋裡甄別到他們?
退一步說,即使方案完美無缺,我們還需要關注它的成本如何。再一次強調,實際工作中人力、時間都是有限的,假使我們能做到滿分條件也不會允許。當你把方案拍到老闆面前,但是他告訴你預算只有三成時,選擇留下哪三分之一的功能,或者說如何用三成的預算做出來一個及格的功能比純粹的編碼更棘手。老闆更多關心的是風險,說實話「時髦」技術表達的並不一定都是褒義,它意味著技術的關注度仍在持續提升中,意味著它還可能沒有被大規模地應用,也意味著我們其實有更成熟的方案可供選擇。決策者都厭惡風險,因此在推廣新方案時風險可控也是因素之一。除此之外程式碼的學習曲線如何?程式碼庫畢竟在依賴團隊維護,你應當考慮到團隊下限對於新技術的接受程度。
最後,我建議技術同學也需要掌握一些產品思維,它也是隻有實戰可以帶給你的,只有你設身處地地把自己當作應用的運營者才會意識到某些問題,這會對技術選型帶來幫助。具體請參見我的上一篇文章:《個人開發者如何選購雲服務》。
你可能會喜歡