Como DDD e Strategic Design estão nos ajudando a modernizar um Legado

Preview:

Citation preview

Globalcode–Open4education

Como Domain Driven Design e Strategic Designestão nos ajudando a modernizar um legado

Luiz Costagutomcosta@gmail.com / @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!