Vitalik Buterin:以太坊是否應該封裝更多功能?

關於協議極簡主義的早期哲學

在當時被稱為“以太坊2.0”的早期歷史中,人們強烈希望創建一個乾淨,簡單和美觀的協議,該協議盡可能少地嘗試通過自身來構建,並將幾乎所有這類工作都留給用戶。理想情況下,協議只是一個虛擬機,而驗證一個區塊只是一個虛擬機呼叫。

「狀態轉換函數」(處理區塊的函數)將只是單一VM 調用,所有其他邏輯將透過合約發生:一些系統級合約,但主要是由用戶提供的合約。這個模型的一個非常好的功能是,即使是整個硬分叉也可以被描述為對於區塊處理器合約而言的單筆交易,該交易將通過鏈下或鏈上治理進行批准,然後以升級的權限運行。

2015 年的這些討論特別適用於我們考慮的兩個領域:帳戶抽象和擴充。在擴容的情況下,我們的想法是嘗試創建一個最大程度的抽象形式的擴容,感覺就像上面圖表的自然擴展。合約可以調用大多數以太坊節點未儲存的數據,協議將檢測到這一點,並透過某種非常通用的擴展計算功能來解決呼叫。從虛擬機器的角度來看,該呼叫將進入某個單獨的子系統,然後一段時間後神奇地返回正確的答案。

我們對這種思路進行了簡短的探索,但很快就放棄了,因為我們太專注於驗證任何類型的區塊鏈擴容都是可能的。儘管我們稍後會看到,數據可用性採樣和ZK-EVM 的結合意味著以太坊擴容的一個可能的未來實際上看起來非常接近這個願景!另一方面,對於帳戶抽象,我們從一開始就知道某種實現是可能的,因此研究立即開始嘗試使盡可能接近“交易只是一個調用”的純粹出發點的東西變為現實。

在處理交易和從發送方位址發出實際的底層EVM 呼叫之間,會出現大量的樣板程式碼,之後還會出現更多的樣板程式碼。我們如何將這些程式碼盡可能減少到接近零?

這裡的主要程式碼之一是validate_transaction(state, tx),它負責檢查交易的nonce 和簽章是否正確。從一開始,帳戶抽象的實際目標就是允許用戶用自己的驗證邏輯替換基本的非增量驗證和ECDSA 驗證,這樣用戶就可以更輕鬆地使用社交恢復和多簽名錢包等功能。因此,找到一種方法將apply_transaction 重新架構為一個簡單的EVM 調用,這不僅僅是一個「為了使程式碼乾淨而使程式碼乾淨」的任務;相反,它是關於將邏輯移動到用戶的帳戶程式碼中,為使用者提供所需的靈活性。

然而,堅持讓apply_transaction 包含盡可能少的固定邏輯的做法最終帶來了許多挑戰。我們可以看下最早的帳戶抽象提案之一EIP-86 。

如果按原樣包含EIP-86 ,它將降低EVM 的複雜性,代價是大量增加以太坊堆疊其他部分的複雜性,需要在其他地方編寫本質上完全相同的程式碼,除了引入全新的怪異類別之外,例如具有相同雜湊值的相同交易可能會在鏈中多次出現,更不用說多重失效問題了。

帳戶抽像中的多重失效問題。在鏈上包含的一筆交易可能會使內存池中的數千筆其他交易無效,從而使內存池很容易被廉價地充斥。

從那時起,帳戶抽象化分階段發展。 EIP-86 後來變成了EIP-208 ,最終出現了實際可行的EIP-2938 。

然而,EIP-2938 一點也不簡約。其內容包括:

· 新的交易類型

· 三個新交易範圍的全域變數

· 兩個新的操作碼,包括非常笨拙的PAYgas 操作碼,用於處理gas 價格和gas 限制檢查,作為EVM 執行斷點,以及臨時存儲ETH 以一次性支付費用

· 一組複雜的挖礦和轉播策略,包括交易驗證階段禁止的操作碼列表

為了在不涉及以太坊核心開發人員(專注於優化以太坊用戶端和實現合併)的情況下實現帳戶​​抽象,EIP-2938 最終被重新架構為完全是協議外的ERC-4337 。

因為這是一個ERC,它不需要硬分叉,並且在技術上存在於「以太坊協議之外」。所以……問題解決了嗎?事實證明並非如此。 ERC-4337 目前的中期路線圖實際上涉及最終將ERC-4337 的大部分轉變為一系列協議功能,這是一個有用的指導範例,可以了解為什麼要考慮這條路徑。

封裝ERC-4337

有幾個關鍵原因討論了最終將ERC-4337 重新納入協議:

gas效率:在EVM 內部進行的任何操作都會導致一定程度的虛擬機開銷,包括在使用諸如儲存槽之類gas 費昂貴的功能時效率低下。目前,這些額外的低效率加起來至少要消耗2 萬gas,甚至更多。將這些組件放入協定中是消除這些問題的最簡單方法。

代碼bug 風險:如果ERC-4337 「入口點合約」有一個足夠可怕的bug,所有與ERC-4337 相容的錢包都可能看到他們所有的資金枯竭。以協議內功能取代合約會產生一種隱含的責任,即透過硬分叉修復程式碼錯誤,從而消除用戶的資金枯竭風險。

支援EVM 操作碼,如txt.origin。 ERC-4337 本身使txt.origin 傳回將一組使用者操作打包到交易中的「捆綁器(bundler)」的位址。原生帳戶抽象化可以解決這個問題,方法是使txt.origin 指向發送交易的實際帳戶,使其運作方式與EOA 相同。

抗審查:提議者/建構者分離的挑戰之一是審查單筆交易變得更容易。在以太坊協議可以識別單筆交易的世界中,包含清單可以極大地緩解這個問題,該清單允許提議者指定在幾乎所有情況下必須包含在接下來兩個插槽中的交易清單。但是協議外的ERC-4337 將「用戶操作」封裝在單筆交易中,使得用戶操作對以太坊協議不透明;因此,以太坊協議提供的包含清單將無法對ERC-4337 用戶操作提供審查阻力。封裝ERC-4337 ,並使使用者操作成為一種「適當的」交易類型,將解決這個問題。

值得一提的是,在目前的形式下,ERC-4337 比「基本」以太坊交易要貴得多:交易成本為21, 000 gas,而ERC-4337 的成本約為42, 000 gas。

理論上,應該有可能對EVM gas 成本系統進行調整,直到協議內成本和協議外訪問存儲的成本相匹配;當其他類型的存儲編輯操作更便宜時,轉移ETH 沒有理由需要花費9000 gas。事實上,與即將到來的Verkle 樹轉換相關的兩個EIP 實際上試圖做到這一點。但是,即使我們這樣做了,有一個顯而易見的原因可以解釋為什麼無論EVM 變得多麼高效,封裝的協議功能都將不可避免地比EVM 代碼便宜得多:封裝代碼不需要為預加載支付gas。

功能齊全的ERC-4337 錢包很大,編譯並放到鏈上的這個實現佔用了約12, 800 位元組。當然,你可以一次部署這段程式碼,並使用DELEGATECALL 來允許每個單獨的錢包呼叫它,但仍然需要在使用它的每個區塊中存取該程式碼。在Verkle 樹gas 成本EIP 下, 12, 800 位元組將組成413 個chunk,存取這些chunk 將需要支付2 倍的witness branch_cost(總共3, 800 gas)和413 倍的witness chunk_cost(總共82, 600 gas) 。這甚至還沒有開始提到ERC-4337 入口點本身,在0.6.0 版本中,鏈上有23, 689 位元組(根據Verkle 樹EIP 規則,約有158, 700 個gas 要載入)。

這就導致了一個問題:實際存取這些代碼的gas 成本必須以某種方式在交易中分攤。 ERC-4337 使用的當前方法不是很好:bundle 中的第一筆交易消耗了一次性儲存/代碼讀取成本,使其比其他交易昂貴得多。協議內封裝將允許這些公共共享庫成為協議的一部分,所有人都可以免費存取。

我們能從這個例子學到什麼,什麼時候更普遍地進行封裝?

在這個例子中,我們看到了在協議中封裝帳戶抽象化方面的一些不同的基本原理。

當固定成本較高時,「將複雜性推向邊緣」的基於市場的方法最容易失敗。事實上,長期的帳戶抽象路線圖看起來每個區塊都有許多固定的成本。 244, 100 gas 用於加載標準化錢包代碼是一回事;但是聚合可能會為ZK-SNARK 驗證增加數十萬的gas,以及證明驗證的鏈上成本。沒有一種方法可以在不引入大量市場低效率的情況下向用戶收取這些成本,而將其中一些功能轉化為所有人都可以免費訪問的協議功能則可以很好地解決這個問題。

社區範圍內對程式碼bug 的回應。如果一些程式碼片段被所有用戶或非常廣泛的用戶使用,那麼區塊鏈社群承擔硬分叉的責任來修復出現的任何錯誤通常更有意義。 ERC-4337 引入了大量的全域共享程式碼,從長遠來看,透過硬分叉修復程式碼中的錯誤無疑比導致用戶損失大量ETH 更合理。

有時,可以透過直接利用協議的功能來實現其更強形式。這裡的關鍵例子是協議內的抗審查功能,例如包含列表:協議內的包含列表可以比協議外的方法更好地保證審查阻力,為了使用戶級操作真正受益於協議內的包含列表,單個用戶級操作需要對協定「易讀」。另一個鮮為人知的例子是, 2017 年時代的以太坊權益證明設計對權益密鑰進行了帳戶抽象,這被放棄了並轉而支持封裝BLS,因為BLS 支持一種「聚合」機制,必須在協定和網路層面實現,這可以使處理大量簽章的效率更高。

但重要的是要記住,與現狀相比,即使是封裝協議內帳戶抽象,仍然是一種巨大的「去封裝化」。如今,頂級以太坊交易只能從外部擁有的帳戶(EOA)發起,這些帳戶使用單一secp 256 k 1 橢圓曲線簽名進行驗證。帳戶抽象消除了這一點,並將驗證條件留給使用者自行定義。因此,在這個關於帳戶抽象的故事中,我們也看到了反對封裝的最大理由:靈活地滿足不同使用者的需求。

讓我們透過查看最近被考慮封裝的其他幾個特徵範例來進一步充實這個故事。我們將特別關注:ZK-EVM,提議者-建構者分離,私有記憶體池,流動性質押和新的預編譯。

封裝ZK-EVM

讓我們把注意力轉移到以太坊協議的另一個潛在封裝目標:ZK-EVM。目前,我們有大量的ZK-rollup,它們都必須編寫相當相似的程式碼來驗證ZK-SNARK 中類似以太坊區塊的執行。有一個相當多樣化的獨立實現生態系統:PSE ZK-EVM、 Kakarot 、 Polygon ZK-EVM、 Linea 、Zeth 等等。

EVM ZK-rollup 領域最近的一個爭議與如何處理ZK 程式碼中可能出現的bug 有關。目前,所有這些正在運行的系統都有某種形式的「安全理事會」機制,可以在出現bug 的情況下控制證明系統。去年,我試圖創建一個標準化的框架,以鼓勵計畫明確他們對證明系統的信任程度,以及對安全理事會的信任程度,並隨著時間的推移,逐漸減少對該組織的權力。

從中期來看,rollup 可能依賴多個證明系統,而安全理事會只有在兩個不同的證明系統產生分歧的極端情況下才有權力。

然而,有一種感覺是,其中一些工作感覺是多餘的。我們已經有了以太坊基礎層,它有一個EVM,我們已經有了一個處理實作中bug 的工作機制:如果有bug,客戶端將進行更新來修復,然後鏈繼續運作。從有bug 的客戶端角度來看,似乎已經最終確認的區塊將不再確認,但至少我們不會看到用戶損失資金。同樣,如果rollup 只是想保持與EVM 等同的作用,那麼它們需要實施自己的治理來不斷更改其內部ZK-EVM 規則以匹配對以太坊基礎層的升級,這感覺是錯誤的,因為最終它們是在以太坊基礎層本身之上構建的,它知道何時升級以及根據什麼新規則。

由於這些L2 ZK-EVM 基本上使用與以太坊完全相同的EVM,我們能否以某種方式將「驗證EVM 在ZK 中的執行」納入協議功能,並透過應用以太坊的社會共識來處理異常情況,如bug 和升級,就像我們已經為基礎層EVM 執行本身所做的那樣?

這是一個重要而富有挑戰性的議題。

關於原生ZK-EVM 中資料可用性的一個可能的爭論主題是有狀態性(statefulness)。如果ZK-EVM 不需要攜帶「見證(witness)」數據,它們的數據效率就會高得多。也就是說,如果某個特定的資料已經在先前的某個區塊中讀取或寫入,我們可以簡單地假設證明者可以存取它,並且不必再次使它可用。這不僅僅是不重新載入儲存和程式碼;事實證明,如果一個rollup 正確地壓縮了數據,那麼與無狀態壓縮相比,有狀態壓縮最多可以節省3 倍的資料。

這意味著對於ZK-EVM 預編譯,我們有兩個選項:

1. 預編譯要求所有資料在同一區塊中可用。這意味著prover 可以是無狀態的,但也意味著使用這種預先編譯的ZK-rollup 比使用自訂程式碼的rollup 要昂貴得多。

2. 預編譯允許pointer 指向先前執行使用或產生的資料。這使得ZK-rollup 接近最優,但它更複雜,並引入了一種必須由prover 儲存的新狀態。

我們能從中學到什麼?以某種方式將ZK-EVM 驗證封裝有一個很好的理由:rollup 已經在建立自己的自訂版本,而以太坊願意將其多個實現和鏈下社會共識的權重置於L1 上執行EVM ,這感覺是錯誤的,但是做完全相同工作的L2 必須實現涉及安全理事會的複雜小工具。但另一方面,細節中有一個大問題:有不同版本的ZK-EVM,它們的成本和收益不同。有狀態和無狀態的區分只是觸及了表面;嘗試支持“近EVM(almost-EVM)”,這些定制代碼已經被其他系統證明,這可能會暴露出更大的設計空間。因此,封裝ZK-EVM 既帶來了希望,也帶來了挑戰。

封裝提議者與建造者分離(ePBS)

MEV 的興起使區塊生產成為一種大規模經濟活動,複雜的參與者能夠生產出比預設演算法產生更多收入的區塊,而預設演算法只是觀察交易的記憶體池並包含它們。到目前為止,以太坊社群試圖透過使用MEV- Boost 等協議外的提議者-建構者分離(proposer-builder separation)方案來解決這個問題,該方案允許常規驗證者(「提議者」)將區塊建構外包給專門的參與者(「建構者」)。

然而,MEV-Boost 在一個新的參與者類別中進行了信任假設,稱為中繼(relay)。在過去的兩年裡,有許多人提議創建「封裝PBS」。這樣做的好處是什麼?在這種情況下,答案非常簡單:透過直接使用協定功能建構的PBS 比不使用它們建構的PBS 更強大(在具有更弱的信任假設的意義上)。這與封裝協議內價格預言機的情況類似——儘管在這種情況下,也存在強烈的反對意見。

封裝私有記憶體池

當用戶發送交易時,該交易立即公開並對所有人可見,甚至在它被包含在鏈上之前。這使得許多應用程式的用戶容易受到經濟攻擊,例如搶先交易。

最近,有許多項目專門致力於創建「私有記憶體池」(或「加密記憶體池」),它將用戶的交易加密,直到它們被不可逆轉地被接受到一個區塊中。

然而,問題是,這樣的方案需要一種特殊的加密:為了防止用戶湧入系統並率先進行解密,加密必須在交易確實被不可逆轉地被接受後自動解密。

為了實現這種形式的加密,有各種不同權衡的技術。 Jon Charbonneau 曾做過很好的描述:

對中心化運營商進行加密,例如 Flashbots Protect。

時間鎖加密,該加密形式經過一定的順序計算步驟後,任何人都可以解密,並且不能並行化;

閾值加密,信任一個誠實的多數委員會來解密資料。具體建議請參閱封閉信標鏈概念。

可信任硬件,如SGX。

不幸的是,每一種加密方式都有不同的弱點。雖然對於每個解決方案,都有一部分使用者願意信任它,但沒有一個解決方案的信任程度足以讓它實際上被Layer 1 接受。因此,至少在延遲加密得到完善或其他一些技術突破之前,在Layer 1 封裝反提前交易功能似乎是一個困難的命題,即使它是一個足夠有價值的功能,許多應用程式解決方案已經出現。

封裝流動性質押

以太坊DeFi 用戶的一個共同需求是能夠同時使用他們的ETH 進行質押和作為其他應用程式中的抵押品。另一個常見的需求只是為了方便:使用者希望能夠在沒有運行節點並保持其始終在線的複雜性的情況下進行質押(並保護線上質押金鑰)。

到目前為止,滿足這兩種需求的最簡單質押「介面」只是一種ERC 20 代幣:將你的ETH 轉換為「質押ETH」,持有它,然後再轉換回來。事實上, Lido 和 Rocket Pool 等流動性質押提供者已經開始這麼做了。然而,流動性質押有一些自然的中心化機制在起作用:人們自然會進入最大版本的質押ETH,因為它是最熟悉和最具流動性的。

每個版本的質押ETH 都需要有一些機制來確定誰可以成為底層節點運營商。它不能是無限制的,因為這樣攻擊者就會加入並利用使用者的資金擴大攻擊。目前,排名前兩位的是Lido 和 Rocket Pool ,前者擁有DAO 白名單節點運營商,後者允許任何人在存入8 枚ETH 的情況下運行一個節點。這兩種方法有不同的風險:Rocket Pool 方法允許攻擊者對網路進行51% 的攻擊,並迫使用戶支付大部分成本;至於DAO 方法,如果某質押代幣占主導地位,就會導致單一的、可能受到攻擊的治理小工具控制所有以太坊驗證者的很大一部分。值得肯定的是,像Lido 這樣的協議已經實施了防範措施,但一層防禦可能還不夠。

在短期內,一種選擇是鼓勵生態系統參與者使用多樣化的流動性質押提供商,以減少一家獨大帶來系統性風險的可能性。然而,從長期來看,這是一種不穩定的平衡,過度依賴道德壓力來解決問題是危險的。一個自然的問題出現了:在協議中封裝某種功能以使流動性質押不那麼中心化是否有意義?

這裡的關鍵問題是:什麼樣的協定內功能?簡單地創建一個協議內可替代的「質押ETH」代幣存在一個問題,即它要么必須有一個封裝以太坊範圍內治理來選擇誰來運行節點,要么是開放的,但這會把它變成攻擊者的工具。

一個有趣的想法是Dankrad Feist 關於流動性質押最大化的文章。首先,我們咬緊牙關,如果以太幣受到51% 攻擊,可能只有5% 的攻擊ETH 被罰沒。這是一個合理的權衡;目前有超過2600 萬枚ETH 被質押,其中三分之一(約800 萬枚ETH)的攻擊成本是過度的,特別是考慮到有多少種“模型外”攻擊可以以更低的成本完成。事實上,類似的權衡已經在「超級委員會」關於實施single-slot finality 的提案中進行了探討。

如果我們接受只有5% 的攻擊ETH 被罰沒,那麼超過90% 的質押ETH 將不會受到罰沒的影響,因此它們可以作為協議內可替代流動性質押代幣,然後被其他應用程式使用。

這條路徑很有趣。但它仍然留下了一個問題:具體封裝什麼? Rocket Pool 的運作方式與此非常相似:每個節點業者提供一些資金,流動性質押者提供其餘的資金。我們可以簡單地調整一些常數,將最大罰沒懲罰限制為2 枚ETH,Rocket Pool 現有的rETH 將變得無風險。

透過簡單的協議調整,我們還可以做其他聰明的事情。例如,假設我們想要一個系統,有兩種「層」的質押:節點運營商(高抵押品要求)和儲戶(沒有最低抵押品要求,可以隨時加入和離開),但我們仍然希望透過賦予一個隨機抽樣的儲戶委員會權力來防止節點運營商的中心化,例如建議必須包括的交易清單(出於抗審查的原因),在不活動洩漏期間控制分叉選擇,或需要在區塊上簽名。這可以透過一種基本上脫離協議的方式來實現,方法是調整協議,要求每個驗證器提供(i)一個常規的質押密鑰,以及(ii)一個ETH 位址,該位址可以在每個槽間被調用以輸出二級質押密鑰。該協議將賦予這兩項金鑰權力,但在每個槽中選擇第二個金鑰的機制可以留給質押池協定。直接封裝一些功能可能仍然更好,但值得注意的是,這種「包含一些東西,把其他東西留給使用者」的設計空間是存在的。

封裝更多預編譯

預編譯(或稱「預編譯合約」)是實現複雜加密操作的以太坊合約,其邏輯在客戶端程式碼中原生實現,而不是EVM 智能合約程式碼。預編碼是以太坊開發之初採用的一種折衷方案:由於虛擬機的開銷對於某些非常複雜和高度專業化的代碼來說太大了,我們可以在本地代碼中實現一些對重要應用程序有價值的關鍵操作,以使其更快。如今,這基本上包括一些特定的雜湊函數和橢圓曲線運算。

目前有人在推動為secp 256 r 1 添加預編譯,這是一種與用於基本以太坊帳戶的secp 256 k 1 略有不同的橢圓曲線,因為它得到了可信硬體模組的良好支持,因此廣泛使用它可以提高錢包安全性。近年來,社群也推動為BLS-12-377、BW 6-761、廣義配對和其他功能添加預編譯。

對這些要求更多預編譯檔案的反駁是,先前加入的許多預編譯(例如RIPEMD 和BLAKE)最終的使用量遠低於預期,我們應該從中學習。與其為特定操作添加更多的預編譯,我們也許應該專注於一種更溫和的方法,該方法基於EVM- MAX 和休眠但始終可恢復的SIMD 提案等思想,這將使EVM 實現能夠以更低的成本執行廣泛的程式碼類別。也許即使是現有的很少使用的預編譯也可以被刪除,並用相同函數的EVM 程式碼實現(不可避免地效率較低)代替。也就是說,仍然有可能存在特定的加密操作,這些操作的價值足以加速,因此將它們作為預編譯添加是有意義的。

我們從這一切中學到了什麼?

盡可能少封裝的願望是可以理解的,也是好的;它源自於 Unix 哲學傳統,即創建極簡的軟體,可以輕鬆適應用戶的不同需求,避免軟體膨脹的詛咒。然而,區塊鏈不是個人運算作業系統,而是社會系統。這意味著在協議中封裝某些功能是有意義的。

在許多情況下,這些其他的例子與我們在帳戶抽像中看到的類似。但我們也學到了一些新的教訓:

封裝功能可以幫助避免堆疊中其他區域的中心化風險:

通常,保持基本協議的最小化和簡單性會將複雜性推到一些協議之外的生態系統。從Unix 哲學的角度來看,這很好。然而,有時存在協議外生態系統將中心化的風險,通常(但不僅僅是)因為高固定成本。封裝有時可以減少事實上的中心化。

封裝太多內容,可能會過度擴大協議的信任和治理負擔:

這是前一篇關於「不要讓以太坊共識過載」文章的主題:如果封裝一個特定的功能削弱了信任模型,並使以太坊作為一個整體變得更加「主觀」,這就削弱了以太坊的可信中立性。在這些情況下,最好將特定功能作為以太坊之上的機制,而不是試圖將其引入以太坊本身。在這裡,加密記憶體池是最好的例子,它可能有點難以封裝,至少在延遲加密技術改進之前是如此。

封裝太多內容可能會使協議過於複雜:

協定複雜性是一種系統性風險,在協定中添加太多功能會增加這種風險。預編譯就是最好的例子。

長期來看,封裝功能可能會適得其反,因為使用者的需求是不可預測的:

一個很多人認為很重要並且會被很多用戶使用的功能,很可能在實踐中並沒有被經常使用。

此外,流動性質押、ZK-EVM 和預編譯案例顯示了一條中間道路的可能性:最小可行封裝(minimal viable enshrinement)。協議不需要封裝整個功能,而可以包含解決關鍵挑戰的特定部分,使該功能易於實現,而不會過於偏執或過於狹隘。這樣的例子包括:

與其封裝一個完整的流動性質押系統,不如改變質押懲罰規則,讓去信任流動性質押更可行;

與其封裝更多的預編譯器,不如封裝EVM-MAX 和/或SIMD,以使更廣泛的操作類別更容易有效地實現;

可以簡單地封裝EVM 驗證,而不是封裝rollup 的整個概念。

我們可以將前面的圖表擴展如下:

有時候,去封裝一些東西是有意義的,去除很少使用的預編譯就是一個例子。帳戶抽象化作為一個整體,如前面提到的,也是一種重要的去封裝形式。如果我們想支援現有用戶的向後相容性,那麼該機制實際上可能與去封裝預編譯的機制驚人地相似:其中一個提案是EIP-5003,它將允許EOA 將其帳戶轉換為具有相同(或更好)功能的合約。

哪些功能應該被引入協議,哪些功能應該留給生態系統的其他層,這是一個複雜的權衡。隨著我們對用戶需求的理解以及可用想法和技術套件的不斷改進,這種權衡有望隨著時間的推移而繼續改進。

Total
0
Shares
Related Posts