Neste artigo, direi a você, usando a evolução do meu projeto como exemplo, o histórico de transição e a visão da programação de contratos.
Inicialmente, quis nomear o artigo - “Programação de contratos”, na medida em que a abordagem usada é dividir toda a lógica de negócios em contratos de dados e clientes de serviço usando esses contratos e interagindo entre si por essas estruturas de dados, para que os mesmos A estrutura é processada com sucesso em diferentes serviços.
Algo que descreverei em meu próprio idioma.
A história da minha transição para a programação de contratos começou com o fato de eu ter um projeto herdado com um grande conjunto de funcionalidades diferentes na mesma área de negócios. Além disso, tudo isso ainda era multithreading e personalização para diferentes clientes. Especificamente, a área de negócios foi a troca de documentos eletrônicos relevantes legalmente entre o sistema contábil, os arquivos e os serviços em nuvem.
No processo de desenvolvimento do sistema, surgiram novos requisitos de negócios e, como resultado, o projeto se desenvolveu rapidamente e ficou complicado por novas funcionalidades, que em algum momento levaram a uma situação em que a arquitetura do projeto começou a se assemelhar a vários aplicativos separados com funcionalidades relacionadas. Somente essa funcionalidade foi implementada, não a partir de elementos comuns, mas a partir de estruturas semelhantes, mas implementadas de maneira diferente, em diferentes assemblies e namespaces.
Visualmente, essa arquitetura pode ser representada como várias verticais de funcionalidade

Um recurso característico dessa arquitetura era que, se algum requisito ou erro adicional aparecesse, era necessário implementar tal tarefa em todos os "módulos funcionais" do sistema, e não em uma área. Outra característica foi a presença no projeto de um grande número de construtoras, o que levou a uma divisão vertical da área de negócios. O desenvolvedor implementa novos algoritmos para novos requisitos de negócios no código dos construtores, o que leva ao surgimento de novas entidades com estruturas diferentes para o mesmo objeto de negócios. É certo que essa abordagem pode ser considerada mais orientada a objetos do que uma abordagem simples por trás de código com código espaguete. Portanto, se você vir um grande número de construtores em seus projetos, a transição para uma abordagem de contato simplificará o suporte e acelerará o desenvolvimento do seu projeto.
Uma vez, na empresa, nos deparamos com o fato de que o cliente com o qual estávamos implementando começou a expressar que o sistema que eu desenvolvia frequentemente produzia erros. Não pude argumentar com isso, embora os erros aparecessem periodicamente, mas eles foram corrigidos e alguns dos clientes tinham o sistema instalado e o usavam. Devo agradecer que o cliente foi prejudicial e exigente e testou com muito cuidado nosso sistema durante o período de implementação.
Eu também não gostei do fato de não ter tempo suficiente para desenvolvimento e suporte, apesar de muitos esforços, e em algum momento simplesmente não tinha idéia do que mais poderia melhorar o sistema e torná-lo mais estável.
A decisão veio repentina e inesperadamente.
Entendi que os mesmos objetos de negócios são implementados de maneira diferente em diferentes módulos do sistema - documentos de diferentes tipos, recebimentos, trabalhadores, clientes de serviço, clientes de banco de dados, clientes de arquivo com a capacidade de armazenar documentos em vários formatos (personalização para clientes diferentes;) )
Parte da lógica foi implementada em entidades, o que impediu o uso das mesmas entidades em diferentes algoritmos.
Então eu decidi - era necessário criar algo como um único construtor com detalhes a partir dos quais todos os algoritmos implementados no sistema podem ser montados. O que é lógico, porque reduz o número de classes semelhantes e simplifica o suporte.
Eu decidi dividir estritamente o "universo" da minha aplicação em
- contratos de dados - estruturas de dados que contêm e são usadas apenas para armazenamento de dados
Documentos
Envelopes
Recibos
EP
...
- customers-services - escrevo especificamente que clientes são serviços, porque ao implementar cada sistema que interagiu na área de negócios, eu o representei como um envelope nesse sistema, no qual os métodos para trabalhar com contratos de data foram implementados. Além do fato de essas classes serem invólucros de serviços, elas também continham a lógica de ligação necessária, conversões e transformações para simplificar a lógica de negócios
Além disso, os loggers se apegavam a esses clientes. Isso permitiu encontrar rapidamente o ponto de erro pelo log. (no futuro, muitas chamadas desapareceram quando, pelos registros, os próprios usuários começaram a entender onde estavam errados - um sistema de arquivos, rede, sistema de contabilidade ou serviço da web do operador)
Por exemplo
CloudClient - um cliente de um serviço em nuvem para o qual os documentos são enviados e processados
- Baixar
- enviar
- Obter
- Baixar
- Concordo
...
FileSystemClient - cliente do sistema de arquivos
ERPClient - sistema de contabilidade do cliente
Os clientes implementaram todos os métodos usados anteriormente nos algoritmos em todos os módulos, o que tornou possível implementar rápida e facilmente os novos algoritmos implementados nas mesmas partes.
E a alocação de métodos de funcionalidade semelhantes nos respectivos clientes levou a uma maior especialização e reutilização do código.
A arquitetura agora era um diagrama como na figura

Aloquei todos os objetos básicos do meu designer na montagem com o final do SDK (Software Developers Kit) e ficou mais fácil trabalhar e, o mais importante, mais agradável. O trabalho já deixou de ser a criação de muletas e soluções temporárias, e agora a atitude em relação ao projeto por dentro tornou-se mais séria pelo fato de eu agora ter visto uma enorme margem de escalabilidade e competitividade da arquitetura. Isso ocorre porque esse fato aumentou significativamente a motivação e abriu novos horizontes profissionais.
Com base no SDK criado, entreguei para implementar uma camada de lógica de negócios que automatiza a implementação de tarefas de negócios diretamente. Como todas as nuances técnicas foram trazidas para as camadas inferiores localizadas nos clientes, a implementação dos mesmos algoritmos foi simplificada e começou a parecer muito mais agradável.
A abordagem é simples e permite simplificar o desenvolvimento adicional e o que é muito importante é aumentar a flexibilidade da arquitetura. Sim, isso exigirá extensa refatoração. No meu caso, foram necessárias duas semanas de desenvolvimento de um modo fanático. Mas depois disso, quase não codifiquei, porque tudo funcionou de forma estável.
E, graças à separação de responsabilidades (SPR) e aos logs, pude rapidamente suprimir erros de serviços de terceiros, implicando erros do meu lado. Antes, isso exigia análises que consumiam um tempo considerável.
Essa abordagem é boa para usar em determinadas camadas. Em camadas mais altas do aplicativo, um modelo anêmico pode ser mais conveniente, mas é melhor implementar um modelo anêmico com base em uma abordagem contratual.