這是用戶在 2024-4-29 12:24 為 https://increase.com/articles/no-abstractions 保存的雙語快照頁面,由 沉浸式翻譯 提供雙語支持。了解如何保存?
Article 文章
No Abstractions: an Increase API design principle
沒有抽象化:一個增加 API 設計原則
No abstractions
API resources are the nouns of your API. Deciding how to name and model these nouns is arguably the hardest and most important part of designing an API. The resources you expose organize your users’ mental model of how your product works and what it can do. At Increase, our team has used a principle called “no abstractions” to help. What do we mean by this?
API 資源是您的 API 的名詞。決定如何命名和建模這些名詞可以說是設計 API 中最難且最重要的部分。您公開的資源組織了您的用戶對您的產品如何運作以及它可以做什麼的心智模型。在 Increase,我們的團隊使用了一個名為“沒有抽象化”的原則來幫助。這是什麼意思呢?


Much of our team came from Stripe, and when designing our API we considered the same values that have been successful there. Stripe excels at designing abstractions in their API — extracting the essential features of a complex domain into something their users can easily understand and work with. In their case this most notably means modeling payments across many different networks into an API resource called a PaymentIntent . For example, Visa and Mastercard have subtly different reason codes for why a chargeback can be initiated, but Stripe combines those codes into a single enum so that their users don’t need to consider the two networks separately.
我們的團隊中有許多人來自 Stripe,在設計我們的 API 時,我們考慮了在那裡取得成功的相同價值觀。Stripe 擅長在他們的 API 中設計抽象化——將複雜領域的基本特徵提取為他們的用戶可以輕鬆理解和使用的東西。在他們的情況下,這最明顯地意味著將許多不同網絡上的付款建模為一個名為 PaymentIntent 的 API 資源。例如,Visa 和 Mastercard 對於為什麼可以發起退款有微妙不同的原因代碼,但 Stripe 將這些代碼組合成一個單一的枚舉,這樣他們的用戶就不需要分別考慮這兩個網絡。


This makes sense because many of Stripe’s users are early startups working on products totally unrelated to payments. They don't necessarily know, or need to know, about the nuances of credit cards. They want to integrate Stripe quickly, get back to building their product, and stop thinking about payments.
這是有道理的,因為許多 Stripe 的用戶是早期創業公司,專注於與支付無關的產品。 他們不一定知道,也不需要知道信用卡的細微差別。 他們想要快速集成 Stripe,回到建立產品的工作中,不再考慮支付的事情。
“For Increase users, trying to hide the underlying complexity of these networks would irritate them, not simplify their lives.”
“對於 Increase 的用戶來說,試圖隱藏這些網絡的基本複雜性將使他們感到惱火,而不是簡化他們的生活。”
Increase’s users are not like this. They often have deep existing knowledge of payment networks, think about financial technology all the time, and come to us because of our direct network connections and the depth of integration that lets them build. They want to know exactly when the FedACH window closes and when transfers will land. They understand that setting a different Standard Entry Class code on an ACH transfer can result in different return timing. Trying to hide the underlying complexity of these networks (by, for example, modeling ACH transfers and wire transfers with a single API resource) would irritate them, not simplify their lives.
Increase 的用戶不是這樣的。 他們通常對支付網絡有深入的了解,一直在思考金融科技,並來找我們是因為我們的直接網絡連接和深度集成讓他們可以建立。 他們想要確切地知道 FedACH 窗口何時關閉以及轉帳何時到賬。 他們明白在 ACH 轉帳上設置不同的標準條目類別代碼可能導致不同的退回時間。 試圖隱藏這些網絡的基本複雜性(例如,通過將 ACH 轉帳和電匯轉帳建模為單一 API 資源)將使他們感到惱火,而不是簡化他們的生活。


Early conversations with these users helped us articulate what we dubbed the “no abstractions” principle as we built the first version of our API. Some examples of the way this mindset has subsequently affected its design:
與這些用戶的早期對話幫助我們表達了我們在構建 API 的第一個版本時所稱之為“無抽象”原則。這種思維方式後來如何影響了其設計的一些示例:
Real-world naming 現實世界的命名
Instead of inventing our own names for API resources and their attributes, we tend to use the vocabulary of the underlying networks. For example, the parameters we expose when making an ACH transfer via our API are named after fields in the Nacha specification.
我們傾向於使用底層網絡的詞彙,而不是為 API 資源及其屬性創造我們自己的名稱。例如,通過我們的 API 進行 ACH 轉帳時公開的參數是根據 Nacha 規範中的字段命名的。
Immutability 不變性
Similar to how we use network nomenclature, we try to model our resources after real-world events like an action taken or a message sent. This results in more of our API resources being immutable. An approach that’s worked well for our API is to take a cluster of these immutable resources (all of the network messages that can be sent as part of the ACH transfer lifecycle, for example) and group them together under a state machine “lifecycle object”. For example, the ach_transfer object in our API has a field called status that changes over time, and several immutable sub-objects that are created as the transfer moves through its lifecycle. A newly-minted ach_transfer object looks like:
與我們使用網絡術語的方式類似,我們試圖將我們的資源建模為現實世界中的事件,如採取的行動或發送的消息。這導致我們的 API 資源更多地是不可變的。對我們的 API 運作良好的一種方法是將這些不可變資源的集群(例如作為 ACH 轉帳生命週期的一部分可以發送的所有網絡消息)捆綁在一起,放在一個狀態機“生命週期對象”下。例如,我們的 API 中的 ach_transfer 對象有一個隨時間變化的字段 status ,以及幾個不可變的子對象,隨著轉帳在其生命週期中移動而被創建。一個新創建的 ach_transfer 對象看起來像:
{ "id": "ach_transfer_abc123", "created_at": "2024-04-24T00:00:00+00:00", "amount": 1000, "status": "pending_approval", "approval": null, "submission": null, "acknowledgement": null // other fields omitted here for clarity }
After that same transfer has moved through our pipeline and we’ve submitted it to FedACH, it looks like:
在同一筆轉帳通過我們的管道並提交給 FedACH 後,它看起來像:
{ "id": "ach_transfer_abc123", "created_at": "2024-04-24T00:00:00+00:00", "amount": 1000, "status": "submitted", // immutable, populated when the transfer is approved "approval": { "approved_by": "administrator@yourcompany.com", "approved_at": "2024-04-24T01:00:00+00:00" }, // immutable, populated when the transfer is submitted "submission": { "trace_number": "058349238292834", "submitted_at": "2024-04-24T02:00:00+00:00" }, // immutable, populated when the transfer is acknowledged "acknowledgement": { "acknowledged_at": "2024-04-24T03:00:00+00:00" } // other fields omitted for clarity }
Separating resources by use case
根據使用情況分離資源
If, for a given API resource, the set of actions a user can take on different instances of the resource varies a lot, we tend to split it into multiple resources. For example, the set of actions you can take on an originated ACH transfer is different (the complete opposite, really) than the actions you can take on a received ACH transfer, so we separate these into ach_transfer and inbound_ach_transfer resources.
如果對於給定的 API 資源,用戶對不同實例採取的操作集合差異很大,我們傾向於將其拆分為多個資源。例如,您可以對發起的 ACH 轉帳採取的操作集合與您可以對收到的 ACH 轉帳採取的操作截然不同,因此我們將其分為 ach_transferinbound_ach_transfer 資源。



This approach can make our API more verbose and intimidating at first glance — there are a lot of resources on the left-hand side of our documentation page! We think it makes things more predictable over the long-term, though.
這種方法可能會使我們的 API 在一瞥之下變得更冗長和令人生畏 - 在我們的文檔頁面的左側有很多資源!但我們認為這樣做可以使事情在長期內更具可預測性。


Importantly, our engineering team has committed to this approach. When you design a complex API over several years, you make small incremental decisions all the time. Committing to foundational principles upfront has reduced the cognitive load for these decisions. For example, when sending a wire transfer to the Federal Reserve, there’s a required field called Input Message Accountability Data which serves as a globally-unique ID for that transfer. When building support for wire transfers, an engineer in an abstraction-heavy API might have to deliberate how to name this field in a “user-friendly” way - trace_number? reference_number? id? At Increase that hypothetical engineer names the field input_message_accountability_data and moves on. When an Increase user encounters this field for the first time, while it might not be the most immediately recognizable name at first, it helps them understand immediately how this maps to the underlying system.
重要的是,我們的工程團隊已經承諾採取這種方法。當你在幾年的時間裡設計一個複雜的 API 時,你會一直做出小的增量決策。事先承諾基本原則已經減少了這些決策的認知負荷。例如,當向聯邦儲備系統發送電匯時,有一個名為輸入消息可靠性數據的必填字段,它作為該轉帳的全球唯一 ID。當建立對電匯的支持時,一個在抽象化 API 中的工程師可能需要考慮如何以“用戶友好”的方式命名這個字段 - trace_number ? reference_number ? id ? 在 Increase,這位假想的工程師將該字段命名為 input_message_accountability_data 並繼續進行。當一個 Increase 用戶第一次遇到這個字段時,雖然一開始可能不是最容易識別的名稱,但它立即幫助他們理解這如何映射到底層系統。


No Abstractions isn’t right for every API, but considering the level of abstraction that’s appropriate for the developers integrating against it is a valuable exercise. This will depend on their level of experience working with your product domain and the amount of energy they’ll be committing to the integration, among other things. If you’re building an abstraction-heavy API, be prepared to think hard before adding new features. If you’re building an abstraction-light API, commit to it and resist the temptation to add abstractions when it comes along.
不是每個 API 都適合沒有抽象化,但考慮適合開發人員集成的抽象化程度是一個有價值的練習。這將取決於他們在您的產品領域中工作經驗的水平以及他們將投入整合的精力等因素。如果您正在構建一個抽象化程度高的 API,請在添加新功能之前做好充分的思考。如果您正在構建一個抽象化程度低的 API,請堅持下去,並抵制在遇到誘惑時添加抽象化的衝動。
Interested in working at Increase?
Email jobs@increase.com to learn more about our open roles.
Banking services provided by First Internet Bank of Indiana, Member FDIC. Increase is a financial technology company, not a bank. Cards Issued by First Internet Bank of Indiana, pursuant to a license from Visa Inc. Deposits are insured by the FDIC up to the maximum allowed by law through First Internet Bank of Indiana, Member FDIC.
由印第安納第一互聯網銀行提供的銀行服務,是 FDIC 的成員。Increase 是一家金融科技公司,而不是銀行。卡片由印第安納第一互聯網銀行根據 Visa Inc.的許可發行。存款通過印第安納第一互聯網銀行進行保險,最高保險金額不超過法律允許的範圍,FDIC 的成員。