Padrão de camada anticorrupção - AWS Orientação prescritiva

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Padrão de camada anticorrupção

Intenção

O padrão da camada anticorrupção (ACL) atua como uma camada de mediação que traduz a semântica do modelo de domínio de um sistema para outro. Ele traduz o modelo do contexto limitado a montante (monólito) em um modelo adequado ao contexto limitado a jusante (microsserviço) antes de consumir o contrato de comunicação estabelecido pela equipe de upstream. Esse padrão pode ser aplicável quando o contexto limitado a jusante contém um subdomínio principal ou o modelo upstream é um sistema legado não modificável. Também reduz o risco de transformação e a interrupção dos negócios, evitando alterações nos chamadores quando suas chamadas precisam ser redirecionadas de forma transparente para o sistema de destino.

Motivação

Durante o processo de migração, quando um aplicativo monolítico é migrado para microsserviços, pode haver mudanças na semântica do modelo de domínio do serviço recém-migrado. Quando os recursos do monólito são necessários para chamar esses microsserviços, as chamadas devem ser roteadas para o serviço migrado sem exigir nenhuma alteração nos serviços de chamada. O padrão ACL permite que o monólito chame os microsserviços de forma transparente, atuando como um adaptador ou uma camada de fachada que traduz as chamadas para a nova semântica.

Aplicabilidade

Considere usar esse padrão quando:

  • Seu aplicativo monolítico existente precisa se comunicar com uma função que foi migrada para um microsserviço, e o modelo e a semântica do domínio do serviço migrado diferem do recurso original.

  • Dois sistemas têm semântica diferente e precisam trocar dados, mas não é prático modificar um sistema para ser compatível com o outro sistema.

  • Você quer usar uma abordagem rápida e simplificada para adaptar um sistema a outro com o mínimo impacto.

  • Seu aplicativo está se comunicando com um sistema externo.

Questões e considerações

  • Dependências da equipe:Quando diferentes serviços em um sistema pertencem a equipes diferentes, a nova semântica do modelo de domínio nos serviços migrados pode levar a mudanças nos sistemas de chamada. No entanto, as equipes podem não conseguir fazer essas mudanças de forma coordenada, porque elas podem ter outras prioridades. A ACL separa os chamadores e traduz as chamadas para corresponder à semântica dos novos serviços, evitando assim a necessidade de os chamadores fazerem alterações no sistema atual.

  • Despesas operacionais:O padrão ACL exige um esforço adicional para operar e manter. Esse trabalho inclui a integração da ACL com ferramentas de monitoramento e alerta, o processo de liberação e os processos de integração contínua e entrega contínua (CI/CD).

  • Ponto único de falha:Qualquer falha na ACL pode tornar o serviço de destino inacessível, causando problemas no aplicativo. Para mitigar esse problema, você deve incorporar recursos de repetição e disjuntores. Veja otente novamente com recuoedisjuntorpadrões para entender mais sobre essas opções. A configuração de alertas e registros apropriados melhorará o tempo médio de resolução (MTTR).

  • Dívida técnica:Como parte de sua estratégia de migração ou modernização, considere se a ACL será uma solução transitória ou provisória ou uma solução de longo prazo. Se for uma solução provisória, você deve registrar a ACL como uma dívida técnica e desativá-la após a migração de todos os chamadores dependentes.

  • Latência:A camada adicional pode introduzir latência devido à conversão de solicitações de uma interface para outra. Recomendamos que você defina e teste a tolerância de desempenho em aplicativos sensíveis ao tempo de resposta antes de implantar a ACL em ambientes de produção.

  • Gargalo de escalabilidade:Em aplicativos de alta carga em que os serviços podem ser escalados até o pico de carga, a ACL pode se tornar um gargalo e causar problemas de escalabilidade. Se o serviço alvo for escalado sob demanda, você deverá projetar a ACL para escalar adequadamente.

  • Implementação compartilhada ou específica do serviço:Você pode criar a ACL como um objeto compartilhado para converter e redirecionar chamadas para vários serviços ou classes específicas do serviço. Leve em consideração a latência, a escalabilidade e a tolerância a falhas ao determinar o tipo de implementação da ACL.

Implementação

Você pode implementar a ACL em seu aplicativo monolítico como uma classe específica para o serviço que está sendo migrado ou como um serviço independente. A ACL deve ser desativada após a migração de todos os serviços dependentes para a arquitetura de microsserviços.

Arquitetura de alto nível

No exemplo de arquitetura a seguir, um aplicativo monolítico tem três serviços: serviço de usuário, serviço de carrinho e serviço de conta. O serviço de carrinho depende do serviço do usuário, e o aplicativo usa um banco de dados relacional monolítico.

Aplicação monolítica com três serviços.

Na arquitetura a seguir, o serviço do usuário foi migrado para um novo microsserviço. O serviço de carrinho chama o serviço do usuário, mas a implementação não está mais disponível no monólito.  Também é provável que a interface do serviço recém-migrado não corresponda à interface anterior, quando estava dentro do aplicativo monolítico.

Aplicativo monolítico em que um serviço é movido para um microsserviço.

Se o serviço de carrinho precisar ligar diretamente para o serviço de usuário recém-migrado, isso exigirá alterações no serviço de carrinho e um teste completo do aplicativo monolítico. Isso pode aumentar o risco de transformação e a interrupção dos negócios. O objetivo deve ser minimizar as alterações na funcionalidade existente do aplicativo monolítico.

Nesse caso, recomendamos que você introduza uma ACL entre o serviço de usuário antigo e o serviço de usuário recém-migrado. A ACL funciona como um adaptador ou uma fachada que converte as chamadas na interface mais recente. A ACL pode ser implementada dentro do aplicativo monolítico como uma classe (por exemplo,UserServiceFacadeouUserServiceAdapter) que é específico para o serviço que foi migrado. A camada anticorrupção deve ser desativada após a migração de todos os serviços dependentes para a arquitetura de microsserviços.

Adicionando uma camada anticorrupção.

Implementação usandoAWSserviços

O diagrama a seguir mostra como você pode implementar esse exemplo de ACL usandoAWSserviços.

Implementando o padrão ACL comAWSserviços.

O microsserviço do usuário é migrado do aplicativo monolítico ASP.NET e implantado como umAWS Lambdafunção na AWS. As chamadas para a função Lambda são roteadas por meio deAmazon API Gateway. A ACL é implantada no monólito para traduzir a chamada e se adaptar à semântica do microsserviço do usuário.

QuandoProgram.cschama o serviço de usuário (UserInMonolith.cs) dentro do monólito, a chamada é roteada para a ACL (UserServiceACL.cs). A ACL traduz a chamada para a nova semântica e interface e chama o microsserviço por meio do endpoint do API Gateway. O chamador (Program.cs) não está ciente da tradução e do roteamento que ocorrem no serviço de usuário e na ACL. Como o chamador não está ciente das alterações no código, há menos interrupções nos negócios e menor risco de transformação.

Código de exemplo

O trecho de código a seguir fornece as alterações no serviço original e a implementação doUserServiceACL.cs. Quando uma solicitação é recebida, o serviço de usuário original chama a ACL. A ACL converte o objeto de origem para corresponder à interface do serviço recém-migrado, chama o serviço e retorna a resposta ao chamador.

public class UserInMonolith: IUserInMonolith { private readonly IACL _userServiceACL; public UserInMonolith(IACL userServiceACL) => (_userServiceACL) = (userServiceACL); public async Task<HttpStatusCode> UpdateAddress(UserDetails userDetails) { //Wrap the original object in the derived class var destUserDetails = new UserDetailsWrapped("user", userDetails); //Logic for updating address has been moved to a microservice return await _userServiceACL.CallMicroservice(destUserDetails); } } public class UserServiceACL: IACL { static HttpClient _client = new HttpClient(); private static string _apiGatewayDev = string.Empty; public UserServiceACL() { IConfiguration config = new ConfigurationBuilder().AddJsonFile(AppContext.BaseDirectory + "../../../config.json").Build(); _apiGatewayDev = config["APIGatewayURL:Dev"]; _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); } public async Task<HttpStatusCode> CallMicroservice(ISourceObject details) { _apiGatewayDev += "/" + details.ServiceName; Console.WriteLine(_apiGatewayDev); var userDetails = details as UserDetails; var userMicroserviceModel = new UserMicroserviceModel(); userMicroserviceModel.UserId = userDetails.UserId; userMicroserviceModel.Address = userDetails.AddressLine1 + ", " + userDetails.AddressLine2; userMicroserviceModel.City = userDetails.City; userMicroserviceModel.State = userDetails.State; userMicroserviceModel.Country = userDetails.Country; if (Int32.TryParse(userDetails.ZipCode, out int zipCode)) { userMicroserviceModel.ZipCode = zipCode; Console.WriteLine("Updated zip code"); } else { Console.WriteLine("String could not be parsed."); return HttpStatusCode.BadRequest; } var jsonString = JsonSerializer.Serialize<UserMicroserviceModel>(userMicroserviceModel); var payload = JsonSerializer.Serialize(userMicroserviceModel); var content = new StringContent(payload, Encoding.UTF8, "application/json"); var response = await _client.PostAsync(_apiGatewayDev, content); return response.StatusCode; } }

GitHubrepositório

Para uma implementação completa da arquitetura de exemplo para esse padrão, consulte aGitHubrepositório emhttps://github.com/aws-samples/anti-corruption-layer-pattern.

Conteúdo relacionado