como ddd e strategic design estão nos ajudando a modernizar um legado
TRANSCRIPT
Globalcode–Open4education
Como Domain Driven Design e Strategic Designestão nos ajudando a modernizar um legado
Luiz [email protected] / @gutomcosta
twitter.com/gutomcosta github.com/gutomcosta
www.sagadoprogramador.com.br medium.com/saga-do-programador
Contexto
Sistema para um empresa de medicina do trabalho realizar atendimentos de medicina ocupacional por
todo o Brasil e fornecer uma análise inteligente sobre o perfil dos colaboradores de uma empresa.
Mas como todo projeto, no início, tudo é muito
simples…
Era só uma "Fila"…
E hoje em dia até envia email
+ de 5 anos de projeto + 10 desenvolvedores passaram no time
Python e Django 1.4 < 50% test coverage
14 servidores = 1 para cada clínica aberta
Depois de algum tempo em produção….
•bugs e mais bugs •altera uma parte, quebra outra •bug em uma parte, sistema fora do ar •demora nas entregas •pressão do cliente para entregar mais
os problemas começaram…
Aplicação Web tradicional algo assim
Isso não é uma service layer, é algo parecido com um TransactionScript
models sendo um espelho do banco de
dados
WTF?
• lógica de domínio espalhada em Controllers, Models e Services
• models espelhando exatamente o modelo de dados
• foco no framework e não no domínio do problema
Como melhorar este projeto?
Domain Driven Design
Domain Model
http://martinfowler.com/eaaCatalog/domainModel.html
the blue and the red book
ENTITIES REPOSITORIES VALUE OBJECTS
FACTORIES SERVICES
Building Blocks
Strategic Design…modeling and design decisions that apply to large parts of the system. Such decisions affect the entire project and have to be decided at team level.
“Domain Driven Design, Chapter 14 - Maintaining Model Integrity", pág: 335Eric Evans - Blue Book
Strategic Design…modeling and design decisions that apply to large parts of the system. Such decisions affect the entire project and have to be decided at team level.
“Domain Driven Design, Chapter 14 - Maintaining Model Integrity", pág: 335 Eric Evans - Blue Book
BOUNDED CONTEXT CONTEXT MAP
ANTI-CURRUPTION LAYER SHARED KERNEL
OPEN HOST SERVICE PUBLISHED LANGUAGE
…
Existe vida além parte 1 do livro azul
Big Domain Model?
Not all of a large system will be well designed.
Eric Evans on Strategic Design presentationshttps://www.infoq.com/presentations/strategic-design-evans
Total unification of the domain model for a large system will not feasible or cost-effective
“Domain Driven Design, Chapter 14 - Maintaining Model Integrity", pág: 332 Eric Evans - Blue Book
Como dividir o domínio?
Bounded Context
Bounded Context…delimits the applicability of a particular model so that team members have a clear and shared understanding of what has to be consistent and how it relates to other contexts.
“Domain Driven Design, Chapter 14 - Maintaining Model Integrity", pág: 336 Eric Evans - Blue Book
Bounded Context…delimits the applicability of a particular model so that team members have a clear and shared understanding of what has to be consistent and how it relates to other contexts.
“Domain Driven Design, Chapter 14 - Maintaining Model Integrity", pág: 336 Eric Evans - Blue Book
Bounded Context…delimits the applicability of a particular model so that team members have a clear and shared understanding of what has to be consistent and how it relates to other contexts.
“Domain Driven Design, Chapter 14 - Maintaining Model Integrity", pág: 336 Eric Evans - Blue Book
Repensando as Fronteiras
Contexto A Contexto B Contexto C
Mesma entidade modelada em vários contextos
Paciente
Atendimento
+ qual nome, nascimento…? + qual dia do agendamento? + qual empresa pertence? + qual é a função que exerce?
Paciente
Gestor de Periódicos
+ qual é o proximo exame? + quantos dias faltam para vencer?
Paciente
Financeiro
+ qual custo dos exames feitos? + alguma condição de desconto?
É responsabilidade de cada contexto modelar os dados da me lh or m ane i ra , de a c o rd o c om a a s s u a s responsabilidades.
Como implementamos? E o que micro-serviços tem com isso?
Anatomia de um Bounded Context
Bounded Context
Domain LayerApplication Layer
use case
use case
use case
Repository
Entity
Value Object
Infrastructure Layer
Entity
DAO
Logger
Service
Module
Application Layer
Domain Layer
Atendimento.Fila
Infrastructure Layer
Implementação de um Caso de Uso
o fluxo de execução é simples e limpo
todas as dependências são
declaradas o construtor
Foco total no Domain ModelDomain Model != Model
Todas as regras de negócio são programadas aqui. Normalmente são
objetos python puros, sem relação com persistência ou infra-estrutura
Expostas através de
casos de uso
Nossa estratégia para dominar o legado
Strangler Applicationwww.martinfowler.com/bliki/StranglerApplication.html
…An alternative route is to gradually create a new system around the edges of the old, letting it grow slowly over several years until the old system is strangled.
www.martinfowler.com/bliki/StranglerApplication.html
www.martinfowler.com/bliki/StranglerApplication.html
Legado
Nova Funcionalidade
Nova Funcionalidade
Nova Funcionalidade
O design deve permitir atrasar decisões
Identificar e evidenciar as fronteiras através de Libs
Don’t distribute your objects.http://martinfowler.com/books/eaa.html
O isolamento do legado se dá através de indireções nos objetos da fronteira. Nesta visão de alto nível, é possível ver como uma funcionalidade é anexada ao código do Legado. A ideia básica é o novo módulo definir um conjunto de interfaces/conectores para troca de informações.
Em uma abordagem de lib, estes conectores se materializam em um
conjunto de interfaces que devem ser implementadas pela Lib.
fronteira do sistema
Inicialmente, os novos contextos são projetos novos, que devem funcionar
como Libs. Deve ser possível extrair a lib para rodar em um runtime diferente
sem muitas dificuldades.
O que fazer quando é preciso usar dados do
legado no módulo novo?
Dependency Inversion Principle
https://en.wikipedia.org/wiki/Dependency_inversion_principle
Um módulo ou contexto novo define um conjunto de interfaces que serão implementadas diretamente no legado.
interfaces definidas pelo módulo
o contexto “Atendimento” depende de dados que estão definidos no legado. Neste caso, o
módulo que necessita dos dados, define o contrato de comunicação e o legado
implementa este contrato, reutilizando objetos existentes ou escrevendo código novo. O importante é que a definição das
interfaces é feita de acordo com as intenções do módulo novo e não com os
detalhes do código legado
O que fazer se o legado precisar de dados do
módulo novo?
Publish/Subscribe ou Observers
https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern https://en.wikipedia.org/wiki/Observer_pattern
A solução mais comum para este caso é o uso de eventos. O módulo publica um conjunto de eventos e o legado assina estes eventos.
no lado do Legado, dentro da ACL, são definido casos de uso que serão estimulados pelos
handlers de tratamento dos eventos.
o caso de uso PatientCheckin, durante sua execução, publica o eventos “PatientCheckedIn”. Este evento
contem os dados necessários para comunicação com o legado,
normalmente serializado em um JSON ou usando um Hash.
Como juntar isso tudo e extrair um micro-serviço?
Este exemplo, mostra com a arquitetura permite separar os componentes em runtimes diferentes, inclusive com banco de dados próprio.
aqui, a lib foi incluída em uma aplicação web e isolada através de uma Anti-Corruption Layer (ACL). A
vantagem de se usar uma ACL é o isolamento do código já criado. As alterações necessárias na lib são muito
pequenas e a própria ACL pode tratar os problemas de comunicação com o legado, logar, lançar exceções, etc.
do lado do legado, a própria api já funciona como uma ACL.
Normalmente esta api vai ser implementada com Http puro, usando formatos simples como
JSON para troca de dados
Chamadas diretas na api do legado ou através de uma arquitetura event-driven.
Broker de mensagens, por exemplo: JMS, ActiveMQ , RabbitMQ , etc
conjunto de EventHandlers interessados nas mensagens
Resumo da nossa estratégia
1 - Reúna o time com algum especialista do domínio e
faça um desenho inicial dos Bounded Contexts
2 - Evidencie as fronteiras inicialmente através
módulos no código fonte
3 - Extraia os módulos que compõem um Bounded Context para uma lib
4 - Se necessário, exponha a mesma lib como micro-
serviço
Obrigado!