Suponha que você tenha um grande projeto suportado por uma base de API. O projeto também envia uma API pública que os usuários finais (ish) podem usar.
Às vezes, você precisa fazer alterações na base da API que suporta seu projeto. Por exemplo, você precisa adicionar um recurso que precise de uma alteração na API, um novo método ou exija a alteração de um dos objetos ou o formato de um desses objetos, passados para ou a partir da API.
Supondo que você também esteja usando esses objetos em sua API pública, os objetos públicos também serão alterados sempre que você fizer isso, o que é indesejável, pois seus clientes podem confiar nos objetos da API que permanecem idênticos para que seu código de análise funcione. (tosse clientes C ++ WSDL ...)
Portanto, uma solução potencial é a versão da API. Mas quando dizemos "version" a API, parece que isso também deve significar a versão dos objetos da API, além de fornecer chamadas de método duplicadas para cada assinatura de método alterada. Então, eu teria um objeto clr antigo e simples para cada versão da minha API, o que novamente parece indesejável. E mesmo que eu faça isso, certamente não construirei cada objeto do zero, pois isso acabaria com grandes quantidades de código duplicado. Em vez disso, é provável que a API estenda os objetos particulares que estamos usando para a API base, mas depois enfrentamos o mesmo problema, porque propriedades adicionadas também estariam disponíveis na API pública quando não deveriam.
Então, que sanidade geralmente é aplicada a essa situação? Conheço muitos serviços públicos, como o Git for Windows, que mantém uma API com versão, mas estou tendo problemas para imaginar uma arquitetura que suporte isso sem grandes quantidades de código duplicado que abrangem os vários métodos e objetos de entrada / saída.
Estou ciente de que processos como o controle de versão semântico tentam melhorar a integridade quando ocorrem quebras de API públicas. O problema é mais: parece que muitas ou a maioria das alterações exigem quebra da API pública se os objetos não estiverem mais separados, mas não vejo uma boa maneira de fazer isso sem duplicar o código.
fonte
I don't see a good way to do that without duplicating code
- Sua nova API sempre pode chamar métodos em sua API antiga ou vice-versa.Respostas:
Ao manter uma API usada por terceiros, é inevitável que você precise fazer alterações. O nível de complexidade dependerá do tipo de mudança que está ocorrendo. Estes são os principais cenários que surgem:
Nova funcionalidade adicionando à API existente
Este é o cenário mais fácil de suportar. Adicionar novos métodos a uma API não deve exigir nenhuma alteração nos clientes existentes. É seguro implantar para os clientes que precisam da nova funcionalidade, pois não possui atualizações para nenhum cliente existente.
Funcionalidade antiga preterida na API
Nesse cenário, você deve comunicar aos consumidores existentes da sua API que a funcionalidade não será suportada a longo prazo. Até que você abandone o suporte para a funcionalidade antiga (ou até que todos os clientes tenham atualizado para a nova funcionalidade), você deve manter a funcionalidade antiga e nova da API ao mesmo tempo. Se for uma biblioteca fornecida, a maioria dos idiomas pode marcar métodos antigos como obsoletos / obsoletos. Se for de algum tipo um serviço de terceiros, geralmente é melhor ter pontos de extremidade diferentes para a funcionalidade antiga / nova.
Funcionalidade existente na API mudando de alguma maneira
Este cenário dependerá do tipo de alteração. Se os parâmetros de entrada não precisarem mais ser usados, basta atualizar o serviço / biblioteca para ignorar os dados extras agora. Em uma biblioteca, o método sobrecarregado chama internamente o novo método que requer menos parâmetros. Em um serviço hospedado, o terminal ignora dados extras e ele pode atender a ambos os tipos de clientes e executar a mesma lógica.
Se a funcionalidade existente precisar adicionar novos elementos necessários, você deverá ter dois pontos de extremidade / métodos para seu serviço / biblioteca. Até a atualização dos clientes, você precisa oferecer suporte às duas versões.
outros pensamentos
Rather, the API is likely to extend the private objects we are using for our base API, but then we run into the same problem because added properties would also be available in the public API when they are not supposed to be.
Não exponha objetos particulares internos através da sua biblioteca / serviço. Crie seus próprios tipos e mapeie a implementação interna. Isso permitirá que você faça alterações internas e minimize a quantidade de atualizações que os clientes externos precisam fazer.
The problem is more that it seems like many or most changes require breaking the public API if the objects aren't more separated, but I don't see a good way to do that without duplicating code.
A API, seja um serviço ou uma biblioteca, precisa estar estável no ponto de integração com os clientes. Quanto mais tempo você gasta para identificar quais devem ser as entradas e saídas e mantê-las como entidades separadas, você economizará muitas dores de cabeça no caminho. Faça com que a API contrate sua própria entidade separada e mapeie para as classes que fornecem o trabalho real. O tempo economizado quando as implementações internas mudam deve compensar o tempo extra necessário para definir a interface extra.
Não veja esta etapa como "código duplicado". Embora semelhantes, são entidades separadas que valem a pena ser criadas. Embora as alterações externas da API quase sempre exijam uma alteração correspondente à implementação interna, as alterações internas da implementação nem sempre devem alterar a API externa.
Exemplo
Suponha que você esteja fornecendo uma solução de processamento de pagamento. Você está usando o PaymentProviderA para fazer transações com cartão de crédito. Mais tarde, você obtém uma taxa melhor através do processador de pagamento do PaymentProviderB. Se sua API expôs os campos Cartão de crédito / Endereço de cobrança do seu tipo, em vez da representação de PaymentProviderA, a alteração da API é 0, pois a interface permaneceu a mesma (esperamos que seja, de qualquer maneira, se PaymentProviderB exigir dados que não foram exigidos por PaymentProviderA, você precisará escolher entre suporte para ambos ou mantenha a pior taxa com PaymentProviderA).
fonte