友快網

導航選單

如何在不可變資料結構上構建了magic money corp?這個方法可能幫你一臂之力

想象一下,您在Magic Money Corp工作,該公司僅使用三行JavaScript:

現在想象一下doStuff出了點問題,您需要將其取下來進行維護。如果您暫時將第二行註釋掉,會發生什麼?

為了解決這個問題,您現在必須通讀doStuff的整個原始碼以瞭解它的作用,並替換關鍵程式碼以發揮作用。聽起來需要做很多工作……也許我們應該離開並編寫解決方法?

現在,讓我們想象一下,如果您不是在不可變資料結構上構建了Magic Money Corp(或使用了功能語言)

自從兩年Dan Abramov撰寫有關最佳化的概念以來,我就一直為之著迷。它清楚地闡明瞭React的核心設計原理(其餘內容在這裡和此處)。對我而言,這是將使React失效原因之一,而我現在嘗試將其應用於其他任何地方。

但是,它沒有回答的主要問題是您如何精確地進行更改?

如何最佳化變更

計劃共同變更

使用簡單值

最小化編輯距離

儘早發現錯誤

為什麼要為更新而最佳化

首先,對這個想法進行必要的解釋:

難以刪除的程式碼會隨時間驅逐出易於刪除的程式碼

因此,我們必須嘗試從最早的設計中進行更改以進行最佳化

這個想法的靈感來自“易於替換的系統趨於被難以替換的系統取代”(Malte Ubl)和“編寫易於刪除而不易於擴充套件的程式碼”(tef)。

並不是說我們不知道何時很難更換系統。最方便的應對方法通常是採取解決方法,然後繼續前進。

我們必須允許更改的原因是需求波動性是軟體工程的核心問題。

我們的開發人員常常幻想如果產品規格預先完全指定,我們的生活會容易得多。

實際上,唯一不變的是變化。考慮到這一事實,我們應該仔細設計我們的抽象和API。

如何計劃共同的變化

一旦您意識到需要進行最佳化以進行更改,就很容易過度投入並被分析癱瘓所克服。當一切都可能改變時,您如何設計東西?

例如,您可以透過在每個介面上放置抽象外觀或使每個函式非同步來實現此目的。顯然,將程式碼庫的大小加倍以換取功能集上的任何差異也是不希望的。

劃清界線的一種合理方法是針對小的,常見的調整進行設計,而不用擔心大的,不頻繁的遷移。 Hillel Wayne稱這些需求為攝動-小型,典型的功能需求不應使您的整個設計毫無疑問。

對於機率上的傾斜,我們能做得最好的事情就是確保我們的設計能夠很好地適應1-3個“標準偏差”的變化。更大的變化是罕見的(根據定義),並且在發生變化時證明進行更具侵入性的重寫是合理的。

這樣,我們還避免針對可能永遠不會發生的變更進行最佳化,因為變更可能是導致軟體複雜的重要原因。

常見的變化可以透過經驗積累的例子是Zawinski定律,但是無論是透過先發制人的多元化還是業務戰略,完全完全是常規且可以預見的極端變化要少得多。

使用簡單值

一旦我們限制了想直接投入有關API設計的思考。最終目標很明確。為了使程式碼易於更改:

首先必須容易刪除

這樣就可以更輕鬆地剪下和貼上

這使得建立和分解抽象變得更加容易

直到您涵蓋所有常規維護任務,包括日誌記錄,除錯,測試和效能最佳化。

Rich Hickey以傳揚“價值觀的價值”和“樸素”而聞名。值得深入瞭解此方法對API設計的影響。

您可以在其中傳遞類例項或物件的地方進行動態引用,您可以改為傳遞簡單的,不變的值。這樣就消除了一整類潛在的錯誤(並解鎖了日誌記錄,序列化和其他功能)。

從簡單的簡單值得這些要求中,您可以從基本原理中得出令人驚訝的“最佳”實踐數量-不可變的程式設計,使用功能性核心約束狀態,命令,無法解析的解析以及管理功能。

追求簡單是從結構共享到靜態分析的各種技術都可以提供幫助。

更好的方法是記住所有這些都是同一條通用規則的例項,而不是記住一個好/壞例子:複雜性是由耦合引起的。

最小化編輯距離

每當我想到複雜性時,我都會從腦海中想象一下“簡單製造”中的例子。

執行順序—如果我刪除第2行中的內容,開發人員如何輕鬆判斷第3行中的內容是否會爆炸?我需要進行多少更改才能修復它?

解決順序-如果併發流程無法正常解決,我如何容易地糾正或保證出現競爭狀況?

檔案系統順序-如果我將某些程式碼從一個地方移到另一個地方,還需要編輯多少個其他檔案來體現這一點?

引數順序—如果我交換某些引數的位置,無論是在函式呼叫中,在類建構函式中還是在YAML配置檔案中,程式是否會內爆?

這是一個臨時列表;我可能在這裡找不到一些大的東西,請讓我知道。

您甚至可以使用“編輯距離”的概念來量化這種複雜性:

如果使用多函式功能,那麼在不更新所有呼叫站點或新增我實際上不想要的預設引數的情況下,我無法輕鬆新增或刪除或重新排列引數。具有命名引數的單個arity函式/語言僅需要基本更新,而無需更多更新。 (當然,這並非沒有取捨,這裡有更多討論。)

使用React(pre-Hooks)將無狀態元件設為有狀態,這需要對7行程式碼進行編輯/新增。使用React Hooks只需1行程式碼。

非同步和資料依賴傾向於在程式碼庫中傳播。如果一個需求發生了變化,並且底層需要進行非同步處理(例如,它需要進行一次資料提取),那麼我曾經不得不在至少3個檔案和資料夾之間進行切換,並使用Redux新增reducer,action和選擇器來協調這一工作。更好地分解關係-React Suspense,Relay Compiler和GraphQL的資料載入器中突出的設計目標。

您甚至可以想象出類似於CSS特異性公式的複雜性度量– C(1,0,0,0)的複雜度比C(0,2,3,4)難以更改。因此,針對變化進行最佳化將意味著減少常見操作的“編輯距離”複雜度。

我還沒有完全弄清楚公式的含義,但是當代碼庫難以更改時,我們可以感覺到它。結果,發展進度變慢。

但這隻

是可見

的效果-因為在程式碼庫中進行實驗並不有趣,所以從未找到新穎的想法。錯過創新所付出的無形代價與嘗試嘗試或改變主意的難易程度直接相關。

為了使

程式碼易於更改,使“編”程式碼成為不可能。

儘早發現錯誤

儘管我們可以嘗試透過API設計和程式碼樣式來遏制意外的程式碼複雜性,但是除了最瑣碎的程式之外,我們永遠無法完全消除它。

對於剩下的基本複雜性,我們必須使反饋迴圈儘可能短。

發現發現錯誤的時間越早,修復錯誤的成本就越高,因此創造了“向左移動”一詞。

如果將軟體開發生命週期從左(設計)安排到右(生產),則想法是,如果將錯誤“向左”轉移,則可以透過更早地捕獲錯誤來節省實際成本。

由語言伺服器或編輯器外掛提供的“實時”值或重播記錄

因果關係可以是雙向的。如果您更輕鬆地進行更改,則可以更頻繁地進行更改。

但是它也可以以其他方式起作用-因為您希望進行頻繁的更改,所以您更有動力使事情易於更改。

一個極端的例子不僅涉及程式碼,還涉及社群。 庫(或語言)在第一個版本上保留的時間越長,切換到第二個版本的難度就越大。而定期釋出破壞性版本(以換取明顯的改進)的生態系統似乎避免了暴露漏洞的可能。

好了,本文到此結束。如果對程式設計、計算機、程式設計師方面感興趣的話,歡迎私信聯絡我,隨時交流!點個關注,是對我莫大的鼓勵!

上一篇:c# 實現的一些設計模式:部分方法、擴充套件方法、外部引數和內部引數
下一篇:摩根大通: 比特幣和以太幣跌至數月低點,未來幾天市場可能仍會波動