Você está na página 1de 35

Contents

Introdução ....................................................................................1
O que é design orientado por domínio .........................................3
Construindo conhecimento de domínio .......................................8
A Língua Onipresente ................................................................13
A necessidade de uma linguagem comum .................................13
Criando a linguagem onipresente ...............................................16
Design orientado para modelos .................................................23
Os blocos de construção de um design orientado por modelos .28
Arquitetura em camadas ............................................................29
Entidades ....................................................................................31
Objetos de valor .........................................................................34
Introdução

oftware é um instrumento criado para nos ajudar a lidar com as

S complexidades de nossa vida moderna. Software é apenas o


meio para um fim, e geralmente esse fim é algo muito prático e
real. Por exemplo, usamos software para controle de tráfego
aéreo, e isso está diretamente relacionado com o mundo ao nosso
redor. Queremos voar de um lugar para outro, e fazemos isso
usando máquinas sofisticadas, então criamos software para
coordenar o voo de milhares de aviões que por acaso estão no ar
a qualquer momento.

O software tem que ser prático e útil; caso contrário, não


investiríamos tanto tempo e recursos em sua criação. Isso o torna
extremamente ligado a um certo aspecto de nossas vidas. Um
pacote útil de software não pode ser dissociado dessa esfera da
realidade, o domínio que ele deve nos ajudar a gerenciar. Pelo
contrário, o software está profundamente envolvido com ele.

O design de software é uma arte, e como qualquer arte, não pode


ser ensinada e aprendida como uma ciência precisa, por meio de
teoremas e fórmulas. Podemos descobrir princípios e técnicas
úteis para serem aplicados durante todo o processo de criação de
software, mas provavelmente nunca seremos capazes de fornecer
um caminho exato a seguir do mundo real necessário para o
módulo de código destinado a atender a essa necessidade. Como
uma imagem ou um edifício, um produto de software incluirá o
toque pessoal daqueles que o projetaram e desenvolveram, algo
do carisma e talento (ou a falta dele) daqueles que contribuíram
para sua criação e crescimento.

Existem diferentes maneiras de abordar o design do software.


Nos últimos 20 anos, a indústria de software tem conhecido e
usado vários métodos para criar seus produtos, cada um com
suas vantagens e deficiências. O objetivo deste livro é focar em
um design

1
2│ DESIGN ORIENTADO POR DOMÍNIO RAPIDAMENTE

método que emergiu e evoluiu ao longo das últimas


duas décadas, mas cristalizou mais claramente
durante os últimos anos: design orientado por
domínio. Eric Evans fez uma grande contribuição
para este assunto escrevendo em um livro grande
parte do conhecimento acumulado sobre design
orientado por domínio. Para uma apresentação
mais detalhada deste tópico, recomendamos a
leitura de seu livro "Domain-Driven Design: Tackling
Complexity in the Heart of Software", publicado por
Addison-Wesley, ISBN: 0-321-12521-5.
Muitos insights valiosos também podem ser
aprendidos seguindo o grupo de discussão Domain
Driven Design em:
http://groups.yahoo.com/group/domaindrivendesign
Este livro é apenas uma introdução ao tema,
destinado a rapidamente dar-lhe uma compreensão
fundamental, mas não detalhada do Design
Orientado por Domínio. Só queremos aguçar seu
apetite por um bom design de software com os
princípios e diretrizes usados no mundo do design
orientado por domínio.
1
O que é design orientado por
domínio

oftware o desenvolvimento é mais frequentemente aplicado à

S automatização de processos que existem no mundo real, ou ao


fornecimento de soluções para problemas reais de negócios; os
processos de negócios sendo automatizados ou problemas do
mundo real que o software é o domínio do software. Devemos
entender desde o início que o software é originário e
profundamente relacionado a este domínio.
O software é feito de código. Podemos ser tentados a passar
muito tempo com o código, e ver o software como simplesmente
objetos e métodos.
Considere a fabricação de carros como uma metáfora. Os
trabalhadores envolvidos na fabricação de automóveis podem se
especializar na produção de peças do carro, mas ao fazê-lo
muitas vezes têm uma visão limitada de todo o processo de
fabricação de automóveis. Eles começam a ver o carro como
uma enorme coleção de peças que precisam se encaixar, mas um
carro é muito mais do que isso. Um bom carro começa com uma
visão. Começa com especificações cuidadosamente escritas. E
continua com o design. Muito e muito design. Meses, talvez
anos de tempo gasto em design, mudando e refinando-o até
chegar à perfeição, até que reflita a visão original. O projeto de
processamento não está todo no papel. Muito disso inclui fazer
modelos do carro, e testá-los sob certas condições para ver se
funcionam. O design é modificado com base nos resultados dos
testes. O carro é enviado para produção eventualmente, e as
peças são criadas e montadas juntas.
3
O desenvolvimento de software é semelhante. Não podemos
simplesmente sentar e digitar código. Podemos fazer isso, e
funciona bem para casos triviais. Mas não podemos criar um
software complexo como esse.
Para criar um bom software, você tem que saber do que se trata
esse software. Você não pode criar um sistema de software
bancário a menos que você tenha uma boa compreensão do que é
bancário, é preciso entender o domínio do banco.
É possível criar softwares bancários complexos sem um bom
conhecimento de domínio? De maneira nenhuma. nunca. Quem
sabe o banco? O arquiteto de Software? Não. Ele só usa o banco
para manter seu dinheiro seguro e disponível quando precisa
deles. O analista de software? Nem por isso. Ele sabe analisar
um determinado tópico, quando recebe todos os ingredientes
necessários. O desenvolvedor? Esqueça. Quem, então? Os
banqueiros, é claro. O sistema bancário é muito bem
compreendido pelas pessoas lá dentro, por seus especialistas.
Eles sabem todos os detalhes, todas as capturas, todos os
problemas possíveis, todas as regras. É aqui que devemos
sempre começar: o domínio.
Quando começarmos um projeto de software, devemos focar no
domínio em que ele está operando. O objetivo do software é
aprimorar um domínio específico. Para ser capaz de fazer isso, o
software tem que se encaixar harmoniosamente com o domínio
para o que foi criado. Caso contrário, introduzirá tensão no
domínio, provocando mau funcionamento, dano e até causar
caos.
Como podemos fazer com que o software se encaixe
harmoniosamente com o domínio? A melhor maneira de fazer
isso é fazer do software um reflexo do domínio. O software
precisa incorporar os conceitos e elementos centrais do domínio,
e perceber precisamente as relações entre eles. O software tem
que modelar o domínio.
Alguém sem conhecimento bancário deve ser capaz de aprender
muito apenas lendo o código em um modelo de domínio. Isso é
essencial. O software que não tem suas raízes plantadas
profundamente no domínio não reagirá bem à mudança ao longo
do tempo.
Então começamos com o domínio. E depois o quê? Um domínio
é algo deste mundo. Ele não pode simplesmente ser tomada e
derramado sobre o teclado no computador para se tornar código.
Precisamos criar uma abstração do domínio. Aprendemos muito
sobre um domínio enquanto conversamos com os especialistas
em domínio. Mas esse conhecimento bruto não será facilmente
transformado em construções de software, a menos que
construamos uma abstração dele, um projeto em nossas mentes.
No começo, o projeto está sempre incompleto. Mas com o
tempo, enquanto trabalhamos nisso, nós o tornamos melhor, e
isso se torna cada vez mais claro para nós. O que é essa
abstração? É um modelo, um modelo do domínio. De acordo
com Eric Evans, um modelo de domínio não é um diagrama
específico; é a ideia de que o diagrama é destinado a transmitir.
Não é apenas o conhecimento na cabeça de um especialista em
domínio; é uma abstração rigorosamente organizada e seletiva
desse conhecimento. Um diagrama pode representar e comunicar
um modelo, assim como um código cuidadosamente escrito,
assim como uma frase em inglês.
O modelo é a nossa representação interna do domínio alvo, e é
muito necessário durante todo o projeto e o processo de
desenvolvimento. Durante o processo de design lembramos e
fazemos muitas referências ao modelo. O mundo ao nosso redor
é demais para nossas cabeças lidarem. Mesmo um domínio
específico pode ser mais do que uma mente humana pode lidar
ao mesmo tempo. Precisamos organizar informações,
sistematizá-la, dividi-la em pedaços menores, agrupar essas
peças em módulos lógicos, e tomar uma de cada vez e lidar com
ela. Precisamos até deixar algumas partes do domínio de fora.
Um domínio contém muitas informações para incluir tudo no
modelo. E muito disso nem é necessário ser considerado. Este é
um desafio por si só. O que guardar e o que jogar fora? Faz parte
do projeto, do processo de criação de software. O software
bancário certamente acompanhará o endereço do cliente, mas
não deve se preocupar com a cor dos olhos do cliente. Esse é um
caso óbvio, mas outros exemplos podem não ser tão óbvios.
Um modelo é uma parte essencial do design de software.
Precisamos dele para poder lidar com a complexidade. Todo o
nosso processo de pensamento sobre o domínio é sintetizado
neste modelo. Isso é bom, mas tem que sair da nossa cabeça.
Não é muito útil se ele permanecer lá, não é? Precisamos
comunicar esse modelo com especialistas em domínio, com
outros designers e com desenvolvedores. O modelo é a essência
do software, mas precisamos criar maneiras de expressá-lo, de
comunicá-lo com os outros. Não estamos sozinhos nesse
processo, por isso precisamos compartilhar conhecimento e
informação, e precisamos fazê-lo bem, precisamente,
completamente e sem ambiguidade. Há diferentes maneiras de
fazer isso. Uma delas é gráfica: diagramas, casos de uso,
desenhos, imagens, etc. Outra é escrever. Nós escrevemos nossa
visão sobre o domínio. Outra é a linguagem. Podemos e
devemos criar um idioma para comunicar questões específicas
sobre o domínio. Vamos detalhar tudo isso mais tarde, mas o
ponto principal é que precisamos comunicar o modelo.
Quando temos um modelo expresso, podemos começar a fazer
design de código. Isso é diferente do design de software. Design
de software é como criar a arquitetura de uma casa, é sobre o
quadro geral. Por outro lado, o design de código está trabalhando
nos detalhes, como a localização de uma pintura em uma
determinada parede. O design de código também é muito
importante, mas não tão fundamental quanto o design de
software. Um erro de design de código geralmente é mais
facilmente corrigido, enquanto erros de design de software são
muito mais caros de reparar. Uma coisa é mover uma pintura
mais para a esquerda, e uma coisa completamente diferente para
derrubar um lado da casa, a fim de fazê-lo de forma diferente.
No entanto, o produto final não será bom sem um bom design de
código. Aqui os padrões de design de código são úteis, e eles
devem ser aplicados quando necessário. Boas técnicas de
codificação ajudam a criar código limpo e mantenedor. Existem
diferentes abordagens para o design de software. Um deles é o
método de design de cachoeira. Este método envolve uma série
de estágios. Os especialistas em negócios apresentaram um
conjunto de requisitos que são comunicados aos analistas de
negócios. Os analistas criam um modelo baseado nesses
requisitos e passam os resultados para os desenvolvedores, que
começam a codificar com base no que receberam. É um fluxo de
conhecimento de uma maneira só. Embora esta tenha sido uma
abordagem tradicional no design de software, e tem sido usada
com um certo nível de sucesso ao longo dos anos, ela tem suas
falhas e limites. O principal problema é que não há feedback dos
analistas para os especialistas em negócios ou dos
desenvolvedores aos analistas.
Outra abordagem são as metodologias ágeis, como a
Programação Extrema (XP). Essas metodologias são um
movimento coletivo contra a abordagem da cachoeira,
decorrente das dificuldades de tentar chegar a todos os requisitos
antecipadamente, especialmente à luz da mudança de requisitos.
É realmente difícil criar um modelo completo que cubra todos os
aspectos de um domínio antecipadamente. É preciso muito
pensamento, e muitas vezes você simplesmente não pode ver
todos os problemas envolvidos desde o início, nem você pode
prever alguns dos efeitos colaterais negativos ou erros do seu
design. Outro problema que a Ágil tenta resolver é a chamada
"paralisia da análise", com os membros da equipe com tanto
medo de tomar qualquer decisão de design que eles não fazem
nenhum progresso. Embora os defensores do Ágil reconheçam a
importância da decisão de design, eles resistem ao design inicial.
Em vez disso, eles empregam uma grande flexibilidade de
implementação, e através do desenvolvimento iterativo com
participação contínua de partes interessadas nos negócios e
muito refator, a equipe de desenvolvimento começa a aprender
mais sobre o domínio do cliente e pode produzir melhor software
que atenda às necessidades dos clientes.
Os métodos ágeis têm seus próprios problemas e limitações; eles
defendem a simplicidade, mas cada um tem sua própria visão do
que isso significa. Além disso, o refatoring contínuo feito por
desenvolvedores sem princípios sólidos de design produzirá
códigos difíceis de entender ou mudar. E embora a abordagem
da cachoeira possa levar à super engenharia, o medo da
engenharia excessiva pode levar a outro medo: o medo de fazer
um projeto profundo e completamente pensado.
Este livro apresenta os princípios do design orientado ao
domínio, que quando aplicado pode aumentar muito a
capacidade de qualquer processo de desenvolvimento de
modelar e implementar os problemas complexos no domínio de
forma sustentável. O Domain Driven Design combina a prática
de design e desenvolvimento e mostra como o design e o
desenvolvimento podem trabalhar juntos para criar uma solução
melhor. Um bom design acelerará o desenvolvimento, enquanto
o feedback proveniente do processo de desenvolvimento
melhorará o design.
Construindo conhecimento de domínio

Vamos considerar o exemplo de um projeto de sistema de


controle de voo de avião e como o conhecimento do domínio
pode ser construído.
Milhares de aviões estão no ar em um dado momento em todo o
planeta. Eles estão voando seus próprios caminhos para seus
destinos, e é muito importante garantir que eles não colidam no
ar. Não tentaremos elaborar todo o sistema de controle de
tráfego, mas em um subconjunto menor que é um sistema de
monitoramento de voo. O projeto proposto é um sistema de
monitoramento que rastreia cada voo sobre uma determinada
área, determina se o voo segue sua suposta rota ou não, e se há a
possibilidade de uma colisão.
Onde começamos de uma perspectiva de desenvolvimento de
software? Na seção anterior dissemos que deveríamos começar
entendendo o domínio, que neste caso é o monitoramento do
tráfego aéreo. Os controladores de tráfego aéreo são os
especialistas deste domínio. Mas os controladores não são
designers de sistemas ou especialistas em software. Você não
pode esperar que eles lhe entreguem uma descrição completa do
domínio do problema deles.
Os controladores de tráfego aéreo têm vasto conhecimento sobre
seu domínio, mas para poder construir um modelo você precisa
extrair informações essenciais e generalizá-la. Quando você
começar a falar com eles, você vai ouvir muito sobre aeronaves
decolando, e aterrissagem, aeronaves no ar e o perigo de colisão,
aviões esperando antes de ser permitido pousar etc. Para
encontrar ordem nesta quantidade aparentemente caótica de
informação, precisamos começar em algum lugar.
O controlador e você concordam que cada aeronave tem uma
partida e um aeródromo de destino. Então temos uma aeronave,
uma partida e um destino, como mostrado na figura abaixo.
Departure Aircraft Destination

Ok, o avião decola de algum lugar e aterrissa em outro. Mas o que


acontece no ar? Que caminho de voo ele vai? Na verdade, estamos mais
interessados no que acontece enquanto ele está no ar. O controlador diz
que cada avião é designado um plano de voo que deve descrever toda a
viagem aérea. Ao ouvir sobre um plano de voo, você pode pensar em sua
mente que este é sobre o caminho seguido pelo avião enquanto está no
ar. Depois de mais discussões, você ouve uma palavra interessante: rota.
Ele instantaneamente chama sua atenção, e por uma boa razão. A rota
contém um importante conceito de viagem de avião. Isso é o que os
aviões fazem enquanto voam, eles seguem uma rota. É óbvio que os
pontos de partida e destino da aeronave também são os pontos de partida
e término da rota. Assim, em vez de associar a aeronave com os pontos
de partida e destino, parece mais natural associá-la a uma rota, que por
sua vez está associada à partida e destino correspondentes.

Departure

Aircraft Route

Destination
Conversando com o controlador sobre as rotas que os aviões seguem, você
descobre que na verdade a rota é composta por pequenos segmentos, que
juntos constituem algum tipo de linha torta da partida para o destino. A
linha deve passar por pontos fixos pré-determinados. Assim, uma rota pode
ser considerada como uma série de correções consecutivas. Neste ponto
você não vê mais a partida e o destino como os pontos terminais da rota,
mas apenas mais duas dessas correções. Isso é provavelmente muito
diferente de como o controlador vê-los, mas é uma abstração necessária que
ajuda mais tarde. As mudanças resultantes com base nessas descobertas são:

Aircraft Route * Fix

3DPoint

O diagrama mostra outro elemento, o fato de que cada correção é um ponto


no espaço seguido pela rota, e é expresso como um ponto tridimensional.
Mas quando você falar com o controlador, você vai descobrir que ele não vê
dessa forma. Na verdade, ele vê a rota como a projeção na Terra do voo do
avião. As correções são apenas pontos na superfície da Terra
exclusivamente determinados por sua latitude e longitude. Então o diagrama
correto é:

Aircraft Route * Fix

2DPoint

O que está realmente acontecendo aqui? Você e os especialistas em


domínios estão falando, você está trocando conhecimento. Você começa
a fazer perguntas, e eles respondem. Enquanto fazem isso, eles cavam
conceitos essenciais fora do domínio de tráfego aéreo. Esses conceitos
podem sair não polidos e desorganizados, mas, no entanto, são essenciais
para a compreensão do domínio. Você precisa aprender o máximo
possível sobre o domínio dos especialistas. E colocando as perguntas
certas e processando as informações da maneira correta, você e os
especialistas começarão a esboçar uma visão do domínio, um modelo de
domínio. Esta visão não é completa nem correta, mas é o começo que
você precisa. Tente descobrir os conceitos essenciais do domínio.
Esta é uma parte importante do projeto. Geralmente há longas discussões
entre arquitetos de software ou desenvolvedores e especialistas em
domínios. Os especialistas em software querem extrair conhecimento
dos especialistas em domínio, e eles também têm que transformá-lo em
uma forma útil. Em algum momento, eles podem querer criar um
protótipo inicial para ver como ele funciona até agora. Ao fazer isso, eles
podem encontrar alguns problemas com seu modelo, ou sua abordagem,
e podem querer mudar o modelo. A comunicação não é apenas uma
maneira, desde os especialistas em domínio até o arquiteto de Software e
mais longe para os desenvolvedores. Há também feedback, o que ajuda a
criar um modelo melhor, e uma compreensão mais clara e correta do
domínio. Especialistas em domínios conhecem bem sua área de atuação,
mas organizam e usam seus conhecimentos de forma específica, o que
nem sempre é o melhor a ser implementado em um sistema de software.
A mente analítica do designer de software ajuda a desenterrar alguns dos
conceitos-chave do domínio durante discussões com especialistas em
domínio, e ajudar a construir uma estrutura para discussões futuras como
veremos no próximo capítulo. Nós, especialistas em software (arquitetos
de software e desenvolvedores) e especialistas em domínio, estamos
criando o modelo do domínio juntos, e o modelo é o lugar onde essas
duas áreas de especialização se encontram. Isso pode parecer um
processo muito demorado, e é, mas é assim que deve ser, porque no final
o objetivo do software é resolver problemas de negócios em um domínio
da vida real, por isso tem que se misturar perfeitamente com o domínio.
2
A Língua Onipresente

A Necessidade De Uma Linguagem


Comum

O
capítulo anterior cedeu que é absolutamente necessário
desenvolver um modelo do domínio, fazendo com que os
especialistas em software trabalhem com os especialistas em
domínio; no entanto, essa abordagem geralmente tem algumas
dificuldades iniciais devido a uma barreira de comunicação
fundamental. Os desenvolvedores têm suas mentes cheias de
classes, métodos, algoritmos, padrões, e tendem a sempre fazer
uma combinação entre um conceito da vida real e um artefato de
programação. Eles querem ver quais classes de objeto criar e
quais relações modelar entre eles. Eles pensam em termos de
herança, polimorfismo, OOP, etc. E eles falam assim o tempo
todo. E é normal que eles façam isso. Desenvolvedores serão
desenvolvedores. Mas os especialistas em domínios geralmente
não sabem nada sobre nada disso. Eles não têm ideia sobre
bibliotecas de software, frameworks, persistência, em muitos
casos nem mesmo bancos de dados. Eles sabem sobre sua área
específica de especialização.
No exemplo de monitoramento do tráfego aéreo, os especialistas
em domínios sabem sobre aviões, sobre rotas, altitudes,
longitudes e latitudes, eles sabem sobre desvios da rota normal,
sobre trajetórias de aviões. E eles falam sobre essas coisas em
seu próprio jargão, que às vezes não é tão simples de seguir por
um estranho.

13
Para superar essa diferença no estilo de comunicação, quando
construímos o modelo, devemos comunicar para trocar ideias sobre o
modelo, sobre os elementos envolvidos no modelo, como os
conectamos, o que é relevante e o que não é. A comunicação nesse
nível é primordial para o sucesso do projeto. Se um diz alguma coisa,
e o outro não entende ou, pior ainda, entende outra coisa, quais são
as chances de o projeto ter sucesso?
Um projeto enfrenta sérios problemas quando os membros da equipe
não compartilham uma linguagem comum para discutir o domínio.
Especialistas em domínios usam seu jargão, enquanto os membros da
equipe técnica têm sua própria linguagem sintonizada para discutir o
domínio em termos de design.
A terminologia das discussões cotidianas é desconectada da
terminologia incorporada no código (em última análise, o produto
mais importante de um projeto de software). E mesmo a mesma
pessoa usa linguagem diferente na fala e na escrita, de modo que as
expressões mais incisivas do domínio muitas vezes emergem de
forma transitória que nunca é capturada no código ou mesmo por
escrito.
Durante essas sessões de comunicação, a tradução é frequentemente
usada para permitir que os outros entendam do que se trata alguns
conceitos. Os desenvolvedores podem tentar explicar alguns padrões
de design usando a linguagem de um leigo, e às vezes sem sucesso.
Os especialistas em domínios se esforçarão para trazer para casa
algumas de suas ideias, provavelmente criando um novo jargão.
Durante esse processo a comunicação sofre, e esse tipo de tradução
não ajuda no processo de construção do conhecimento.
Tendemos a usar nossos próprios dialetos durante essas sessões de
design, mas nenhum desses dialetos pode ser uma linguagem comum
porque nenhum atende às necessidades de todos.
Definitivamente precisamos falar a mesma língua quando nos
encontramos para falar sobre o modelo e defini-lo. Que língua vai
ser? A linguagem dos desenvolvedores? A linguagem dos
especialistas em domínios? Algo no meio?
Um princípio central do design orientado por domínio é usar uma
linguagem baseada no modelo. Como o modelo é o terreno comum, o
lugar onde o software encontra o domínio, é apropriado usá-lo como
base de construção para esta linguagem.
Use o modelo como espinha dorsal de uma linguagem. Solicite que a
equipe use o idioma de forma consistente em todas as comunicações e
no código. Ao compartilhar conhecimento e martelar o modelo, a equipe
usa fala, escrita e diagramas. Certifique-se de que essa linguagem
apareça consistentemente em todas as formas de comunicação utilizadas
pela equipe; por essa razão, a língua é chamada de Língua Onipresente.
A Linguagem Onipresente conecta todas as partes do design, e cria a
premissa para que a equipe de design funcione bem. Leva semanas e até
meses para que projetos de projetos em grande escala tomem forma. Os
membros da equipe descobrem que alguns dos conceitos iniciais foram
incorretos ou usados inapropriadamente, ou descobrem novos elementos
do design que precisam ser considerados e se encaixam no design geral.
Tudo isso não é possível sem uma linguagem comum.
Línguas não aparecem da noite para o dia. É preciso muito trabalho e
muito foco para garantir que os elementos-chave da linguagem sejam
trazidos à tona. Precisamos encontrar esses conceitos-chave que definem
o domínio e o design, e encontrar palavras correspondentes para eles, e
começar a usá-los. Alguns deles são facilmente vistos, mas alguns são
mais difíceis.
Resolver dificuldades experimentando expressões alternativas, que
refletem modelos alternativos. Em seguida, refatorar o código,
renomeando classes, métodos e módulos para se adequar ao novo
modelo. Resolver a confusão sobre os termos da conversa, da maneira
como chegamos a concordar com o significado das palavras comuns.
Construir uma linguagem como essa tem um resultado claro: o modelo e
a linguagem estão fortemente interconectadas entre si. Uma mudança na
linguagem deve se tornar uma mudança no modelo.

Os especialistas em domínio devem se opor a termos ou estruturas que


sejam desajeitados ou inadequados para transmitir a compreensão do
domínio. Se os especialistas em domínio não conseguem entender algo no
modelo ou no idioma, então é mais provável que haja algo errado com ele.
Por outro lado, os desenvolvedores devem ficar atentos à ambiguidade ou
inconsistência que tendem a aparecer no design.
Criando a Linguagem Onipresente

Como podemos começar a construir uma língua? Aqui está um diálogo


hipotético entre um desenvolvedor de software e um especialista em
domínio no projeto de monitoramento de tráfego aéreo. Cuidado com as
palavras que aparecem em negrito.
Desenvolvedor: Queremos monitorar o tráfego aéreo. Por onde
começamos?
Especialista: Vamos começar com o básico. Todo esse tráfego é
feito de aviões. Cada avião decola de um local de partida, e pousa em
um local de destino.
Desenvolvedor: Isso é fácil. Quando voa, o avião pode escolher
qualquer caminho aéreo que os pilotos gostem? Cabe a eles decidir
para que lado devem ir, desde que cheguem ao destino?
Especialista: Oh, não. Os pilotos recebem uma rota que devem
seguir. E eles devem ficar nessa rota o mais perto possível.
Desenvolvedor: Estou pensando nesta rota como um caminho 3D no
ar. Se usarmos um sistema cartesiano de coordenadas, então a rota é
simplesmente uma série de pontos 3D.
Expert: Acho que não. Não vemos rota dessa maneira. A rota é, na
verdade, a projeção no solo do caminho aéreo esperado do avião. A
rota passa por uma série de pontos no chão determinados por sua
latitude e longitude.
Desenvolvedor: OK, então vamos chamar cada um desses pontos de
uma correção, porque é um ponto fixo da superfície da Terra. E
usaremos então uma série de pontos 2D para descrever o caminho. E,
a propósito, a partida e o destino são apenas correções. Não
devemos considerá-los como conceitos separados. A rota chega ao
destino à medida que atinge qualquer outra correção. O avião deve
seguir a rota, mas isso significa que ele pode voar tão alto ou tão
baixo quanto quiser?
Especialista: Não. A altitude que um avião deve ter em um
determinado momento também está estabelecida no plano de voo.
Desenvolvedor: Plano de voo? O que é aquilo?
Expert: Antes de deixar o aeroporto, os pilotos recebem um plano de
voo detalhado que inclui todo tipo de informações sobre o voo: a rota, a
altitude de cruzeiro, a velocidade do cruzeiro, o tipo de avião, até
mesmo informações sobre os membros da tripulação.

Aircraft Flight Plan Route

Fix

2DPoint

Developer: Hmm, O plano de voo parece muito importante para mim.


Vamos incluí-lo no modelo.
Desenvolvedor: Isso é melhor. Agora que estou olhando para ele,
percebo uma coisa. Quando estamos monitorando o tráfego aéreo,
não estamos realmente interessados nos próprios aviões, se eles são
brancos ou azuis, ou se eles são Boeing ou Airbus. Estamos
interessados no voo deles. Isso é o que estamos realmente rastreando
e medindo. Acho que devemos mudar um pouco o modelo para
sermos mais precisos.
Observe como esta equipe, falando sobre o domínio de
monitoramento do tráfego aéreo e em torno de seu modelo
incipiente, está lentamente criando uma linguagem composta pelas
palavras em negrito. Observe também como essa linguagem muda o
modelo!
No entanto, na realidade, esse diálogo é muito mais verboso, e
muitas vezes as pessoas falam sobre as coisas indiretamente, ou
entram em muitos detalhes, ou escolhem os conceitos errados; isso
pode tornar a linguagem muito difícil. Para começar a lidar com isso,
todos os membros da equipe devem estar cientes da necessidade de
criar uma linguagem comum e devem ser lembrados para manter o
foco no essencial e usar a linguagem sempre que necessário.
Devemos usar nosso próprio jargão durante essas sessões o mínimo
possível, e devemos usar a Linguagem Onipresente porque isso nos
ajuda a nos comunicar de forma clara e precisa.

Flight Flight Plan Route

Fix

2DPoint

Também é altamente recomendado para os desenvolvedores


implementar os principais conceitos do modelo no código. Uma aula
poderia ser escrita para Route e outra para Fix. A classe Fix pode herdar
de uma classe 2DPoint, ou poderia conter um 2DPoint como seu
principal atributo. Isso depende de outros fatores que serão discutidos
posteriormente. Ao criar classes para os conceitos de modelo
correspondentes, estamos mapeando entre o modelo e o código, e entre a
linguagem e o código. Isso é muito útil, pois torna o código mais legível,
e o torna reproduzir o modelo. Ter o código expresso o modelo
compensa mais tarde no projeto, quando o modelo cresce grande, e
quando as alterações no código podem ter consequências indesejáveis se
o código não foi devidamente projetado.
Vimos como a linguagem é compartilhada por toda a equipe, e como ela
ajuda a construir conhecimento e criar o modelo. O que devemos usar
para a linguagem? Só discurso? Usamos diagramas. O que mais poderia
ser? escrita?
Alguns podem dizer que UML é bom o suficiente para construir um
modelo sobre. E, de fato, é uma ótima ferramenta para escrever
conceitos-chave como classes, e expressar relações entre eles. Você pode
desenhar quatro ou cinco classes em um bloco de desenho, escrever os
seus nomes, e mostrar as relações entre eles. É muito fácil para todos
seguir o que você está pensando, e uma expressão gráfica de uma ideia é
fácil de entender. Todos compartilham instantaneamente a mesma visão
sobre um determinado tópico, e torna-se mais simples comunicar com
base nisso. Quando novas ideias surgem, e o diagrama é modificado para
refletir a mudança conceitual.
Diagramas UML são muito úteis quando o número de elementos
envolvidos é pequeno. Mas UML pode crescer como cogumelos
depois de uma boa chuva de verão. O que você faz quando tem
centenas de aulas enchendo uma folha de papel enquanto o
Mississipi? É difícil ler até mesmo pelos especialistas em software,
sem mencionar especialistas em domínio. Eles não vão entender
muito disso quando ele fica grande, e ele faz isso mesmo para
projetos de médio porte.
Além disso, a UML é boa em expressar classes, seus atributos e
relações entre elas. Mas o comportamento das classes e as restrições
não são tão facilmente expressos. Para que UML recorre ao texto
colocado como notas no diagrama. Assim, a UML não pode
transmitir dois aspectos importantes de um modelo: o significado dos
conceitos que representa e o que os objetos devem fazer. Mas tudo
bem, já que podemos adicionar outras ferramentas de comunicação
para fazê-lo.
Podemos usar documentos. Uma maneira aconselhável de comunicar
o modelo é fazer alguns pequenos diagramas cada um contendo um
subconjunto do modelo. Esses diagramas conteriam várias classes, e
a relação entre eles. Isso já inclui boa parte dos conceitos envolvidos.
Então podemos adicionar texto ao diagrama. O texto explicará o
comportamento e as restrições que o diagrama não pode. Cada uma
dessas subseção tenta explicar um aspecto importante do domínio,
ele aponta um "holofote" para iluminar uma parte do domínio.
Esses documentos podem até ser desenhados à mão, pois isso
transmite a sensação de que são temporários, e podem ser alterados
em um futuro próximo, o que é verdade, porque o modelo é alterado
muitas vezes no início antes de atingir um status mais estável.
Pode ser tentador tentar criar um grande diagrama sobre todo o modelo. No
entanto, na maioria das vezes tais diagramas são quase impossíveis de
montar. Além disso, mesmo que você consiga fazer esse diagrama
unificado, ele será tão desordenado que não transmitirá melhor o
entendimento do que fez a coleta de pequenos diagramas.
Desconfie de documentos longos. Leva muito tempo para escrevê-los, e eles
podem se tornar obsoletos antes de terminarem. Os documentos devem estar
em sincronia com o modelo. Documentos antigos, usar a linguagem errada,
e não refletir o modelo não são muito úteis. Tente evitá-los quando possível.
Também é possível comunicar usando código. Essa abordagem é
amplamente defendida pela comunidade XP. Código bem escrito pode ser
muito comunicativo. Embora o comportamento expresso por um método
seja claro, o nome do método é tão claro quanto seu corpo? Afirmações de
um teste falam por si, mas que tal os nomes variáveis e a estrutura geral do
código? Eles estão contando toda a história, alto e claro? O código, que
funcionalmente faz a coisa certa, não necessariamente expressa a coisa
certa. Escrever um modelo em código é muito difícil.
Há outras maneiras de se comunicar durante o projeto. Não é o propósito
deste livro apresentar todos eles. Uma coisa é, no entanto, clara: a equipe de
design, composta por arquitetos de software, desenvolvedores e
especialistas em domínio, precisa de uma linguagem que unifique suas
ações, e os ajude a criar um modelo e expressar esse modelo com código.
DESIGN ORIENTADO
3
POR MODELO

O
s capítulos anteriores ressaltaram a importância de uma
abordagem para o desenvolvimento de software centrada no
domínio empresarial. Dissemos que é fundamentalmente
importante criar um modelo que esteja profundamente enraizado
no domínio, e que reflita os conceitos essenciais do domínio com
grande precisão. A Linguagem Onipresente deve ser totalmente
exercida durante todo o processo de modelagem, a fim de
facilitar a comunicação entre os especialistas em software e os
especialistas em domínio, e descobrir conceitos-chave de
domínio que devem ser usados no modelo. O objetivo deste
processo de modelagem é criar um bom modelo. O próximo
passo é implementar o modelo em código. Esta é uma fase
igualmente importante do processo de desenvolvimento de
software. Tendo criado um ótimo modelo, mas não transferindo-
o adequadamente para o código acabará em software de
qualidade questionável.

Acontece que os analistas de software trabalham com


especialistas em domínio de negócios por meses, descobrem os
elementos fundamentais do domínio, enfatizam as relações entre
eles e criam um modelo correto, que captura com precisão o
domínio. Em seguida, o modelo é passado para os
desenvolvedores de software. Os desenvolvedores podem olhar
para o modelo e descobrir que alguns dos conceitos ou
relacionamentos encontrados nele não podem ser devidamente
expressos em código. Então eles usam o modelo como fonte
original de inspiração, mas criam seu próprio design que pega
emprestado algumas das ideias do modelo, e adiciona algumas
das suas próprias. O processo de desenvolvimento continua, e
mais classes são adicionadas ao código, expandindo a divisão
entre o modelo original e o
implementação final. O bom resultado não está garantido. Bons
desenvolvedores podem montar um produto que funcione, mas
será que ele suportará os testes do tempo? Será facilmente
estendido? Será facilmente mantido?
Qualquer domínio pode ser expresso com muitos modelos, e
qualquer modelo pode ser expresso de várias maneiras em
código. Para cada problema em particular pode haver mais de
uma solução. Qual deles escolhemos? Ter um modelo analítico
correto não significa que o modelo possa ser expresso
diretamente em código. Ou talvez sua implementação quebre
alguns princípios de design de software, o que não é
aconselhável. É importante escolher um modelo que possa ser
facilmente e precisamente colocado em código. A questão básica
aqui é: como abordamos a transição de modelo para código?
Uma das técnicas recomendadas de design é o chamado modelo
de análise, que é visto como separado do design de código e
geralmente é feito por pessoas diferentes. O modelo de análise é
resultado da análise do domínio empresarial, resultando em um
modelo que não tem consideração pelo software utilizado para
implementação. Tal modelo é usado para entender o domínio.
Um certo nível de conhecimento é construído, e o modelo
resultante pode ser analíticamente correto. O software não é
levado em conta nesta fase porque é considerado um fator
confuso. Este modelo chega aos desenvolvedores que devem
fazer o design. Uma vez que o modelo não foi construído com
princípios de design em mente, provavelmente não servirá bem a
esse propósito. Os desenvolvedores terão que adaptá-lo ou criar
um design separado. E não há mais um mapeamento entre o
modelo e o código. O resultado é que os modelos de análise são
logo abandonados após o início da codificação.
Uma das principais questões dessa abordagem é que os analistas
não podem prever alguns dos defeitos em seu modelo, e todos os
meandros do domínio. Os analistas podem ter entrado em muitos
detalhes com alguns dos componentes do modelo, e não
detalharam outros suficientes. Detalhes muito importantes são
descobertos durante o processo de projeto e implementação. Um
modelo que é verdadeiro para o domínio pode vir a ter sérios
problemas com persistência de objeto, ou comportamento de
desempenho inaceitável.
Os desenvolvedores serão forçados a tomar algumas decisões
por conta própria, e farão mudanças de design a fim de resolver
um problema real que não foi considerado quando o modelo foi
criado. Eles criam um design que foge do modelo, tornando-o
menos relevante.
Se os analistas trabalharem de forma independente, eles
eventualmente criarão um modelo. Quando esse modelo é
passado para os designers, parte do conhecimento dos analistas
sobre o domínio e o modelo é perdido. Embora o modelo possa
ser expresso em diagramas e escritas, as chances são de que os
designers não entendam todo o significado do modelo, ou as
relações entre alguns objetos, ou seu comportamento. Há
detalhes em um modelo que não são facilmente expressos em um
diagrama, e podem não ser totalmente apresentados mesmo por
escrito. Os desenvolvedores terão dificuldade em descobri-los.
Em alguns casos, eles farão algumas suposições sobre o
comportamento pretendido, e é possível que eles façam os
errados, resultando em funcionamento incorreto do programa.
Analistas têm suas próprias reuniões fechadas onde muitas
coisas são discutidas sobre o domínio, e há muito
compartilhamento de conhecimento. Eles criam um modelo que
deveria conter todas essas informações de forma condensada, e
os desenvolvedores têm que assimilar tudo isso lendo os
documentos dados a eles. Seria muito mais produtivo se os
desenvolvedores pudessem participar das reuniões de analistas e,
assim, alcançar uma visão clara e completa do domínio e do
modelo antes de começarem a projetar o código.
Uma abordagem melhor é relacionar de perto modelagem e
design de domínio. O modelo deve ser construído de olho nas
considerações de software e design. Os desenvolvedores devem
ser incluídos no processo de modelagem. A ideia principal é
escolher um modelo que possa ser devidamente expresso em
software, para que o processo de design seja simples e baseado
no modelo. Relacionar firmemente o código a um modelo
subjacente dá significado ao código e torna o modelo relevante.
Envolver os desenvolvedores fornece feedback. Ele garante que
o modelo pode ser implementado em software.
Se algo estiver errado, ele é identificado em um estágio inicial, e
o problema pode ser facilmente corrigido.
Aqueles que escrevem o código devem conhecer o modelo muito
bem, e devem se sentir responsáveis por sua integridade. Eles
devem perceber que uma mudança no código implica uma
mudança no modelo; caso contrário, eles vão refator o código ao
ponto de não expressar mais o modelo original. Se o analista for
separado do processo de implementação, ele logo perderá sua
preocupação com as limitações introduzidas pelo
desenvolvimento. O resultado é um modelo que não é prático.
Qualquer pessoa técnica que contribua para o modelo deve
passar algum tempo tocando o código, seja qual for o papel
principal que ele ou ela desempenha no projeto. Qualquer pessoa
responsável por mudar o código deve aprender a expressar um
modelo através do código. Todo desenvolvedor deve estar
envolvido em algum nível de discussão sobre o modelo e ter
contato com especialistas em domínios. Aqueles que contribuem
de diferentes formas devem envolver conscientemente aqueles
que tocam o código em uma troca dinâmica de ideias de modelo
através da Linguagem Onipresente.
Se o design, ou alguma parte central dele, não mapear para o
modelo de domínio, esse modelo é de pouco valor, e a correção
do software é suspeita. Ao mesmo tempo, mapeamentos
complexos entre modelos e funções de design são difíceis de
entender e, na prática, impossíveis de manter à medida que o
design muda. Uma divisão mortal se abre entre análise e design
para que a percepção adquirida em cada uma dessas atividades
não se alimente do outro.
Projete uma parte do sistema de software para refletir o modelo
de domínio de forma muito literal, de modo que o mapeamento
seja óbvio. Revisite o modelo e modifique-o para ser
implementado mais naturalmente em software, mesmo que você
busque fazê-lo refletir uma visão mais profunda sobre o
domínio. Exija um único modelo que sirva bem aos dois
propósitos, além de apoiar uma linguagem onipresente fluente.
Extrair do modelo a terminologia utilizada no desenho e a
atribuição básica de responsabilidades. O código se torna uma
expressão do modelo, de modo que uma mudança no código
pode ser um mudar para o modelo. Seu efeito deve se espalhar
pelo resto das atividades do projeto em conformidade.
Para vincular firmemente a implementação a um modelo geralmente
requer ferramentas de desenvolvimento de software e linguagens que
suportam um paradigma de modelagem, como a programação orientada
a objetos.
A programação orientada a objetos é adequada para a implementação do
modelo porque ambos são baseados no mesmo paradigma. A
programação orientada a objetos fornece classes de objetos e associações
de classes, instâncias de objetos e mensagens entre eles. As linguagens
OOP possibilitam criar mapeamentos diretos entre objetos modelo com
suas relações e suas contrapartes de programação.
As linguagens processuais oferecem suporte limitado para design
orientado por modelos. Tais linguagens não oferecem os construtos
necessários para implementar componentes-chave de um modelo.
Alguns dizem que o OOP pode ser feito com uma linguagem processual
como C, e, de fato, algumas das funcionalidades podem ser reproduzidas
dessa forma. Objetos podem ser simulados como estruturas de dados.
Tais estruturas não contêm o comportamento do objeto, e isso deve ser
adicionado separadamente como funções. O significado desses dados
existe apenas na mente do desenvolvedor, porque o código em si não é
explícito. Um programa escrito em uma linguagem processual é
geralmente percebido como um conjunto de funções, um chamando o
outro, e trabalhando em conjunto para alcançar um determinado
resultado. Tal programa não pode facilmente encapsular conexões
conceituais, dificultando o mapeamento entre domínio e código.
Alguns domínios específicos, como a matemática, podem ser facilmente
modelados e implementados usando programação processual, porque
muitas teorias matemáticas são simplesmente abordadas usando
chamadas de função e estruturas de dados porque é principalmente sobre
computação. Domínios mais complexos não são apenas um conjunto de
conceitos abstratos envolvendo computação, e não podem ser reduzidos
a um conjunto de algoritmos, de modo que as linguagens processuais
estão aquém da tarefa de expressar os respectivos modelos. Por essa
razão, a programação processual não é recomendada para o design
orientado por modelos.
Os Blocos De Construção De Um Design Orientado
Por Modelos
As seguintes seções deste capítulo apresentarão os padrões mais
importantes a serem usados no design orientado por modelos. O
objetivo desses padrões é apresentar alguns dos elementos-chave
da modelagem de objetos e do design de software do ponto de
vista do design orientado por domínio. O diagrama a seguir é um
mapa dos padrões apresentados e das relações entre eles.

REPOSITORIES
access with

SERVICES
access with

maintain integrity with


ENTITIES
express model with
act as root of
express model with
AGGREGATES

express model with


MODEL-DRIVEN VALUE OBJECTS
DESIGN encapsulate with

encapsulate with encapsulate with


isolate domain with

X
mutually exclusive
choices LAYERED encapsulate with
ARCHITECTURE FACTORIES

SMART UI
Arquitetura em Camadas

User Infrastructure
Interface Application Domain

Quando criamos um aplicativo de software, grande parte do


aplicativo não está diretamente relacionado ao domínio, mas faz
parte da infraestrutura ou serve ao próprio software. É possível e
ok para a parte de domínio de um aplicativo ser bastante
pequena em comparação com o resto, uma vez que um aplicativo
típico contém um monte de código relacionado ao acesso ao
banco de dados, acesso a arquivos ou rede, interfaces de usuário,
etc.

Em um programa orientado a objetos, interface do usuário,


banco de dados e outro código de suporte geralmente são
escritos diretamente nos objetos de negócios. A lógica de
negócios adicional está incorporada no comportamento dos
widgets de interface do usuário e scripts de banco de dados. Isso
às vezes acontece porque é a maneira mais fácil de fazer as
coisas funcionarem rapidamente.

No entanto, quando o código relacionado ao domínio é


misturado com as outras camadas, torna-se extremamente difícil
de ver e pensar. Mudanças superficiais na interface do usuário
podem realmente mudar a lógica dos negócios. Para alterar uma
regra de negócios pode exigir um rastreamento meticuloso do
código de interface do usuário, código de banco de dados ou
outros elementos do programa. Implementar objetos coerentes e
orientados por modelos torna-se impraticável. Testes
automatizados são estranhos. Com todas as tecnologias e lógica
envolvidas em cada atividade, um programa deve ser mantido
muito simples ou torna-se impossível de entender.
Portanto, partição de um programa complexo em LAYERS.
Desenvolva um design dentro de cada CAMADA que seja coeso
e que dependa apenas das camadas abaixo. Siga padrões
arquitetônicos padrão para fornecer acoplamento solto às
camadas acima. Concentre todo o código relacionado ao modelo
de domínio em uma camada e isole-o da interface do usuário,
aplicativo e código de infraestrutura. Os objetos de domínio,
livres da responsabilidade de se exibir, armazenar-se, gerenciar
tarefas de aplicativos e assim por diante, podem ser focados em
expressar o modelo de domínio. Isso permite que um modelo
evolua para ser rico o suficiente e claro o suficiente para capturar
conhecimentos essenciais do negócio e colocá-lo em prática.
Uma solução arquitetônica comum para projetos orientados por
domínio contém quatro camadas conceituais:
User Interface Responsável por apresentar informações ao usuário e
(Presentation interpretar comandos do usuário.
Layer)

Application Esta é uma camada fina que coordena a atividade de


Layer aplicação. Não contém lógica de negócios. Ele não
detém o estado dos objetos comerciais, mas pode
manter o estado de um progresso de tarefa de
aplicação.

Domain Layer Esta camada contém informações sobre o domínio. Este


é o coração do software de negócios. O estado dos
objetos comerciais é mantido aqui. A persistência dos
objetos comerciais e possivelmente seu estado é
delegado à camada de
infraestrutura.

Infrastructure Esta camada funciona como uma biblioteca de suporte


Layer para todas as outras camadas. Ele fornece
comunicação entre camadas, implementa persistência
para objetos de negócios, contém bibliotecas de
suporte para a camada de interface do usuário, etc..
É importante dividir uma aplicação em camadas separadas e estabelecer
regras de interações entre as camadas. Se o código não for claramente
separado em camadas, logo se tornará tão emaranhado que se tornará muito
difícil gerenciar mudanças. Uma simples alteração em uma seção do código
pode ter resultados inesperados e indesejáveis em outras seções. A camada
de domínio
deve ser focado em questões de domínio principal. Não deveria estar
envolvido em atividades de infraestrutura. A interface do usuário não deve
estar bem conectada à lógica do negócio, nem às tarefas que normalmente
pertencem à camada de infraestrutura. Uma camada de aplicação é
necessária em muitos casos. Tem que haver um gestor sobre a lógica
empresarial que supervisiona e coordena a atividade geral do aplicativo.

Por exemplo, uma interação típica do aplicativo, domínio e infraestrutura


pode ser assim. O usuário quer reservar uma rota de voo, e pede um serviço
de aplicativo na camada de aplicativo para fazê-lo. O nível de aplicação
busca os objetos de domínio relevantes da infraestrutura e invoca métodos
relevantes sobre eles, por exemplo, para verificar as margens de segurança
para outros voos já reservados. Uma vez que os objetos de domínio tenham
feito todas as verificações e atualizado seu status para "decidido", o serviço
de aplicativo persiste os objetos para a infraestrutura.
Entidades

Há uma categoria de objetos que parecem ter uma identidade,


que permanece a mesma em todos os estados do software. Para
esses objetos não são os atributos que importam, mas um fio de
continuidade e identidade, que abrange a vida útil de um sistema
e pode se estender além dele. Tais objetos são chamados de
Entidades
As linguagens OOP mantêm as instâncias do objeto na memória
e associam uma referência ou um endereço de memória para
cada objeto. Esta referência é única para cada objeto em um
determinado momento, mas não há garantia de que ele
permanecerá assim por um período indeterminado. Na verdade,
o contrário é verdade. Os objetos são constantemente movidos
para fora e de volta à memória, eles são serializados e enviados
pela rede e recriados na outra extremidade, ou são destruídos.
Essa referência, que se coloca como identidade para o ambiente
de execução do programa, não é a identidade de que estamos
falando. Se houver uma classe que detém informações
meteorológicas, como temperatura, é bem possível ter duas
instâncias distintas da respectiva classe, ambas contendo o
mesmo valor. Os objetos são perfeitamente iguais e
intercambiáveis uns com os outros, mas eles têm referências
diferentes. Não são entidades.
Se fôssemos implementar o conceito de pessoa usando um
programa de software, provavelmente criaríamos uma classe
Pessoa com uma série de atributos: nome, data de nascimento,
local de nascimento etc. Algum desses atributos é a identidade
da pessoa? O nome não pode ser a identidade porque pode haver
mais pessoas com o mesmo nome. Não poderíamos distinguir
entre pessoas com o mesmo nome, se levarmos em conta apenas
o nome deles. Também não podemos usar a data de nascimento,
porque há muitas pessoas nascidas no mesmo dia. Ele se aplica
ao local de nascimento. Um objeto deve ser distinguido de
outros objetos, mesmo que eles possam ter os mesmos atributos.
Identidade equivocada pode levar à corrupção de dados.
Considere um sistema de contabilidade bancária. Cada conta tem
seu próprio número. Uma conta pode ser precisamente
identificada pelo seu número. Esse número permanece inalterado
ao longo da vida útil do sistema, e garante a continuidade. O
número da conta pode existir como um objeto na memória, ou
pode ser destruído na memória e enviado para o banco de dados.
Ele também pode ser arquivado quando a conta é fechada, mas
ainda existe em algum lugar, desde que haja algum interesse em
mantê-la por perto. Não importa que representação seja
necessária, o número permanece o mesmo.
Portanto, implementar entidades em software significa criar
identidade. Para uma pessoa pode ser uma combinação de
atributos: nome, data de nascimento, local de nascimento, nome
dos pais, endereço atual. O número da Segurança Social também
é usado nos EUA para criar identidade. Para uma conta bancária,
o número da conta parece ser suficiente para sua identidade.
Normalmente, a identidade é um atributo do objeto, uma
combinação de atributos, um atributo especialmente criado para
preservar e expressar identidade, ou mesmo um comportamento.
É importante que dois objetos com identidades diferentes sejam
facilmente distinguidos pelo sistema, e dois objetos com a
mesma identidade sejam considerados os mesmos pelo sistema.
Se essa condição não for cumprida, então todo o sistema pode
ficar corrompido.
Existem diferentes maneiras de criar uma identidade única para
cada objeto. O ID poderia ser gerado automaticamente por um
módulo, e usados internamente no software sem torná-lo visível
para o usuário. Pode ser uma chave primária em uma tabela de
banco de dados, que é assegurada ser única no banco de dados.
Sempre que o objeto é recuperado do banco de dados, seu ID é
recuperado e recriado na memória. O ID pode ser criado pelo
usuário como acontece com os códigos associados aos
aeroportos. Cada aeroporto possui uma identificação de string
única que é reconhecida internacionalmente e usada pelas
agências de viagens de todo o mundo para identificar aeroportos
em seus horários de viagem. Outra solução é usar os atributos do
objeto para criar o ID, e quando isso não for suficiente, outro
atributo pode ser adicionado para ajudar a identificar o
respectivo objeto.
Quando um objeto é distinguido por sua identidade, em vez de
seus atributos, faça isso principal à sua definição no modelo.
Mantenha a definição de classe simples e focada na continuidade
e identidade do ciclo de vida. Defina um meio de distinguir cada
objeto, independentemente de sua forma ou história. Esteja
atento aos requisitos que exigem objetos correspondentes por
atributos. Defina uma operação que seja garantida para produzir
um resultado único para cada objeto, possivelmente anexando
um símbolo que seja garantido único. Esse meio de identificação
pode vir de fora, ou pode ser um identificador arbitrário criado
por e para o sistema, mas deve corresponder às distinções de
identidade no modelo. O modelo deve definir o que significa ser
a mesma coisa.
As entidades são objetos importantes de um modelo de domínio,
e devem ser considerados desde o início do processo de
modelagem. Também é importante determinar se um objeto
precisa ser uma entidade ou não, o que é discutido no próximo
padrão.
Objetos de Valor

Discutimos entidades e a importância de reconhecer as entidades


precocemente durante a fase de modelagem. As entidades são
objetos necessários em um modelo de domínio. Devemos fazer
todas as entidades de objetos? Cada objeto deve ter uma
identidade?
Podemos ser tentados a fazer todas as entidades de objetos. As
entidades podem ser rastreadas. Mas rastrear e criar identidade
vem com um custo. Precisamos ter certeza de que cada instância
tem sua identidade única, e rastrear identidade não é muito
simples. É preciso muito cuidado para decidir o que faz uma
identidade, porque uma decisão errada levaria a objetos com a
mesma identidade, algo que não é desejado. Há também
implicações de desempenho na fabricação de todas as entidades
de objetos. Tem que haver uma instância para cada objeto. Se o
Cliente é um objeto de entidade, então uma instância deste
objeto, representando um cliente bancário específico, não poderá
ser reutilizada para operações de conta correspondentes a outros
clientes. O resultado é que tal instância tem que ser criada para
cada cliente. Isso pode resultar em degradação do desempenho
do sistema ao lidar com milhares de instâncias.
Vamos considerar uma aplicação de desenho. O usuário é
apresentado uma tela e ele pode desenhar quaisquer pontos e
linhas de qualquer espessura, estilo e cor. É útil criar uma classe
de objetos chamado Point, e o programa poderia criar uma
instância desta classe para cada ponto na tela. Tal ponto conteria
dois atributos associados às coordenadas de tela ou tela. É
necessário considerar cada ponto como tendo uma identidade?
Tem continuidade? Parece que a única coisa que importa para tal
objeto são suas coordenadas.
Há casos em que precisamos conter alguns atributos de um
elemento de domínio. Não estamos interessados em qual objeto
é, mas em que atributos ele tem. Um objeto que é usado para
descrever certos aspectos de um domínio, e que não tem
identidade, é chamado Objeto de Valor.
É necessário distinguir entre Objetos de Entidade e Objetos de
Valor. Não é útil fazer todas as entidades de objetos por uma
questão de uniformidade. Na verdade, recomenda-se selecionar
como entidades apenas os objetos que estejam em conformidade
com a definição da entidade. E faça o resto dos objetos Valorize
Objetos. (Apresentaremos outro tipo de objeto na próxima seção,
mas vamos assumir que temos apenas objetos de entidade e
objetos de valor por enquanto.) Isso simplificará o projeto, e
haverá algumas outras consequências positivas.
Sem identidade, Objetos de Valor podem ser facilmente criados
e descartados. Ninguém se importa em criar uma identidade, e o
coletor de lixo cuida do objeto quando não é mais referenciado
por qualquer outro objeto. Isso simplifica muito o design.
É altamente recomendável que objetos de valor sejam imutáveis.
Eles são criados com um construtor, e nunca modificados
durante sua vida. Quando você quer um valor diferente para o
objeto, você simplesmente cria outro. Isso tem consequências
importantes para o projeto. Sendo imutável e sem identidade,
Objetos de Valor podem ser compartilhados. Isso pode ser
imperativo para alguns projetos. Objetos imutáveis são
fragmentáveis com implicações importantes de desempenho.
Eles também manifestam integridade, ou seja, integridade dos
dados. Imagine o que significaria compartilhar um objeto que
não é imutável. Um sistema de reserva de viagens aéreas poderia
criar objetos para cada voo. Um dos atributos pode ser o código
de voo. Um cliente reserva um voo para um determinado
destino. Outro cliente quer reservar o mesmo voo. O sistema
opta por reutilizar o objeto que contém o código de voo, porque
é quase o mesmo voo. Enquanto isso, o cliente muda de ideia, e
escolhe pegar um voo diferente. O sistema muda o código de
voo porque isso não é imutável. O resultado é que o código de
voo do primeiro cliente também muda.
Uma regra de ouro é: se objetos de valor são compartilháveis,
eles devem ser imutáveis. Valor Os objetos devem ser mantidos
finos e simples. Quando um Objeto de Valor é necessário por
outra parte, ele pode ser simplesmente passado por valor, ou uma
cópia dele pode ser criada e dada.
Fazer uma cópia de um objeto de valor é simples, e geralmente
sem quaisquer consequências. Se não houver identidade, você
pode fazer quantas cópias quiser, e destruir todas elas quando
necessário.

Customer Customer

customerID customerID
name name
street address
city
state

Address

street
city
state

Objetos de valor podem conter outros Objetos de Valor, e eles


podem até conter referências a Entidades. Embora os Objetos de
Valor sejam usados simplesmente para conter atributos de um
objeto de domínio, isso não significa que ele deve conter uma
longa lista com todos os atributos. Atributos podem ser
agrupados em diferentes objetos. Atributos escolhidos para
compor um Objeto de Valor devem formar um todo conceitual.
Um cliente está associado a um nome, uma rua, uma cidade e um
estado. É melhor conter as informações de endereço em um
objeto separado, e o objeto do cliente conterá uma referência a
tal objeto. Rua, cidade, estado deve ter um objeto próprio, o
Endereço, porque eles pertencem conceitualmente juntos, em
vez de serem atributos separados do cliente, como mostrado no
diagrama abaixo.

Você também pode gostar