- As decisões de nomenclatura e modelagem de recursos de API são a parte mais difícil e importante do design de APIs. Os recursos formam o modelo mental dos usuários sobre como o produto funciona e quais são suas funcionalidades.
- A equipe da Increase usa o princípio de "sem abstrações" para orientar o design de APIs.
Abordagem da Stripe para design de API
- Uma parte significativa da equipe da Increase trabalhou anteriormente na Stripe e leva em conta os valores de design de API que fizeram sucesso na Stripe.
- A Stripe é excelente em extrair a funcionalidade central de domínios complexos em abstrações que os usuários conseguem entender e usar com facilidade. (Ex.:
PaymentIntent, que abstrai as diferenças entre Visa e Mastercard)
- A maioria dos usuários da Stripe são startups em estágio inicial desenvolvendo produtos sem relação com pagamentos, então não precisam conhecer os detalhes de cartões de crédito. Eles querem integrar a Stripe rapidamente e se concentrar no desenvolvimento do produto.
Usuários da Increase e princípios de design de API
- Já os usuários da Increase têm conhecimento profundo sobre redes de pagamento, e o motivo de escolherem a Increase é justamente a conexão direta com a rede e a profundidade da integração.
- Eles querem saber exatamente quando a janela do FedACH se fecha e em que momento uma transferência ocorre, e entendem que configurar códigos SEC diferentes em transferências ACH pode afetar o timing de retorno.
- Tentar esconder a complexidade fundamental dessas redes não simplifica a vida deles; só causa frustração.
- A partir de conversas com os primeiros usuários, a equipe chegou ao princípio de "sem abstrações" e o aplicou ao design da API.
Como o princípio de "sem abstrações" influenciou o design da API
- Uso da terminologia real: em vez de criar nomes próprios para recursos e propriedades da API, a equipe usa o vocabulário da rede subjacente. (Ex.: os parâmetros de transferências ACH usam os nomes de campos da especificação Nacha)
- Imutabilidade: ao usar eventos reais como modelo, mais recursos da API se tornam imutáveis. Funciona bem agrupar clusters de recursos imutáveis em objetos de ciclo de vida de máquina de estados. (Ex.: o campo
status do objeto ach_transfer e alguns subobjetos imutáveis gerados conforme o ciclo de vida da transferência avança)
- Separação de recursos por caso de uso: quando o conjunto de ações que o usuário pode executar varia muito dependendo da instância do recurso, ele é dividido em vários recursos. (Ex.: transferências ACH de saída e de entrada são separadas em recursos distintos)
Aderência da equipe de engenharia à abordagem
- A equipe de engenharia se comprometeu a seguir essa abordagem.
- Ao projetar uma API complexa por anos, é preciso tomar continuamente pequenas decisões incrementais; assumir previamente o compromisso com princípios básicos reduz a carga cognitiva dessas decisões.
- Por exemplo, no caso do campo Input Message Accountability Data, necessário ao enviar dinheiro ao Federal Reserve, em uma API com muitas abstrações seria preciso pensar em como dar a esse campo um nome mais "amigável"; na Increase, o engenheiro simplesmente o nomeia como
input_message_accountability_data e segue em frente.
Opinião do GN⁺
- O nível de abstração de uma API pode variar conforme o nível de experiência do desenvolvedor no domínio do produto e a energia que ele pretende investir na integração. Por isso, ao projetar uma API, é importante considerar o nível de abstração adequado para os desenvolvedores que vão integrá-la.
- Se você estiver construindo uma API com alto nível de abstração, é preciso pensar com cuidado antes de adicionar novas funcionalidades. Por outro lado, se estiver construindo uma API com baixo nível de abstração, é importante manter essa linha e resistir à tentação de adicionar abstrações.
- Usar diretamente a terminologia da rede ou do protocolo subjacente pode ajudar os desenvolvedores a entender o underlying system, mas também pode se tornar uma barreira de entrada para quem está tendo o primeiro contato. Por isso, parece importante investir bem em comentários e documentação.
- Utilizar objetos immutable no design de APIs pode ser eficaz para manter a consistência dos dados e evitar side effects. Por outro lado, pode ser inconveniente quando atualizações de dados são necessárias, então é preciso considerar bem esse trade-off.
- Separar recursos por caso de uso pode aumentar a complexidade da API, mas no longo prazo pode elevar a previsibilidade. Ainda assim, se houver granularidade excessiva, a usabilidade pode cair, então é importante encontrar um nível adequado.
1 comentários
Opiniões no Hacker News
É bom oferecer tanto APIs com abstrações de baixo nível quanto APIs com abstrações de alto nível
Gostei da parte que explica por que a Increase escolheu uma abordagem diferente
A verdadeira capacidade da Stripe está em conhecer seus clientes e oferecer a simplicidade que eles querem
Isso se parece com o padrão de projeto "Ubiquitous Language" da Domain-Driven Design, em que a implementação usa os mesmos termos reais usados pelos especialistas do domínio
É preciso usar uma linguagem que os especialistas do domínio consigam entender
Sem uma abstração como POSIX, os aplicativos teriam que escrever adaptadores para todos os sistemas de arquivos suportados
Dizem que parte da estrutura da API é construída em uma relação 1:1 com base em especificações controladas externamente
Uma coisa difícil de modelar de forma limpa em APIs de pagamento é que os sistemas de pagamento representam de maneiras diferentes os papéis de pagador e recebedor em devoluções de pagamento