Overreacted

React 團隊的技術準則

2019 M12 25 • ☕️ 2 min read

Translated by readers into: Español繁體中文

Read the originalImprove this translationView all translated posts

我很幸運地在 React 團隊的這段時間內,看見 JordanSebastianSophie 和其他團隊成員如何解決問題。在這篇文章中,我會把從他們身上所學到的,濃縮為一些較高層級的技術準則。這些準則未必詳盡,它們只是我個人對 React 團隊運作的觀察和整理——其他團隊成員或許會有不同的觀點。

UI 優先於 API

每個抽象概念合理地部署時,都有其古怪之處。這些地方該如何在 UI 上清楚呈現?你能看出一個應用程式中蘊含的特定抽象概念嗎?

抽象概念對使用者體驗有直接的影響——它能創造好的、延續性的體驗或限制某些操作。這使得我們設計 API 時,並不會從抽象概念開始發想。我們會從想呈現的使用者體驗來著手,之後再走回抽象概念。

有時當我們回到了抽象概念,會發現必須換掉整個作法,才能打造正確的使用者體驗。如果我們從 API 下手,我們就無法察覺到這點。所以我們把 UI 的優先性放在 API 前面。

吸收複雜性

React 內部程式碼的簡單化並不是我們的目標。為了使產品開發者使用 React 寫出更平易近人、易於改動的程式碼,我們樂於複雜化 React 內部的實作。

我們想讓產品開發者分散權責、互相合作,這代表我們必須把複雜部分封裝在 React 本身。React 不實作出許多小規模、鬆散的模組,因為這樣便無法做到調節和整合的工作,而 React 的使命是成為協調的角色。

我們把抽象的層級向上提升,使得產品開發者更為強大,且受益於擁有可預測屬性的 React 系統。但這意味著我們推出的每個(第 N + 1 個)新功能都必須相容於(N 個)現存的功能。因此設計和實作 React 的新功能並不容易,這也是我們沒有開源我們許多核心部分的原因。

我們吸收了複雜的部分,防止它們去影響產品的程式碼。

從 Hacks 到 Idioms

每個 API 都創造了新的限制。有時,這些限制會妨礙我們打造良好的使用者體驗。為此,我們提供一些應急用的 API(escape hatches)以供需要時使用。

使用應急用 API 的實作(hacks)不會存活很久,因為它很脆弱。產品開發者必須決定他們是否維護、支援這些 hacks,或者是移除它們而降低使用者體驗。通常我們會放棄使用者體驗,且這些 hacks 也有可能會阻礙使用者體驗的優化。

我們必須讓產品開發者使用這些應急用的 API,並觀察他們都如何實作。提供這類實作一個慣用的解決方法(idiomatic solution)是我們的最終任務,目的是達成更好的使用者體驗。這部分有時會花上數年的時間,因為我們傾向於使用有彈性的 hack 來確立一個還不完整的慣用法(a poor idiom)。

實現局部開發

你無法在程式編輯器裡做太多事情。你可以增加幾行、移除幾行,或複製貼上,但許多抽象概念讓這些基本操作變得困難。

舉例來說,MVC 架構讓刪除一些 render 的結果變得不可靠。這是因為即使你移除了 children 的 method,parents 仍然有可能執行它。相較之下,React 的優勢在於:你通常能安全地刪除 render tree 的程式碼。

在設計 API 時,我們會假設使用它的人只熟悉他們會用到的局部程式碼的相關知識。如果預期產生的影響只會發生在這局部的程式碼,我們將會避免意料之外的結果。意思是我們通常會假設增加程式碼是安全的,我們預期移除和修改程式碼時,應該清楚指出這些改動會連帶影響、應該被考慮到的部分。我們不能假設改動單一檔案的人,擁有整個 codebase 的知識。

如果一個改動不安全,我們希望開發者能夠在局部就輕易地研究這個改動所帶來的所有影響。雖然可以使用警告、型別檢查和開發者工具來幫忙,但它們也都受限於 API 的設計。如果 API 不夠局部性,局部開發就不可能實現。舉例來說,findDOMNode() 就不是一個好的 API,因為它需要 codebase 的全面知識。

漸進的複雜度

有些框架會選擇在開發的路上分出叉路,提供兩種路線:簡單的方法或強大、完整的方法。簡單的方法容易學習,但有時你會走到它的極限,這時你必須移除已完成的部分,重新使用另一個方法來實作。

我們認為實作一個複雜的東西,和實作一個簡單的東西,在結構上是沒有差太多的。我們並不會為簡單的狀況提供不同的 DSL 模板,因為這樣做會使開發中出現叉路。如果我們認為開發者在開發的過程中會逐漸想要完整的開發工具,我們願意犧牲低入門門檻來達成這件事。

有時「簡單」和「強大、完整」代表兩種不同的框架,那你仍需要換框架重寫,最好能避免這種事。以 React 為例,伺服器端的 render 這類的優化會需要付出額外的努力,但你不需要完全地重寫。

包容損害

由上而下的解決方式很重要,例如編列程式碼預算。然而長時間下來,我們的標準會下降,功能會在截止日前被完成,也有可能不繼續維護產品。當我們無法依賴其他人時,身為協調者的我們(React),必須包容損害。

如果有些 UI 相關的程式碼很慢,或超出預算,我們必須盡量避免讓它拖累載入時間,避免它和其他 UI 互動時產生負面影響。最理想的狀況是:開發者只會為了他們使用到的功能付出開發代價,而產品使用者只需要看到他們會使用到的 UI。Concurrent Mode 便能達成這種理想狀況,可以使用 Time Slicing 和 Selective Hydration 等不同方式來實現。

Library 相對穩定,而應用程式的程式碼較不受控。因此我們傾向於在應用程式之中包容損害,而不是去修正 library 內的程式碼。

相信理論

有時我們會知道某些嘗試是死路一條:它現在可以運作,但已經看得到它的極限:我們無法靠它來實現我們想要的使用者體驗。一旦有機會我們會立刻從這類的死路抽身。

我們不想卡在 local maxima,如果有某種做法在理論上更站得住腳,就算會花上好幾年,我們也樂於投注心力在其之上。在達成目標的過程中會遇到許多障礙,有時必須因現實考量而妥協,但我們相信若持續地克服這些困難,理論終究會獲勝。

你們團隊的準則是什麼?

以上是我觀察到的 React 團隊在工作時的基本原則,但我可能漏了很多。我也還沒提到 React 如何推出 API、團隊如何溝通未來的改動方向等等。或許下次可以來談談這些。

你們團隊也有一系列的工作準則嗎?我洗耳恭聽。

原始文章發表在這裡.