Implementando uma camada oculta de complexidade


8

Como parte das dependências do projeto em que estou trabalhando, usamos vários serviços principais. Esses serviços, para os quais não podemos fazer grandes mudanças, são uma grande bagunça. Dependendo do método que invocamos, precisamos converter nossos parâmetros (e retornar valores) em diferentes codificações, localidades e fusos horários.

Como geramos esses parâmetros em vários locais em nosso próprio código, realizamos essas conversões em vários locais. Algumas vezes em que os geramos, antes de passá-los ao nosso lado; algumas vezes antes de invocar o método no serviço principal. Portanto, a bagunça está se espalhando por todo o código e quero introduzir uma camada para isolá-lo.

Minha pergunta é qual é a melhor abordagem para isso. Inicialmente, pensei em apenas criar um serviço / método correspondente a cada serviço / método que precisamos usar. Esses métodos simplesmente executariam a conversão, delegariam nos serviços principais e executariam a conversão do valor de retorno. Mas isso parece de alguma forma pesado.

Então pensei em usar anotações, mas não tenho certeza de como usá-las. E, pelo que entendi, o ideal seria anotar o método invocado. Por exemplo, eu poderia anotar os parâmetros com @converToUtce fazer a conversão na implementação da anotação. Isso está correto? Obviamente, isso é difícil porque não é o nosso código e ele quebrará o código atualmente usando esses métodos em outros projetos que não o nosso.

Qual é a melhor abordagem para esta situação?


6
Um termo comum para isso é a camada anti-corrupção, se você quiser procurar.
Esben Skov Pedersen

Respostas:


6

O que você está tentando fazer é implementar o padrão de fachada . Basicamente, você deseja colocar uma face mais simples no código principal. Você provavelmente desejará criar um conjunto de classes que forneça um mapeamento 1: 1 para cada classe principal e, em seguida, use as classes de fachada no lugar das classes principais. Se os serviços principais são apenas um monte de métodos em alguma classe monolítica grande, considere dividi-los por domínio funcional (por exemplo, autenticação, acesso a dados, função comercial etc.) e ter uma fachada diferente para cada domínio. Sua fachada deve apresentar uma interface que faça sentido para o seu código e lidar com todo o mapeamento e conversão de dados necessários para se comunicar com os serviços principais.


6

O problema que você está enfrentando é uma instância de um problema geral que geralmente enfrentamos na Engenharia de Software: Moldando as ferramentas para trazê-las ao nosso domínio de problemas específico por meio de camadas de abstração / conversão.

Você tem um aplicativo que resolve um problema. As entidades que ele contém, gerencia e interage são entidades que pertencem ao domínio do problema. Todos eles são expressos em termos úteis para resolver o problema em questão e são "amigáveis", pois permitem que você se concentre em resolver o problema em vez de perder tempo e poluir seu código com conversões que não têm nada a ver com o problema. problema em questão.

Contanto que você possua todo o código, tudo ficará bem; mas quando você coloca em cena ferramentas de terceiros (bibliotecas), essas ferramentas provavelmente não foram escritas para funcionar no domínio do seu problema; portanto, exigem conversões que geralmente são perturbadoras, complicadas e propensas a erros.

O que geralmente acontece é que os inconvenientes são pequenos e apenas lidamos com as ferramentas que recebemos. Mas quando os inconvenientes são grandes, tanto que tornam a nossa vida diária consideravelmente mais difícil, ou que o resultado final é mais frágil e mais suscetível a erros, às vezes introduzimos camadas de abstração / conversão entre nosso código e as ferramentas que usamos .

Essas camadas de abstração / conversão oferecem serviços ao nosso código, expressos em termos do domínio do problema, e são delegados às ferramentas de terceiros, realizando todas as conversões necessárias ao longo do caminho. Ao fazer isso, essas camadas tendem a abstrair o máximo possível as peculiaridades das ferramentas que usamos, para que, em teoria, possamos substituir uma ferramenta por uma ferramenta diferente, modificando apenas as camadas de abstração / conversão, sem precisamos modificar nossa lógica principal.

Em relação às anotações, não vejo como elas podem ajudar aqui. Primeiro de tudo, se você não possui o código fonte das interfaces de destino, não poderá adicionar anotações a elas. Mas mesmo se você pudesse adicionar anotações às interfaces de destino, para que as anotações funcionassem, seria necessário incorporar uma camada intermediária entre o código e as interfaces de destino, que intercepta as chamadas, examina as anotações dos métodos de destino e executa o procedimento conversões necessárias. Talvez você possa usar o Spring Framework ou algo como o Interceptor do Castle Proxy mecanismo para incorporar magicamente essa camada intermediária entre seu código e as bibliotecas, mas parece-me que você poderia facilmente escrever a camada intermediária de maneira tradicional, tendo um conhecimento profundo das interfaces de destino, realizando as conversões de forma codificada , de maneira direta e também abstraindo as interfaces das bibliotecas para atender às suas necessidades.


0

Primeiro de tudo, você (ou sua equipe) precisa concordar com um formato "padrão" que você usará em seu próprio código. Por exemplo:

  • Codificação: UTF-8
  • Localidade: en_UK
  • Fuso Horário: UTC

Somente depois, você poderá escrever uma camada que adaptará os valores aos formatos solicitados pelas suas dependências (não acho que seja pesado).

Como Mike Nakis disse, também não vejo nenhum benefício em usar anotações para resolver esse problema.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.