並非所有軟體建議都一樣。有些建議很實用。它會明確告訴你該怎麼做:
這類建議很有用,因為它容易理解、容易教學,也容易驗證。你可以看著一段程式碼,然後問:這個函式是不是太大了?這是魔術數字嗎?這個常數命名正確嗎?
通常都會有相對明確的答案。而且因為這類建議很容易遵循,所以它們往往會迅速擴散。團隊會把它寫進程式碼規範,linter 會強制檢查,程式碼審查會確認,開發者也會在職涯早期學到。但還有另一種建議。它更難遵循。而依我的經驗,它往往也更有價值。
我大致把軟體建議分成兩類。第一種是實用建議。它接近非黑即白:
這樣做。
不要那樣做。
第二種是判斷型建議。
它不會給你一套配方。相反地,它會給你一個原則,而你必須根據情境去詮釋。它甚至可能和你學過的另一個原則互相矛盾。這類建議比較像是在兩種對立力量之間取得平衡。它不一定有放諸四海皆準的正確答案。也正因如此,它才困難。
像這樣的建議:
撰寫小型函式。
通常都很有用。初階開發者看得懂,資深開發者能教,程式碼審查者看到一個 200 行的函式,也能直接說:「這應該拆開。」
像下面這些建議也一樣:
不要使用魔術數字。
或:
使用有意義的名稱。
或:
讓你的類別保持聚焦。
這些都是很棒的建議,因為它們減少了你需要做的決策數量。
你不需要花很多年經驗才能理解它們的意思。你可以從書上學到,明天就套用,然後立刻看到改善。這也是像 Clean Code 這類書籍變得如此有影響力的原因之一。因為其中很大一部分建議都能直接採用。
你可以把一個原則立刻轉換成你在寫程式時會做的事。這很有價值。但也有風險。我們可能會開始把遵守良好實踐和成為一位優秀工程師混為一談。
考慮另一種建議:
錯誤的抽象,比重複更昂貴。
這聽起來很簡單,但試著把它變成一條規則。這段程式碼我應該重複嗎?有時候是。有時候不是。
重複到什麼程度算可以接受?
兩段程式碼要多像,才應該抽象化?如果它們今天看起來很像,但未來很可能會往不同方向演進呢?
如果這個抽象化讓目前的程式更複雜,但也許能避免我們之後重複實作,那又該怎麼辦?這些問題沒有簡單的檢查清單可以回答。你需要判斷力。而判斷力來自經驗。你必須見過做得很好的抽象,也必須見過把程式變成怪物的抽象。
你需要親身經歷過:太早設計的抽象在修改時要付出多大的代價。你需要看過完全無害的重複。也需要看過重複最後變成維護災難。只有到那時,這個建議才會在更深層次上變得有用。它不再只是規則,而會變成一種思考方式。
這正是我覺得軟體工程很迷人的地方。你在職涯的不同階段聽到同一句建議,可能每次都會理解出完全不同的東西。職涯早期,別人告訴你:「不要重複自己。」
你學會了 DRY,所以你開始到處找重複。兩段程式看起來相似?就抽象化。幾個參數重複出現?就建立一個共用物件。幾個類別有相似行為?就建立一個基底類別。你在遵循這個建議。然後幾年後,你又遇到另一個原則:
寧可重複,也不要做錯抽象。
這時 DRY 就不再那麼簡單了。你會發現,重複不一定是問題。
有時候,重複是維持兩個概念彼此獨立所要付出的代價。有時候,抽象化造成的耦合,遠比重複本身更糟。有時候,最好的做法就是先重複,等領域真的告訴你應該如何抽象時,再來處理。
建議本身沒變。變的是你詮釋它的能力。 這就是經驗帶來的東西。
職涯會有一個階段,你累積了足夠多的例子,開始能在自己還說不清楚之前,就先辨識出模式。你看到一個抽象,就覺得哪裡怪怪的。你可能一時無法清楚說明原因。你或許只會說:
「我覺得現在還不該把這個抽象化。」
為什麼?也許你以前見過完全相同的情況。也許你曾經歷過這些抽象如何演變。也許你意識到,兩個現在看起來一模一樣的東西,未來很可能因為完全不同的原因而改變。
這就是直覺開始變得重要的地方。軟體工程中的直覺不是魔法,也不是思考的替代品。它通常是累積經驗的結果。
你見過夠多的情境、失敗、取捨與後果,大腦就會開始自動辨識模式。問題是,直覺比規則更難教。我可以花五分鐘教你「使用小型函式」。
但我沒辦法用五分鐘的建議,讓你理解什麼時候函式算太大、為什麼它太大,以及什麼時候把它拆開反而會讓程式更糟。這需要經驗。
這種建議之所以困難,還有另一個原因。有時候兩條好建議會互相衝突。你可能會聽到:
保持簡單。
以及:
不要重複程式碼。
還有:
避免過早抽象化。
以及:
將會變動的部分封裝起來。
這些都可能是好建議。但如果遵循其中一條,會讓你更難遵循另一條,該怎麼辦?
沒有編譯器警告你這件事。也沒有 linter 能告訴你哪個原則應該勝出。你必須自己做決定。而這個決定取決於上下文。
這也是為什麼有時候資深工程師對一段程式碼會有不同看法,但雙方的論點都很合理。分歧不一定是因為一方懂規則、另一方不懂。
也可能是因為他們對未來、對領域、對變更成本,或對相關風險,做出了不同判斷。這就是軟體工程的灰色地帶。
我認為,在程式碼之外也能看到同樣的區別。以 Scrum 和《敏捷宣言》為例。Scrum 提供的是具體內容:角色、事件、工件和規則。
一個團隊可以學 Scrum,然後相對快速地開始實作。這讓組織很容易接受。能夠說出:
「我們有在做 Scrum。」
會讓人感到安心。因為有框架,有明確做法,有可以排程的儀式,有可以建立的工件,也有可以指著說「我們有做到」的東西。
《敏捷宣言》則不同。它提供四大價值與十二項原則,但沒有給你一份完整的軟體組織作業手冊。
它告訴你像是:重視個人與互動高於流程與工具,重視回應變化高於遵循計畫。這些陳述都需要解讀,也需要判斷。
例如,重視個人與互動高於流程,並不代表流程沒有用。回應變化,也不代表計畫沒有用。
真正有趣的問題不是:
「我要遵守哪一個?」
而是:
「在這個特定情境下,我要怎麼應用這些原則?」
而這困難得多。你可以實作 Scrum,卻不一定會培養出 Agile 背後的判斷力。
你可以擁有所有儀式、所有看板、所有角色、所有術語,卻還是錯過背後的原則。
這就是遵循框架和理解框架背後的原則之間的差別。
實用建議之所以占上風,有很自然的原因。
公司可以制定一條程式碼規範說:
函式應該要短小。
但要制定這樣的規範就難多了:
使用你累積的經驗與判斷,來決定目前領域及其未來可能變化所需的適當抽象層級。
前者可以變成規則,後者需要真正知道自己在做什麼的人。組織自然偏好能被寫成規則的東西。而這不一定是壞事。實用建議非常有幫助。問題出在於,我們相信只要蒐集足夠多實用規則,最後就會得到好的判斷力。
事情不是這樣運作的。知道更多規則,不會自動讓你更擅長取捨。到最後,你還是得培養出一種能力:判斷在這個情境下,哪條規則比較重要。
這就是為什麼我認為,某些最有價值的軟體建議,其實也是最難遵循的。
它不會明確告訴你該怎麼做。
它會讓你思考。它提供你一個看待問題的角度。它甚至可能迫使你在兩個互相競爭的想法之間取得平衡。起初,這會讓人挫折。我們希望軟體工程能有配方。
但軟體是建立在情境中的。
你累積越多經驗,就越會發現,許多最重要的工程決策都沒有放諸四海皆準的答案。它們需要判斷力。而判斷力之所以困難,是因為你必須對這個決定負責。你不能躲在檢查清單後面。
也許,成為更好的軟體工程師,不是把錯誤的規則換成更好的規則。也許是逐漸從規則走向原則。
從:
「有人叫我這樣做。」
到:
「我知道這通常為什麼有用。」
最後到:
「我理解這個取捨,而且我能判斷它是否適用於這裡。」
這是一項困難得多的技能。但一旦你具備了它,實用建議反而會變得更有用。你不會停止使用規則,而是更懂得規則。你知道什麼時候該遵守它們,也知道兩條規則何時會衝突。而最重要的是,你知道什麼時候不該遵守它們。這就是經驗把建議轉化為智慧的地方。
我很好奇你的經驗。你在職涯中遇過最沒意義的實用軟體建議是什麼? 反過來,你學過最有價值的判斷型建議又是什麼? 那種不是直接給你規則去遵循,而是改變你看待軟體工程方式的建議。
我很期待在留言中看到你的例子。
原文出處:https://dev.to/remojansen/why-the-best-software-advice-is-the-hardest-to-follow-4kg8