Clean Code na Prática
Conceitos de Clean Code Apresentados
em Exemplos de Código
Douglas Siviotti
Novembro de 2019 V1.1
Sobre esta Apresentação
1. Conteúdo: Clean Code (Código Limpo)
2. Área/Foco: Engenharia de Software, Desenvolvimento Ágil
3. Público alvo: Desenvolvedores
4. Conteúdo relacionado: OO, Programação Funcional, DDD, SOLID, GRASP
Organização (155 slides)
Parte 1 – Um Pouco de Filosofia
Parte 2 – Um Pouco de Teoria (Conceitos Relacionados)
Parte 3 – Clean Code na Prática em Exemplos de Código
Parte 4 – Laboratório de Refatoração
Código-fonte usado nesta apresentação:
https://github.com/refactown/cleancode
Cognição
Micro Design
Integração
Macro Design
Sintomas
comuns
equipe entregando cada vez menos
pontos a cada sprint
estimativas frustradas: o esforço
é sempre maior que o previsto
erros
frequentes em
produção
correção de um bug causa
outros problemas não previstos
incidentes resolvidos e o mesmo
erro voltando a aparecer
muito “To Do” espalhado pelo
código e/ou código morto
dificuldade de evolução ou
incorporação de novas
funcionalidades
Código Ruim
manutenção difícil
+ retrabalho e - produtividade
Código Ruim
manutenção difícil
+ retrabalho e - produtividade
Procrastinação
aversão a mudanças
criação de dívida técnica
Procrastinação
aversão a mudanças
criação de dívida técnica
Falta de Testes
design pobre e inflexível
falta de segurança p/ o dev
Falta de Testes
design pobre e inflexível
falta de segurança p/ o dev
Pressão
bugs, incidentes, pouco valor,
baixa evolução: insatisfação
Pressão
bugs, incidentes, pouco valor,
baixa evolução: insatisfação
ciclo
vicioso da
dívida
técnica
Código Limpo
fácil de entender e manter
expressa o negócio
Código Limpo
fácil de entender e manter
expressa o negócio
Refatoração
adaptação ao novo problema
tratamento de dívida técnica
Refatoração
adaptação ao novo problema
tratamento de dívida técnica
Teste de Unidade
guiando o design (feedback)
com boa cobertura
Teste de Unidade
guiando o design (feedback)
com boa cobertura
Entregas c/ Valor
evolução sustentável
cliente satisfeito
Entregas c/ Valor
evolução sustentável
cliente satisfeito
ciclo da
eficácia no
software
sob medida
Clean Code
Fazer código para ser lido e
entendido por outras pessoas
Clean Code
Fazer código para ser lido e
entendido por outras pessoas
Refatoração
adaptação ao novo problema
tratamento de dívida técnica
Teste de Unidade
guiando o design (feedback)
com boa cobertura
Entregas c/ Valor
evolução sustentável
cliente satisfeito
ciclo da
eficácia no
software
sob medida
Um PoucoUm Pouco
de Filosofiade Filosofia
Parte 1
Pequenas CoisasPequenas Coisas
ImportamImportam
“Deus está nos detalhes” “Menos é mais”
(Ludwig Mies van der Rohe)
Quem não faz bem as pequenas
coisas, não faz bem coisa alguma
código é detalhamentocódigo é detalhamento
dos requisitos e devedos requisitos e deve
expressar o negócioexpressar o negócio
código deve ser feito para ser lido por outra pessoacódigo deve ser feito para ser lido por outra pessoa
comunique,
não codifique!
código ruim geracódigo ruim gera
baixa produtividadebaixa produtividade
que gera código piorque gera código pior
seja um
glóbulo branco
prevenir é melhor
que remediar
por que
CódigoCódigo
Limpo?Limpo?
“elegante e eficiente
faz apenas uma coisa”
Bjarne Stroustrup
“simples e direto - legível”
Grady Booch
“inteligível ao seres humanos”
Dave Thomas
“escrito por alguém
que se importava”
Michael Feathers
“sem duplicação, expressivo,
pequenas abstrações”
Ron Jeffries
“a linguagem parece que foi
feita para o problema”
Ward Cunningham
O que é
A T I T U D EA T I T U D E
teoria da janela
quebrada
regra do
escoteiro
quando
programador
profissional
quem
quando
técnica, treino e tempotécnica, treino e tempo
livros de arte não
fazem um artista
trabalho artesanal
mas profissional
como
Um Pouco de Teoria*Um Pouco de Teoria*
*Oriunda de muita prática*Oriunda de muita prática
Parte 2
Título do Slide (Arial 18)
16/155
2.1 DDD: Negócio ao Código
2.2 Linguagem Onipresente
2.3 Princípio SRP
2.4 Princípio DRY
2.5 Indireção / Delegação
2.6 Lei de Demeter
2.7 Acoplamento e Coesão
2.8 Imutabilidade
2.9 OO + Funções Puras
2.10 Testes Tempestivos
2.11 Refatoração Tempestiva
2.12 Regras da Simplicidade
Conceitos
relacionados
O requisito está no código, mas muito código não vem do requisito
O domínio de um problema organiza os conceitos sobre os quais é baseada a solução de software
Foco no Negócio
Parte do código deve expressar o negócio
Isolamento do Domínio
O código de domínio é idiossincrático e particular
Infraestrutura à Parte
Tecnologias vêm e vão, o negócio permanece
Do Negócio ao Código Via DDD 2.1 Negócio ao Código
Domain
DDD e os Nomes das Coisas 2.2 Linguagem Onipresente
Ubiquos
Language
Service
Entity
Value
Object
Agregate
Factory
Model-driven
Design
Bounded
Context
RepositoryDomain
Events
Layered
Architecture
Core
Domain
Context
Map
Continuos
Integration
Linguagem Onipresente (Ubíqua)
- Termos e conceitos usados pelos desenvolvedores e pelos
especialistas no negócio
- Presente na fala de todos e no código de domínio
Contexto Delimitado
- Partes bem delimitadas de um domínio
- Candidatos a microsserviços
Tijolos de Construção
- Entidades, Objetos de Valor, Agregados
- Eventos de Domínio
- Serviços, Fábricas, Repositórios
Princípio da Responsabilidade Única (SRP) 2.3 Princípio SRP
“Cada módulo de um software deve ter um e apenas um motivo para mudar”
1
O que seria
apenas “uma”
responsabilidade?
Menos é Mais 2.4 Princípio DRY
DRY = Don’t Repeat Yourself
“Não Se Repita” (código, requisito, teste etc)
Toda parte do conhecimento deve ter
uma representação única e livre
de ambiguidades em todo o sistema
Problemas
- Mais trabalho: alterar mais vezes
- Mais risco: encontrar todos os lugares
- Mais teste: testar várias vezes a mesma coisa
- Mais esforço de comunicação
Indireção ou Delegação 2.5 Indireção / Delegação
SRP
Fazer apenas
uma coisa em
um certo lugar
SRP
Fazer apenas
uma coisa em
um certo lugar
DRY
Fazer apenas
em um lugar
uma certa coisa
DRY
Fazer apenas
em um lugar
uma certa coisa
Coisa única
em um
único lugar
“A”
Coisa única
em um
único lugar
“A”
Outra
coisa única
em um
único lugar
“B”
Outra
coisa única
em um
único lugar
“B”
Indireção ou Delegação
1. Não pode conter
2. Não pode copiar
3. Precisa referenciar
Indireção Indireção
Calculo de Frete Busca de EndereçoEfetuar Pedido
Lei de Demeter – Princípio do Menor Conhecimento 2.6 Lei de Demeter
Um módulo não deve enxergar o interior
dos objetos que ele manipula
Um método “m” de uma classe “C” só deve chamar:
- Objetos do tipo “C”
- Parâmetros passados para o método “m” (e.g. “x: P”)
- Um objeto criado pelo próprio método “m”
- Variáveis de instância da classe “C” (e.g. “a: A”)
Train Wreck (Acidente de Trem): x.getY().getZ()
“Você não manda as pernas do cachorro andarem e sim o cachorro”
Classe “C”
Atributo a: A
Método “m” (x: X)
Classe X
Atributo y : Y
Classe Y
Atributo z : Z
Baixo Acoplamento e Alta Coesão 2.7 Acoplamento e Coesão
Alto Acoplamento
Baixa Coesão
(entre classes)
Poucas classes e grandes
Mais dependência por classe
Maior conhecimento
Baixo Acoplamento
Alta Coesão
(entre classes)
Muitas classes e pequenas
Menos dependência por classe
Menor conhecimento
Coesão de uma Classe:
- Poucas variáveis de instância
- Cada método manipula uma ou mais
Uma classe pouco coesa sugere
que uma nova classe deve “nascer”
Quanto Mais Imutável Melhor 2.8 Imutabilidade
Evite Surpresas
Imutabilidade é uma defesa contra
efeitos colaterais
Vantagens
- Mais seguro e confiável
- Mais legível:
minimiza testes e garantias
diminui o código por tabela
- Paralelismo e escalabilidade
private final int idade;
Quanto Mais Puro Melhor 2.9 OO + Funções Puras
Função Pura
1. Para um certo Input sempre retorna o mesmo Output
2. Não causa nenhum efeito colateral
3. Não depende de nenhum dado externo (autocontida)
Vantagens
- Mais simples e menores
- Mais fácil de entender e testar
Quando usar em código OO?
Sempre que possível
Em muitas situações não é possível: BD, integração, estados etc
Possível em regras de negócio, métodos utilitários, internos etc
Function
Input
Output
IMUTABILIDADE
- efeitos colaterais
TDD e Testes Tempestivos 2.10 Testes Tempestivos
TDD – Test Driven Development
(Desenvolvimento Guiado por Testes)
- Escreve um teste que falha antes do código produtivo
- Faz o teste passar ao construir o código produtivo
- Refatora o código até o teste falhar (ou não)
Testes Tempestivos (TDD inclusive)
(teste que ajuda na construção, logo cedo)
1. Atividade de engenharia (código e design)
2. Feedback rápido sobre o código testado (erra cedo)
3. Gera código limpo através da “dificuldade” de testar
4. Antecipa o custo gasto em correções e debug
5. Ainda serve como teste de regressão
Refatora
Falha
Passa
Ciclos
Curtos
Refatoração Tempestiva 2.11 Refatoração
“Refatoração (refactoring) é a disciplina técnica
para reestruturar um determinado código,
alterando sua estrutura interna sem mudar seu
comportamento externo”
Martin Fowler
Problema Inicial Solução Inicial
Problema Refinado
Refatoração
Mudança
Solução Final
Validar Solução
Refinamento
Ciclo de
Sprint
Ajuste da solução em função de:
- uma nova visão sobre o problema
- preparar para uma evolução ou mudança
Pequenas mudanças que fazem
diferença no longo prazo
Quatro Regras da Simplicidade (Martin Fowler : Kent Beck) 2.12 Simplicidade
Testes Tempestivos
Refatoração Tempestiva
https://martinfowler.com/bliki/BeckDesignRules.html
Conceitos Relacionados Conceitos
DDDDDD Linguagem
Onipresente
Linguagem
Onipresente
Indireção
Abstração, especialização
Indireção
Abstração, especialização
Lei de Demeter
Mínimo conhecimento
Lei de Demeter
Mínimo conhecimento
Princípio SRP
Responsabilidade Única
Princípio SRP
Responsabilidade Única
Princípio DRY
Não Se Repita
Princípio DRY
Não Se Repita
Acoplamento
e Coesão
Acoplamento
e Coesão
Funções Puras
OO ou funcional
Funções Puras
OO ou funcionalInfraInfra
DomínioDomínio
AppApp
Refatoração
Tempestiva
Refatoração
Tempestiva
Teste
Tempestivo
Teste
Tempestivo
4 Regras da
Simplicidade
4 Regras da
Simplicidade
Imutabilidade
- efeitos colaterais
Imutabilidade
- efeitos colaterais
Clean
Code
Clean
Code
PráticaPrática
Parte 3
Título do Slide (Arial 18)
31/155
3.1 Código Limpo
3.2 Nomes Significativos
3.3 Comentários (capítulo 4)
3.4 Formatação (capítulo 5)
3.5 Funções (capítulo 3)
3.6 Objetos e E. de Dados
3.7 Tratamento de Erro
3.8 Fronteiras (Limites)
3.9 Testes de Unidade
3.10 Classes
3.11 Sistemas Complexos
3.12 Simplicidade
Prática
- filosofia
- bad smell
- boa prática
- exemplo
- exercício
Cognição
Entendimento e leitura
Integração
Contratos e expectativas
Macro Design
Escala e expansão
Micro Design
Estado e comportamento
Código LimpoCódigo Limpo
(Visão Geral)(Visão Geral)
Parte 3.1Parte 3.1
Filosofia sobre Código Limpo (Visão Geral) 3.1 Código Limpo
- O código não fica nem se mantém limpo sozinho
- Todos na equipe devem praticar e cobrar
- Manter o código limpo é uma atividade diária
- Funciona como na “Teoria das janelas quebradas”
- Atitude é mais relevante do que “patrocínio”
- Sempre dá pra começar (regra do escoteiro)
- Ler e entender consome mais tempo que escrever
- Precisa de tempo, técnica e treino pra fazer bem
Código Ruim 3.1 Código Limpo
Problemas
- Nomes ruins
- Função grande e complexa (SRP)
- Comentários questionáveis
- Formatação inexistente
Dificuldades
- Legibilidade: confuso
- Testabilidade: alta complexidade
Código Menos Ruim 3.1 Código Limpo
Problemas
- Nomes ruins
- Função grande e complexa (SRP)
- Comentários questionáveis
- Formatação inexistente
Dificuldades
- Legibilidade: confuso
- Testabilidade: alta complexidade
Código Melhorado (Refatorado) 3.1 Código Limpo
O que pode melhorar?
Possíveis Melhorias 3.1 Código Limpo
Lançar Exceção
Constantes
Enum “Premio”
Classe Separada
NomesNomes
SignificativosSignificativos
Parte 3.2Parte 3.2
Filosofia sobre Nomes 3.2 Nomes Significativos
- Nomes são muito importantes (especialmente em OO)
- Use nomes que revelam seu propósito
- Evite informações erradas (itemList: Map)
- Faça distinções significativas (evite a1, a2 a3...)
- Nomes pronunciáveis e passíveis de busca
- Evite codificações (e.g. notação húngara e similares)
- classes = substantivos, métodos = verbos
- Selecione uma palavra por conceito (get, set, find)
- Nomes do problema (Pedido, Item) e da solução (DAO)
- Adicione ou evite contexto quando necessário
Bad Smell 3.2 Nomes Significativos
Problemas
- Nomes genéricos “i”, “x”, “d” etc
- Nomes impronunciáveis
- Número Mágico (perdido no código)
- Notação Húngara
- Interface prefixada
- Nome com contexto redundante
Boa Prática 3.2 Nomes Significativos
Alternativas
- Nomes que revelam propósito
- Nomes pronunciáveis
- Constantes para número mágico
(passíveis de busca)
- Sem Notação Húngara
- Interface = Conceito
- Nomes com o mínimo necessário
Problema x Solução 3.2 Nomes Significativos
Problema
Solução
Modelo de Exemplo 3.2 Nomes Significativos
Nomes a partir do domínio do problema (Pedido, Item etc)
Nomes a partir do domínio da solução (Controller, Delegate, DAO)
Classes = Substantivos, Métodos = Verbos
Nomes pronunciáveis e passíveis de busca
Parte 3.3Parte 3.3
ComentáriosComentários
Filosofia sobre Comentários 3.3 Comentários
“Qualquer um pode escrever código que o computador
entenda. Bons programadores escrevem códigos que os
humanos entendem.”
Martin Fowler
- Comentários são a última opção do programador
- O programador deve expressar-se no código
- Comunique, não codifique (outros devem ler)
- Comentário pode estar compensando código ruim
- Alguns comentários são bons ou necessários
Explique-se no Código 3.3 Comentários
Alguns comentários existem para explicar código ruim.
Um comentário deve explicar “o porquê” e nunca “o que”
Não comente, refatore!
Comentários Bons: Legais e APIs Públicas 3.3 Comentários
Comentários Bons: Alguns “TODO”, Alertas e Destaques 3.3 Comentários
Comentário Ruim: Murmúrio e Redundância 3.3 Comentários
Comentário Ruim: Código Morto e/ou com Autoria 3.3 Comentários
Use o controle de versão!
Outros Comentários Ruins 3.3 Comentários
- Ruidosos, muito longos ou repetitivos
- Imperativos (e.g. em todas as funções)
- Marcadores de Posição //////////////// ou ************
- Ao lado de chaves de fechamento (e.g. //for)
- Comentários em HTML
- Informações excessivas
- Conexões nada óbvias
- Cabeçalhos de funções (prefira um bom nome)
- Javadoc em código não público
Parte 3.4Parte 3.4
FormataçãoFormatação
Filosofia sobre Formatação 3.4 Formatação
- Atenção ao “code convention” da linguagem
- O projeto deve ter um “code style” (bom ou ruim)
- Qualquer “code style” é melhor que nenhum
- A formatação automática evita muitas brigas
- Formatação vertical
Metáfora do jornal, distância vertical, espaçamento e
continuidade vertical
- Formatação horizontal
Indentação, espaçamento e continuidade horizontal
Formatação Vertical: Metáfora do Jornal 3.4 Formatação
Formatação Vertical: Continuidade e Espaçamento Vertical 3.4 Formatação
Linhas de código relacionadas
devem permanecer unidas
Pensamentos completos devem ser
separados por espaços em branco
Formatação Vertical: Distância Vertical 3.4 Formatação
Declaração de Variável
O mais próximo possível de
onde será usada
Variáveis de Instância
Antes dos métodos
Funções Dependentes
Verticalmente próximas
Afinidade Conceitual
Mesma convenção de nomes
atuam na mesma tarefa
devem ficar próximas
Formatação Horizontal 3.4 Formatação
Evite
- Espaçamentos manuais
- Indentação do “seu gosto”
- Mais de 120 caracteres por linha
Deixe a IDE trabalhar
- Espaçamentos automáticos
- Indentação padrão
- Quebras de linha
Regra da Tela 3.4 Formatação
<= 20
Cabe na tela
<= 500
100-120
Cabe na tela
Code Convention + Regra da Equipe 3.4 Formatação
Mantenha a paz no seu projeto: tenha um “code style” combinado pela equipe
Parte 3.5Parte 3.5
FunçõesFunções
Filosofia sobre Funções 3.5 Funções
- Funções devem ser pequenas (<= 20 linhas)
- Funções devem fazer apenas uma coisa
- Devem ter nomes descritivos do que fazem
- Somente um nível de abstração por função
- Funções devem ter poucos parâmetros
- Efeitos colaterais devem ser evitados ao máximo
- Quanto mais funções puras, melhor
- Quanto mais autocontida mais fácil de testar
Clean
Code
(2008)
Programação
Funcional
(1958)
Pura
Sem efeitos colaterais
1 nível de abstração
Faz apenas 1 coisa
Pequena
Clean Code + Programação Funcional 3.5 Funções
Regra 1 3.5 Funções
Faz Apenas 1 Coisa
- Nomes, comentários e formatação são importantes para a
leitura, mas as funções são o que o programa realmente faz
- É melhor ler e entender uma coisa de cada vez
- É melhor testar uma coisa de cada vez
1 Nível de Abstração
- Cada conceito em seu lugar apropriado
Abstração é a capacidade de separar o essencial do que
não é essencial. Separar conceitos dos detalhes.
3.5 FunçõesExemplo de Função “Suja”
Grande (34 linhas)
Faz muitas coisas:
1. Valida os números apostados
2. Verifica se está entre 6 e 15
3. Sorteia 6 números
4. Conta os acertos
5. Calcula o prêmio
Vários níveis de
abstração
1
2
3
4
5
Exemplo de Função “Limpa” 3.5 Funções
Pequena (11 linhas)
Faz 1 coisa:
1. Valida os números apostados
2. Verifica se está entre 6 e 15
3. Sorteia 6 números
4. Conta os acertos
5. Calcula o prêmio
1 nível de abstração
1 coisa e 1 nível de abstração
Indireção
Regra Decrescente 3.5 Funções
Indireção Nível de abstração 1
Nível de abstração 2
Leitura
de cima
para
baixo
Nomes
descritivos
do que
fazem
Switch Highlander (Java) 3.5 Funções
Um “Switch” deve estar em
uma classe de nível mais
baixo de abstração e
nunca ser repetido
Opção procedural
Opção polimórfica
Switch Highlander (Kotlin) 3.5 Funções
Um “Switch” deve estar em
uma classe de nível mais
baixo de abstração e
nunca ser repetido
Opção procedural
Opção polimórfica
Fibonacci (Funções Puras) 3.5 Funções
1. Para um certo Input sempre retorna o mesmo Output
2. Não causa nenhum efeito colateral
3. Não depende de nenhum dado externo (escopo)
Pedra, Papel e Tesoura: Especificação via Teste de Unidade 3.5 Funções
R (Rock/Pedra) vence S (Scissors/Tesoura)
S (Scissors/Tesoura) vence P (Paper/Papel)
P (Paper/Papel) vence R (Rock/Pedra)
Pedra, Papel e Tesoura: Contrato 3.5 Funções
Cabeçalho da Função:
pedraPapelTesoura(char,char):int
Contrato da Função:
- Recebe dois caracteres (R, P ou S)
- Se empata retorna 0
- Se o primeiro ganha retorna -1
- Se o segundo ganha retorna 1
- Se um dos caracteres é inválido gera uma
exceção “IllegalArgumentException”
(melhor que código de erro)
- R vence S, S vence P, P vence R
Pedra, Papel e Tesoura (Kotlin) 3.5 Funções
1 Nível de abstração
Faz apenas 1 coisa
Prefira exceções a retorno de códigos de erro!
É uma função pura?
Pedra, Papel e Tesoura (Java) 3.5 Funções
É uma função pura?
Parâmetros 3.5 Funções
Função Mônade P1
Função Díade
Função Tríade P1 P2 P3
P1 P2
A quantidade de parâmetros deve ser a
menor possível. Se a quantidade de
parâmetros é muito grande, pode ser usado
um objeto como parâmetro.
Objeto como Parâmetro
O parâmetro tem suas regras e seus próprios conceitos
Parâmetros Seletores e de “Saída” 3.5 Funções
Parâmetro de “Saída”
Saída deve ser no retorno
Parâmetro Seletor
É preferível dividir em duas funções
Um parâmetro seletor já indica logo
na assinatura que uma função faz
duas coisas. O ideal é fazer
duas funções separadas.
Separação Comando-Consulta 3.5 Funções
Comando + Consulta
Apenas Consulta
Apenas Comando
As funções devem somente
fazer ou responder
algo, mas não ambos. Ou altera
o estado de um objeto ou
retorna informação sobre ele.
Tratamento de Erro é 1 Coisa Só 3.5 Funções
O “try” deve ser a primeira linha da função e não deve
haver nada depois fim do bloco “try/catch/finally”
O Cerne de Boas Funções 3.5 Funções
Evite Repetição (DRY)
- Indireção, extração etc podem gerar duplicação
- Funções menores e especializadas requerem reúso (SRP)
Faça e Refaça com Confiança
- Comece fazendo funcionar e depois refatore
- Tenha cobertura de testes para ter confiança
Funções são verbos do domínio
- Uma hierarquia de funções conta uma estória
- Níveis de abstração ajudam na leitura da estória
Objetos e EstruturasObjetos e Estruturas
de Dadosde Dados
Parte 3.6Parte 3.6
Filosofia sobre Objetos e Estruturas de Dados 3.6 Objetos e E. de Dados
Os objetos usam abstrações para esconder seus
dados e expõem funções que operam sobre eles
Estruturas de dados expõem seus dados e não
possuem funções significativas (get/set = acessores)
- Objetos buscam o menor conhecimento
- Estruturas de dados (DTO) buscam imutabilidade
Estruturas de Dados nas Linguagens 3.6 Objetos e E. de Dados
Kotlin tem uma palavra reservada para definir uma estrutura
de dados: “data”. A sintaxe deixa clara a diferença entre
uma estrutura de dados e demais classes/objetos
PedidoDTO 3.6 Objetos e E. de Dados
Objeto ou Estrutura de Dados?
Pedido 3.6 Objetos e E. de Dados
Objeto ou Estrutura de Dados?
Pedido Com Mais Encapsulamento 3.6 Objetos e E. de Dados
Objeto ou Estrutura de Dados?
Feature Envy (Inveja de Funcionalidade) 3.6 Objetos e E. de Dados
https://martinfowler.com/bliki/TellDontAsk.html
Um objeto tem “inveja” da funcionalidade de
que deveria ser implementada em outro objeto
No exemplo abaixo, o primeiro “IF” tem inveja da funcionalidade
que diz se um pedido é válido, mas pedido é um OBJETO
Numa ESTRUTURA DE DADOS isso não seria problema
Princípio “Tell
Don’t Ask”
Indireção
Sobre uma Estrutura de Dados
Sobre um Objeto
Procedural x Orientado a Objetos (OO) 3.6 Objetos e E. de Dados
E se precisar calcular o perímetro?
(as estruturas de dados não serão afetadas)
E se precisar criar a classe triângulo?
Espectros de Objetos / Estrutura de Dados 3.6 Objetos e E. de Dados
Encapsulamento
Estrutura
de Dados ObjetosHíbridos
Imutabilidade
Facilita a adição de novas funcionalidades
Facilita a adição de novas classes Triângulo
Perímetro
Feature Envy no Modelo de Figuras (Shape) 3.6 Objetos e E. de Dados
Feature Envy + Efeitos Colaterais 3.6 Objetos e E. de Dados
Lei de Demeter sobre Objetos 3.6 Objetos e E. de Dados
x = a.getB().getC().getD()x = a.b.c.d
Train Wrecks
(Acidente de Trem)
a
b c d
NullPointer
Exception
(null)
Estrutura de Dados Objetos
- Imutabilidade
- Proibição de “null”
- Estados mutáveis
- Possibilidade de “null”
x = a?.b?.c?.d
(Navegação Segura)
Parte 3.7Parte 3.7
Tratamento de ErroTratamento de Erro
Filosofia sobre Tratamento de Erro 3.7 Tratamento de Erros
- Use exceções em vez de retornar códigos
- Prefira exceções não verificadas (unchecked)
- Forneça exceções com contexto e sem abafamento
- Pense no design do “try-catch-finally” antes
- Defina exceções pensando no chamador (e.g. Libs)
- Cada “catch” faz apenas uma coisa
- Não retorne nem passe “null”
- Dê preferência às exceções já fornecidas (efective java)
Código de Exceção Ruim 3.7 Tratamento de Erros
Problemas
- Não retorna uma exceção
- Abafa exceção do Gson
- Retorna “null”
- Imprime direto no console
Consequências
- Contrato baseado em “null”
- Omissão do erro raiz (causa)
- Força a testar nulidade:
kotlin: ?.
java: if (result != null)
- Log inadequado e ineficiente
Código de Exceção com Perda da Causa Raiz 3.7 Tratamento de Erros
Problemas
- Não retorna uma exceção
- Abafa exceção do Gson
- Retorna “null”
- Imprime direto no console
Consequências
- Contrato baseado em “null”
- Omissão do erro raiz (causa)
- Força a testar nulidade:
kotlin: ?.
java: if (result != null)
- Log inadequado e ineficiente
Código Melhorado (Repassando a Causa Raiz) 3.7 Tratamento de Erros
O que acontece se “json” ou “clazz” forem nulos?
Por que nunca se deve passar “null” como parâmetro?
Código de Teste Obtendo a Causa Raiz (Gson) 3.7 Tratamento de Erros
Questão Sobre a Criação de Classes de Exceção 3.7 Tratamento de Erros
Existe realmente a necessidade de criar a exceção “JsonException”?
Não seria melhor usar as exceções prontas do Gson?
Parte 3.8Parte 3.8
FronteirasFronteiras
Filosofia sobre Fronteiras 3.8 Fronteiras
- Código de terceiro quase sempre é “infraestrutura”
- Infraestrutura deve ser isolada do negócio
- Testes de aprendizado são uma boa dica
Estudo de Caso do Parsing de Json 3.8 Fronteiras
Necessidade
Fazer parsing e serialização de Json
em várias partes da aplicação
Inicialmente usando o “Gson”
Opcionalmente pode ser usado outra
biblioteca como “Jackson”
A infraestrutura deve ser isolada
Domain
ControllerController
JsonParser
Interface
toJson()
fromJson()
JsonParser
Interface
toJson()
fromJson()
GsonParserGsonParser
JacksonParserJacksonParser
Estudo de Caso do Parsing de Json 3.8 Fronteiras
Terceiros Infraestrutura
Infraestrutura
Aplicação
API de Terceiros
Estudo de Caso do Parsing de Json 3.8 Fronteiras
GsonParserGsonParser
JacksonParserJacksonParser
Parser Baseado no Gson 3.8 Fronteiras
GsonParserGsonParser
Encapsula o Gson
É um JsonParser
Injetando Dependência 3.8 Fronteiras
Criação manual
Injeção de dependência
Controller
Parser
Interface
toJson()
fromJson()
GsonParser
JacksonParser
Teste de Aprendizado do Gson 3.8 Fronteiras
Parte 3.9Parte 3.9
Testes de UnidadeTestes de Unidade
Filosofia sobre Testes de Unidade 3.9 Testes de Unidade
- Teste de unidade dá feedback sobre o design
- O feedback deve chegar o quanto antes
- TDD é uma boa opção para tornar mais fácil
- Testes de unidade são atividade de construção
- Cobertura de testes provê confiança
- Refatoração sem cobertura pode ser uma aventura
- Teste também é código e deve ser limpo
Cenário de Construção com TDD em 3 Iterações 3.9 Testes de Unidade
Requisitos do Contador de Constantes
1. Criar uma função que conte todas as constantes inteiras de uma
classe passada como parâmetro (atributos estáticos e “final”)
2. Parâmetro “null”, classes abstratas e enuns são ignorados e
deve ser retornado “-1” como resultado da função
3. A contagem deve incluir todas as superclasses
As 3 Regras do TDD 3.9 Testes de Unidade
Refatora
Falha
Passa
1. Você não pode escrever nenhum código até ter escrito um
teste que detecte uma possível falha.
2. Você não pode escrever mais testes de unidade do que o
suficiente para detectar a falha – não compilar é não ter
efeito.
3. Você não pode escrever mais código do que o suficiente
para passar nos testes.
TDD – Escrever a Primeira Versão do Teste e Falhar 3.9 Testes de Unidade
Falha
1. Criar uma função que conte
todas as constantes inteiras de
uma classe (estáticos e “final”)
TDD – Escrever o Código Real e Passar 3.9 Testes de Unidade
Passa
TDD – Refatorar o Código Real e Passar (Apenas Melhoria) 3.9 Testes de Unidade
Passa
Extração da lista
Extração do método
TDD – Refatorar o Teste para o Requisito 2 (Iteração 2) 3.9 Testes de Unidade
2. Classes abstratas e enuns são ignorados (retornar -1), inclusive “null”
Refatora
TDD – Teste Refatorado Vai Falhar 3.9 Testes de Unidade
Falha
Falha Aqui
TDD – Ajuste do Código para Atender o Teste (Iteração 2) 3.9 Testes de Unidade
Passa
Adição do requisito 2
TDD – Refatorar o Teste para o Requisito 3 (Iteração 3) 3.9 Testes de Unidade
3. A contagem deve incluir as superclasses
Refatora
TDD – Teste Refatorado Vai Falhar (Iteração 3) 3.9 Testes de Unidade
Falha
Tem 2 constantes
Falha Aqui
TDD – Ajuste do Código para Atender o Teste (Iteração 3) 3.9 Testes de Unidade
Passa
Adição do requisito 3
Parte 3.10Parte 3.10
ClassesClasses
Filosofia sobre Classes 3.10 Classes
- Classes devem ser pequenas
- Devem ter somente uma responsabilidade (SRP)
- Ter apenas um motivo para mudar
- Devem ter coesão interna*
* Poucas variáveis de instância
* Cada método manipula uma variável ou mais
- Devem encapsular seus dados ao máximo
- Devem ter baixo acoplamento a outras classes
Jogando “Pedra, Papel e Tesoura” 3.10 Classes
Requisitos do Melhor de 3 (Pedra, Papel e Tesoura)
1. Criar uma simulação de dois jogadores jogando “pedra, papel e
tesoura” por um número variável de rodadas (3, 5 etc).
2. O jogo deve parar se um jogador já for o vencedor antes da última
rodada (cenário de vitória antecipada).
3. Ao final deve ser indicado o vencedor (ou empate) e listados os
resultados de todas as rodadas.
Código Fornecido 3.10 Classes
Enum
Mão: Possibilidades de
escolha (Pedra, Papel ou
Tesoura)
Código Fornecido 3.10 Classes
Enum
Resultado: Resultado em relação
ao primeiro jogador:
Perde: -1
Empata: 0
Vence: 1
Abstração de pedraPapelTesoura
Código Fornecido 3.10 Classes
Enum
ResultadoJogada: Resultados
de um match (Primeiro Vence,
Empate ou Segundo Vence)
Implementação Procedural Simples 3.10 Classes
pedraPapelTesoura(char,char):int
Problemas
- Um método faz tudo
- Muitos conceitos juntos:
“Jogador”, “Match”, “Resultados”
- “Rodadas” constantes
- Nomes “hard coded”
- Não pára em vitória antecipada
Questões
Como se livrar do código legado
pedraPapelTesoura ?
A solução é muito procedural?
Como testar isso?
2 escolhas aleatórias
Modelo Lógico: Possível Solução OO 3.10 Classes
Níveis de Abstração
- O Jogo e os resultados
- Uma Disputa entre jogadores
- O resultado de uma disputa
- Jogador com nome e escolha
- A opção de jogada
Modelo Lógico: Análise dos Conceitos do Jogo 3.10 Classes
Inicialização e Contexto
Conceito: 1 JogadorConceito: 1 Disputa
Conceito: O Jogo em si
Várias rodadas e resultado
Código “Legado”: Lógica do jogo
Conceito: Resultado de uma Disputa
Abstração sobre -1,0,1
Opções do Jogo: R, P e S
Implementação OO - Main 3.10 Classes
Instanciação de
dependências
Inicialização
em “jogar()”
I/O = Efeito colateralI/O = Efeito colateral
Classe MelhorDeTres 3.10 Classes
Responsabilidade: representa um jogo de
“Pedra, Papel e Tesoura” com a definição
do número de rodadas (3 por padrão) e
armazena os resultados (estado)
API
- Executa o jogo (play)
- Retorna se tem vencedor
- Retorna o vencedor (se houver)
- Retorna os resultados
Delega para a classe Match o
conhecimento sobre a disputa entre dois
jogadores e seu resultado
Indireção para Jogada
Requisito número 2
Dependência será resolvida
via construtor
Classe JogadaLegada (Implementa Jogada) 3.10 Classes
Representa uma disputa entre dois jogadores e seu resultado (imutável)
API: Executa a disputa (play) e gera um resultado
Delega para os jogadores a escolha da “mão” que será jogada. Delega para a função
rockPaperScissors a lógica de quem venceu a disputa com base nestas escolhas
Classe Jogador 3.10 Classes
Representa um jogador que deve fazer uma escolha de qual mão usar na disputa
Delega para Mao a escolha de forma aleatória, mas encapsula esta decisão
O jogador poderia ser criado com a escolha já feita anteriormente
Solução OO x Procedural 3.10 Classes
A solução OO tem mais código, mas cada parte é mais fácil de entender que o todo
Permite testes de unidade por classe
Cada abstração está em uma classe
Cada classe tem uma responsabilidade
A necessidade de manutenção tende a impactar somente uma parte do código
Refatoração: Livrando-se do Código Legado 3.10 Classes
Como remover pedraPapelTesoura?
Qual classe deve conhecer esta regra
de quem vence quem?
Como implementar a regra de forma a
gerar o menor impacto possível?
Qual seria o impacto de alterar e
testar na solução procedural?
Especificação da Regra “Pedra/Papel/Tesoura” Legada 3.10 Classes
Especificação da Regra “Pedra/Papel/Tesoura” OO 3.10 Classes
Responsabilidade da Classe “Mao” 3.10 Classes
Código expressivo sobre a regra do jogo
Função (API) que externaliza a regra
Impacto: Nova Classe Implementando “Jogada” 3.10 Classes
Implementação alternativa de “Jogada” livre do código legado
O método “jogar” expressa o negócio de forma simples e elegante
Função (API)
que externaliza
a regra
JogadaLegada x JogadaSimples (Nova) 3.10 Classes
- Mais semântico e claro
- Dispensa o enum “Resultado”
- Delega para o método “vence” de
uma outra classe (“Mao”)
Kotlin infix
Impacto da Refatoração na Classe “Main” 3.10 Classes
Criação da classe “JogadaSimples” (Troca de “JogadaLegada” por “JogadaSimples”)
A classe “MelhorDeTres” não teve nenhum impacto e ainda recebe a dependência
Responsabilidades:
- Criar Jogadores
- Criar Jogada
- Inicializar o Jogo
...
- Conexão de Banco ?
- I/O, Integrações ?
Parte 3.11Parte 3.11
SistemasSistemas
Filosofia sobre Testes de Unidade 3.11 Sistemas Complexos
- Sistemas precisam de separação de preocupações
- Separe a inicialização do uso de um sistema
- Sistemas beneficiam-se do uso de uma DSL
Modularização e Separação de Preocupações 3.11 Sistemas Complexos
- Criação de objetos e escopos superiores
- Conexão com BD, I/O e efeitos colaterais DDD e Preocupações Transversais
Main main()
Negocio
Módulo A
Domain Service
Módulo B
Função X1
Classe X Função X2
Função X3
Factory Create
Módulo C
Função Y1
Classe Y Função Y2
Função Y3
Repository Save
Log
Segurança
BD
I/O
Inicialização e Contexto
Conceito: 1 JogadorConceito: 1 Disputa
Conceito: O Jogo em si
Várias rodadas e resultado
Código “Legado”: Lógica do jogo
Conceito: Resultado de uma Disputa
Abstração sobre -1,0,1
Opções do Jogo: R, P e S
Separe a Construção do Uso no Sistema 3.11 Sistemas Complexos
As demais classes não
devem conhecer sobre
contexto e inicialização
Devem ser projetadas
como se isso fosse ser
resolvido para elas…
E será!
Main conhece o sistema
Sistema ignora o Main
Função pura ignora tudo
fora do seu escopo
Injeção de Dependência Via Construtor 3.11 Sistemas Complexos
O uso de CDI com
@inject faz o mesmo
trabalho automaticamente
Injeção de dependência minimiza o
acoplamento entre classes além de
facilitar os testes de unidade
DSL – Domain Specific Language 3.11 Sistemas Complexos
DSL: Código
Expressivo
DSL encapsula a lógica
Main main()
Negocio
Módulo A
Domain Service
Módulo B
Função X1
Classe X Função X2
Função X3
Factory Create
Módulo C
Função Y1
Classe Y Função Y2
Função Y3
Repository Save
Classes e Funções são negócio destilado
O domínio do problema é descrito na solução
Parte 3.12Parte 3.12
SimplicidadeSimplicidade
Filosofia sobre Simplicidade 3.12 Simplicidade
- Todos os testes devem passar (deve haver testes)
- Nenhuma duplicação de código ou configuração
- O código deve expressar o negócio e sua intenção
- A solução deve usar o mínimo de elementos
- Simples não é Simplório (pelo contrário)
- Simplicidade é a sofisticação máxima
As 4 Regras da Simplicidade 3.12 Simplicidade
Testes Tempestivos
Refatoração Tempestiva
https://martinfowler.com/bliki/BeckDesignRules.html
Regra 1 de Projeto Simples: Efetue Todos os Testes 3.12 Simplicidade
1 2
3
Teste 1: Afere se a regra entre as opções
está funcionando: Pedra vence Tesoura,
Tesoura vence Papel e Papel vence Pedra
Teste 2: Afere se o SmartMatch retorna o
resultado certo dado que já se sabe o que
os jogadores vão escolher (mock)
Teste 3: Afere que, de 7 rodadas, irá parar
na quarta com 4 vitórias de “Bob”
Regras de 2 a 4 de Projeto Simples: Refatoração 3.12 Simplicidade
Conceitos
- O Jogo e os resultados
- Uma Disputa entre jogadores
- O resultado de uma disputa
- Jogador com nome e escolha
- A opção de jogada
DSL: Código
Expressivo
A: Reúso
B: Refactoring
Regra
1 conceito p/ classe
já sei clean code?
técnicatécnica, treino e tempo, treino e tempo
abordagem de atuação profissional
não é sobre códigonão é sobre código
é sobreé sobre fazer códigofazer código
RefatoraçãoRefatoração
Parte 4
Laboratório de Refatoração 4 Refatoração
treinotreino
github.com/refactown/lab
REFERÊNCIAS
BECK, Kent. Padrões de Implementação. Porto Alegre, Bookman, 2013.
EVANS, E. Domain-Driven Design – Atacando as complexidades no coração do software. 2a edição, Rio de
Janeiro, Alta Books, 2010.
FOWLER, Martin. BeckDesignRules, https://martinfowler.com/bliki/BeckDesignRules.html
FOWLER, Martin. TellDontAsk, https://martinfowler.com/bliki/TellDontAsk.html
HUNT, Andrew; THOMAS, David, O Programador Pragmático, Bookman, 2010
MARTIN, Robert, O Codificador Limpo, Alta Books, Rio de Janeiro 2012
MARTIN, Robert, Código Limpo, Alta Books, Rio de Janeiro 2011
Programação Funcional X Orientação a Objetos
155/155
1 42 3 5
Prática
para encerrar...
Obrigado!
Douglas Siviotti
douglas.siviotti@gmail.com
github.com/siviotti
Teoria

clean code

  • 1.
    Clean Code naPrática Conceitos de Clean Code Apresentados em Exemplos de Código Douglas Siviotti Novembro de 2019 V1.1
  • 2.
    Sobre esta Apresentação 1.Conteúdo: Clean Code (Código Limpo) 2. Área/Foco: Engenharia de Software, Desenvolvimento Ágil 3. Público alvo: Desenvolvedores 4. Conteúdo relacionado: OO, Programação Funcional, DDD, SOLID, GRASP Organização (155 slides) Parte 1 – Um Pouco de Filosofia Parte 2 – Um Pouco de Teoria (Conceitos Relacionados) Parte 3 – Clean Code na Prática em Exemplos de Código Parte 4 – Laboratório de Refatoração Código-fonte usado nesta apresentação: https://github.com/refactown/cleancode Cognição Micro Design Integração Macro Design
  • 3.
    Sintomas comuns equipe entregando cadavez menos pontos a cada sprint estimativas frustradas: o esforço é sempre maior que o previsto erros frequentes em produção correção de um bug causa outros problemas não previstos incidentes resolvidos e o mesmo erro voltando a aparecer muito “To Do” espalhado pelo código e/ou código morto dificuldade de evolução ou incorporação de novas funcionalidades
  • 4.
    Código Ruim manutenção difícil +retrabalho e - produtividade Código Ruim manutenção difícil + retrabalho e - produtividade Procrastinação aversão a mudanças criação de dívida técnica Procrastinação aversão a mudanças criação de dívida técnica Falta de Testes design pobre e inflexível falta de segurança p/ o dev Falta de Testes design pobre e inflexível falta de segurança p/ o dev Pressão bugs, incidentes, pouco valor, baixa evolução: insatisfação Pressão bugs, incidentes, pouco valor, baixa evolução: insatisfação ciclo vicioso da dívida técnica
  • 5.
    Código Limpo fácil deentender e manter expressa o negócio Código Limpo fácil de entender e manter expressa o negócio Refatoração adaptação ao novo problema tratamento de dívida técnica Refatoração adaptação ao novo problema tratamento de dívida técnica Teste de Unidade guiando o design (feedback) com boa cobertura Teste de Unidade guiando o design (feedback) com boa cobertura Entregas c/ Valor evolução sustentável cliente satisfeito Entregas c/ Valor evolução sustentável cliente satisfeito ciclo da eficácia no software sob medida
  • 6.
    Clean Code Fazer códigopara ser lido e entendido por outras pessoas Clean Code Fazer código para ser lido e entendido por outras pessoas Refatoração adaptação ao novo problema tratamento de dívida técnica Teste de Unidade guiando o design (feedback) com boa cobertura Entregas c/ Valor evolução sustentável cliente satisfeito ciclo da eficácia no software sob medida
  • 7.
    Um PoucoUm Pouco deFilosofiade Filosofia Parte 1
  • 8.
    Pequenas CoisasPequenas Coisas ImportamImportam “Deusestá nos detalhes” “Menos é mais” (Ludwig Mies van der Rohe) Quem não faz bem as pequenas coisas, não faz bem coisa alguma
  • 9.
    código é detalhamentocódigoé detalhamento dos requisitos e devedos requisitos e deve expressar o negócioexpressar o negócio
  • 10.
    código deve serfeito para ser lido por outra pessoacódigo deve ser feito para ser lido por outra pessoa comunique, não codifique!
  • 11.
    código ruim geracódigoruim gera baixa produtividadebaixa produtividade que gera código piorque gera código pior seja um glóbulo branco prevenir é melhor que remediar por que
  • 12.
    CódigoCódigo Limpo?Limpo? “elegante e eficiente fazapenas uma coisa” Bjarne Stroustrup “simples e direto - legível” Grady Booch “inteligível ao seres humanos” Dave Thomas “escrito por alguém que se importava” Michael Feathers “sem duplicação, expressivo, pequenas abstrações” Ron Jeffries “a linguagem parece que foi feita para o problema” Ward Cunningham O que é
  • 13.
    A T IT U D EA T I T U D E teoria da janela quebrada regra do escoteiro quando programador profissional quem quando
  • 14.
    técnica, treino etempotécnica, treino e tempo livros de arte não fazem um artista trabalho artesanal mas profissional como
  • 15.
    Um Pouco deTeoria*Um Pouco de Teoria* *Oriunda de muita prática*Oriunda de muita prática Parte 2
  • 16.
    Título do Slide(Arial 18) 16/155 2.1 DDD: Negócio ao Código 2.2 Linguagem Onipresente 2.3 Princípio SRP 2.4 Princípio DRY 2.5 Indireção / Delegação 2.6 Lei de Demeter 2.7 Acoplamento e Coesão 2.8 Imutabilidade 2.9 OO + Funções Puras 2.10 Testes Tempestivos 2.11 Refatoração Tempestiva 2.12 Regras da Simplicidade Conceitos relacionados
  • 17.
    O requisito estáno código, mas muito código não vem do requisito O domínio de um problema organiza os conceitos sobre os quais é baseada a solução de software Foco no Negócio Parte do código deve expressar o negócio Isolamento do Domínio O código de domínio é idiossincrático e particular Infraestrutura à Parte Tecnologias vêm e vão, o negócio permanece Do Negócio ao Código Via DDD 2.1 Negócio ao Código Domain
  • 18.
    DDD e osNomes das Coisas 2.2 Linguagem Onipresente Ubiquos Language Service Entity Value Object Agregate Factory Model-driven Design Bounded Context RepositoryDomain Events Layered Architecture Core Domain Context Map Continuos Integration Linguagem Onipresente (Ubíqua) - Termos e conceitos usados pelos desenvolvedores e pelos especialistas no negócio - Presente na fala de todos e no código de domínio Contexto Delimitado - Partes bem delimitadas de um domínio - Candidatos a microsserviços Tijolos de Construção - Entidades, Objetos de Valor, Agregados - Eventos de Domínio - Serviços, Fábricas, Repositórios
  • 19.
    Princípio da ResponsabilidadeÚnica (SRP) 2.3 Princípio SRP “Cada módulo de um software deve ter um e apenas um motivo para mudar” 1 O que seria apenas “uma” responsabilidade?
  • 20.
    Menos é Mais2.4 Princípio DRY DRY = Don’t Repeat Yourself “Não Se Repita” (código, requisito, teste etc) Toda parte do conhecimento deve ter uma representação única e livre de ambiguidades em todo o sistema Problemas - Mais trabalho: alterar mais vezes - Mais risco: encontrar todos os lugares - Mais teste: testar várias vezes a mesma coisa - Mais esforço de comunicação
  • 21.
    Indireção ou Delegação2.5 Indireção / Delegação SRP Fazer apenas uma coisa em um certo lugar SRP Fazer apenas uma coisa em um certo lugar DRY Fazer apenas em um lugar uma certa coisa DRY Fazer apenas em um lugar uma certa coisa Coisa única em um único lugar “A” Coisa única em um único lugar “A” Outra coisa única em um único lugar “B” Outra coisa única em um único lugar “B” Indireção ou Delegação 1. Não pode conter 2. Não pode copiar 3. Precisa referenciar Indireção Indireção Calculo de Frete Busca de EndereçoEfetuar Pedido
  • 22.
    Lei de Demeter– Princípio do Menor Conhecimento 2.6 Lei de Demeter Um módulo não deve enxergar o interior dos objetos que ele manipula Um método “m” de uma classe “C” só deve chamar: - Objetos do tipo “C” - Parâmetros passados para o método “m” (e.g. “x: P”) - Um objeto criado pelo próprio método “m” - Variáveis de instância da classe “C” (e.g. “a: A”) Train Wreck (Acidente de Trem): x.getY().getZ() “Você não manda as pernas do cachorro andarem e sim o cachorro” Classe “C” Atributo a: A Método “m” (x: X) Classe X Atributo y : Y Classe Y Atributo z : Z
  • 23.
    Baixo Acoplamento eAlta Coesão 2.7 Acoplamento e Coesão Alto Acoplamento Baixa Coesão (entre classes) Poucas classes e grandes Mais dependência por classe Maior conhecimento Baixo Acoplamento Alta Coesão (entre classes) Muitas classes e pequenas Menos dependência por classe Menor conhecimento Coesão de uma Classe: - Poucas variáveis de instância - Cada método manipula uma ou mais Uma classe pouco coesa sugere que uma nova classe deve “nascer”
  • 24.
    Quanto Mais ImutávelMelhor 2.8 Imutabilidade Evite Surpresas Imutabilidade é uma defesa contra efeitos colaterais Vantagens - Mais seguro e confiável - Mais legível: minimiza testes e garantias diminui o código por tabela - Paralelismo e escalabilidade private final int idade;
  • 25.
    Quanto Mais PuroMelhor 2.9 OO + Funções Puras Função Pura 1. Para um certo Input sempre retorna o mesmo Output 2. Não causa nenhum efeito colateral 3. Não depende de nenhum dado externo (autocontida) Vantagens - Mais simples e menores - Mais fácil de entender e testar Quando usar em código OO? Sempre que possível Em muitas situações não é possível: BD, integração, estados etc Possível em regras de negócio, métodos utilitários, internos etc Function Input Output IMUTABILIDADE - efeitos colaterais
  • 26.
    TDD e TestesTempestivos 2.10 Testes Tempestivos TDD – Test Driven Development (Desenvolvimento Guiado por Testes) - Escreve um teste que falha antes do código produtivo - Faz o teste passar ao construir o código produtivo - Refatora o código até o teste falhar (ou não) Testes Tempestivos (TDD inclusive) (teste que ajuda na construção, logo cedo) 1. Atividade de engenharia (código e design) 2. Feedback rápido sobre o código testado (erra cedo) 3. Gera código limpo através da “dificuldade” de testar 4. Antecipa o custo gasto em correções e debug 5. Ainda serve como teste de regressão Refatora Falha Passa Ciclos Curtos
  • 27.
    Refatoração Tempestiva 2.11Refatoração “Refatoração (refactoring) é a disciplina técnica para reestruturar um determinado código, alterando sua estrutura interna sem mudar seu comportamento externo” Martin Fowler Problema Inicial Solução Inicial Problema Refinado Refatoração Mudança Solução Final Validar Solução Refinamento Ciclo de Sprint Ajuste da solução em função de: - uma nova visão sobre o problema - preparar para uma evolução ou mudança Pequenas mudanças que fazem diferença no longo prazo
  • 28.
    Quatro Regras daSimplicidade (Martin Fowler : Kent Beck) 2.12 Simplicidade Testes Tempestivos Refatoração Tempestiva https://martinfowler.com/bliki/BeckDesignRules.html
  • 29.
    Conceitos Relacionados Conceitos DDDDDDLinguagem Onipresente Linguagem Onipresente Indireção Abstração, especialização Indireção Abstração, especialização Lei de Demeter Mínimo conhecimento Lei de Demeter Mínimo conhecimento Princípio SRP Responsabilidade Única Princípio SRP Responsabilidade Única Princípio DRY Não Se Repita Princípio DRY Não Se Repita Acoplamento e Coesão Acoplamento e Coesão Funções Puras OO ou funcional Funções Puras OO ou funcionalInfraInfra DomínioDomínio AppApp Refatoração Tempestiva Refatoração Tempestiva Teste Tempestivo Teste Tempestivo 4 Regras da Simplicidade 4 Regras da Simplicidade Imutabilidade - efeitos colaterais Imutabilidade - efeitos colaterais Clean Code Clean Code
  • 30.
  • 31.
    Título do Slide(Arial 18) 31/155 3.1 Código Limpo 3.2 Nomes Significativos 3.3 Comentários (capítulo 4) 3.4 Formatação (capítulo 5) 3.5 Funções (capítulo 3) 3.6 Objetos e E. de Dados 3.7 Tratamento de Erro 3.8 Fronteiras (Limites) 3.9 Testes de Unidade 3.10 Classes 3.11 Sistemas Complexos 3.12 Simplicidade Prática - filosofia - bad smell - boa prática - exemplo - exercício Cognição Entendimento e leitura Integração Contratos e expectativas Macro Design Escala e expansão Micro Design Estado e comportamento
  • 32.
    Código LimpoCódigo Limpo (VisãoGeral)(Visão Geral) Parte 3.1Parte 3.1
  • 33.
    Filosofia sobre CódigoLimpo (Visão Geral) 3.1 Código Limpo - O código não fica nem se mantém limpo sozinho - Todos na equipe devem praticar e cobrar - Manter o código limpo é uma atividade diária - Funciona como na “Teoria das janelas quebradas” - Atitude é mais relevante do que “patrocínio” - Sempre dá pra começar (regra do escoteiro) - Ler e entender consome mais tempo que escrever - Precisa de tempo, técnica e treino pra fazer bem
  • 34.
    Código Ruim 3.1Código Limpo Problemas - Nomes ruins - Função grande e complexa (SRP) - Comentários questionáveis - Formatação inexistente Dificuldades - Legibilidade: confuso - Testabilidade: alta complexidade
  • 35.
    Código Menos Ruim3.1 Código Limpo Problemas - Nomes ruins - Função grande e complexa (SRP) - Comentários questionáveis - Formatação inexistente Dificuldades - Legibilidade: confuso - Testabilidade: alta complexidade
  • 36.
    Código Melhorado (Refatorado)3.1 Código Limpo O que pode melhorar?
  • 37.
    Possíveis Melhorias 3.1Código Limpo Lançar Exceção Constantes Enum “Premio” Classe Separada
  • 38.
  • 39.
    Filosofia sobre Nomes3.2 Nomes Significativos - Nomes são muito importantes (especialmente em OO) - Use nomes que revelam seu propósito - Evite informações erradas (itemList: Map) - Faça distinções significativas (evite a1, a2 a3...) - Nomes pronunciáveis e passíveis de busca - Evite codificações (e.g. notação húngara e similares) - classes = substantivos, métodos = verbos - Selecione uma palavra por conceito (get, set, find) - Nomes do problema (Pedido, Item) e da solução (DAO) - Adicione ou evite contexto quando necessário
  • 40.
    Bad Smell 3.2Nomes Significativos Problemas - Nomes genéricos “i”, “x”, “d” etc - Nomes impronunciáveis - Número Mágico (perdido no código) - Notação Húngara - Interface prefixada - Nome com contexto redundante
  • 41.
    Boa Prática 3.2Nomes Significativos Alternativas - Nomes que revelam propósito - Nomes pronunciáveis - Constantes para número mágico (passíveis de busca) - Sem Notação Húngara - Interface = Conceito - Nomes com o mínimo necessário
  • 42.
    Problema x Solução3.2 Nomes Significativos Problema Solução
  • 43.
    Modelo de Exemplo3.2 Nomes Significativos Nomes a partir do domínio do problema (Pedido, Item etc) Nomes a partir do domínio da solução (Controller, Delegate, DAO) Classes = Substantivos, Métodos = Verbos Nomes pronunciáveis e passíveis de busca
  • 44.
  • 45.
    Filosofia sobre Comentários3.3 Comentários “Qualquer um pode escrever código que o computador entenda. Bons programadores escrevem códigos que os humanos entendem.” Martin Fowler - Comentários são a última opção do programador - O programador deve expressar-se no código - Comunique, não codifique (outros devem ler) - Comentário pode estar compensando código ruim - Alguns comentários são bons ou necessários
  • 46.
    Explique-se no Código3.3 Comentários Alguns comentários existem para explicar código ruim. Um comentário deve explicar “o porquê” e nunca “o que” Não comente, refatore!
  • 47.
    Comentários Bons: Legaise APIs Públicas 3.3 Comentários
  • 48.
    Comentários Bons: Alguns“TODO”, Alertas e Destaques 3.3 Comentários
  • 49.
    Comentário Ruim: Murmúrioe Redundância 3.3 Comentários
  • 50.
    Comentário Ruim: CódigoMorto e/ou com Autoria 3.3 Comentários Use o controle de versão!
  • 51.
    Outros Comentários Ruins3.3 Comentários - Ruidosos, muito longos ou repetitivos - Imperativos (e.g. em todas as funções) - Marcadores de Posição //////////////// ou ************ - Ao lado de chaves de fechamento (e.g. //for) - Comentários em HTML - Informações excessivas - Conexões nada óbvias - Cabeçalhos de funções (prefira um bom nome) - Javadoc em código não público
  • 52.
  • 53.
    Filosofia sobre Formatação3.4 Formatação - Atenção ao “code convention” da linguagem - O projeto deve ter um “code style” (bom ou ruim) - Qualquer “code style” é melhor que nenhum - A formatação automática evita muitas brigas - Formatação vertical Metáfora do jornal, distância vertical, espaçamento e continuidade vertical - Formatação horizontal Indentação, espaçamento e continuidade horizontal
  • 54.
    Formatação Vertical: Metáforado Jornal 3.4 Formatação
  • 55.
    Formatação Vertical: Continuidadee Espaçamento Vertical 3.4 Formatação Linhas de código relacionadas devem permanecer unidas Pensamentos completos devem ser separados por espaços em branco
  • 56.
    Formatação Vertical: DistânciaVertical 3.4 Formatação Declaração de Variável O mais próximo possível de onde será usada Variáveis de Instância Antes dos métodos Funções Dependentes Verticalmente próximas Afinidade Conceitual Mesma convenção de nomes atuam na mesma tarefa devem ficar próximas
  • 57.
    Formatação Horizontal 3.4Formatação Evite - Espaçamentos manuais - Indentação do “seu gosto” - Mais de 120 caracteres por linha Deixe a IDE trabalhar - Espaçamentos automáticos - Indentação padrão - Quebras de linha
  • 58.
    Regra da Tela3.4 Formatação <= 20 Cabe na tela <= 500 100-120 Cabe na tela
  • 59.
    Code Convention +Regra da Equipe 3.4 Formatação Mantenha a paz no seu projeto: tenha um “code style” combinado pela equipe
  • 60.
  • 61.
    Filosofia sobre Funções3.5 Funções - Funções devem ser pequenas (<= 20 linhas) - Funções devem fazer apenas uma coisa - Devem ter nomes descritivos do que fazem - Somente um nível de abstração por função - Funções devem ter poucos parâmetros - Efeitos colaterais devem ser evitados ao máximo - Quanto mais funções puras, melhor - Quanto mais autocontida mais fácil de testar
  • 62.
    Clean Code (2008) Programação Funcional (1958) Pura Sem efeitos colaterais 1nível de abstração Faz apenas 1 coisa Pequena Clean Code + Programação Funcional 3.5 Funções
  • 63.
    Regra 1 3.5Funções Faz Apenas 1 Coisa - Nomes, comentários e formatação são importantes para a leitura, mas as funções são o que o programa realmente faz - É melhor ler e entender uma coisa de cada vez - É melhor testar uma coisa de cada vez 1 Nível de Abstração - Cada conceito em seu lugar apropriado Abstração é a capacidade de separar o essencial do que não é essencial. Separar conceitos dos detalhes.
  • 64.
    3.5 FunçõesExemplo deFunção “Suja” Grande (34 linhas) Faz muitas coisas: 1. Valida os números apostados 2. Verifica se está entre 6 e 15 3. Sorteia 6 números 4. Conta os acertos 5. Calcula o prêmio Vários níveis de abstração 1 2 3 4 5
  • 65.
    Exemplo de Função“Limpa” 3.5 Funções Pequena (11 linhas) Faz 1 coisa: 1. Valida os números apostados 2. Verifica se está entre 6 e 15 3. Sorteia 6 números 4. Conta os acertos 5. Calcula o prêmio 1 nível de abstração 1 coisa e 1 nível de abstração Indireção
  • 66.
    Regra Decrescente 3.5Funções Indireção Nível de abstração 1 Nível de abstração 2 Leitura de cima para baixo Nomes descritivos do que fazem
  • 67.
    Switch Highlander (Java)3.5 Funções Um “Switch” deve estar em uma classe de nível mais baixo de abstração e nunca ser repetido Opção procedural Opção polimórfica
  • 68.
    Switch Highlander (Kotlin)3.5 Funções Um “Switch” deve estar em uma classe de nível mais baixo de abstração e nunca ser repetido Opção procedural Opção polimórfica
  • 69.
    Fibonacci (Funções Puras)3.5 Funções 1. Para um certo Input sempre retorna o mesmo Output 2. Não causa nenhum efeito colateral 3. Não depende de nenhum dado externo (escopo)
  • 70.
    Pedra, Papel eTesoura: Especificação via Teste de Unidade 3.5 Funções R (Rock/Pedra) vence S (Scissors/Tesoura) S (Scissors/Tesoura) vence P (Paper/Papel) P (Paper/Papel) vence R (Rock/Pedra)
  • 71.
    Pedra, Papel eTesoura: Contrato 3.5 Funções Cabeçalho da Função: pedraPapelTesoura(char,char):int Contrato da Função: - Recebe dois caracteres (R, P ou S) - Se empata retorna 0 - Se o primeiro ganha retorna -1 - Se o segundo ganha retorna 1 - Se um dos caracteres é inválido gera uma exceção “IllegalArgumentException” (melhor que código de erro) - R vence S, S vence P, P vence R
  • 72.
    Pedra, Papel eTesoura (Kotlin) 3.5 Funções 1 Nível de abstração Faz apenas 1 coisa Prefira exceções a retorno de códigos de erro! É uma função pura?
  • 73.
    Pedra, Papel eTesoura (Java) 3.5 Funções É uma função pura?
  • 74.
    Parâmetros 3.5 Funções FunçãoMônade P1 Função Díade Função Tríade P1 P2 P3 P1 P2 A quantidade de parâmetros deve ser a menor possível. Se a quantidade de parâmetros é muito grande, pode ser usado um objeto como parâmetro. Objeto como Parâmetro O parâmetro tem suas regras e seus próprios conceitos
  • 75.
    Parâmetros Seletores ede “Saída” 3.5 Funções Parâmetro de “Saída” Saída deve ser no retorno Parâmetro Seletor É preferível dividir em duas funções Um parâmetro seletor já indica logo na assinatura que uma função faz duas coisas. O ideal é fazer duas funções separadas.
  • 76.
    Separação Comando-Consulta 3.5Funções Comando + Consulta Apenas Consulta Apenas Comando As funções devem somente fazer ou responder algo, mas não ambos. Ou altera o estado de um objeto ou retorna informação sobre ele.
  • 77.
    Tratamento de Erroé 1 Coisa Só 3.5 Funções O “try” deve ser a primeira linha da função e não deve haver nada depois fim do bloco “try/catch/finally”
  • 78.
    O Cerne deBoas Funções 3.5 Funções Evite Repetição (DRY) - Indireção, extração etc podem gerar duplicação - Funções menores e especializadas requerem reúso (SRP) Faça e Refaça com Confiança - Comece fazendo funcionar e depois refatore - Tenha cobertura de testes para ter confiança Funções são verbos do domínio - Uma hierarquia de funções conta uma estória - Níveis de abstração ajudam na leitura da estória
  • 79.
    Objetos e EstruturasObjetose Estruturas de Dadosde Dados Parte 3.6Parte 3.6
  • 80.
    Filosofia sobre Objetose Estruturas de Dados 3.6 Objetos e E. de Dados Os objetos usam abstrações para esconder seus dados e expõem funções que operam sobre eles Estruturas de dados expõem seus dados e não possuem funções significativas (get/set = acessores) - Objetos buscam o menor conhecimento - Estruturas de dados (DTO) buscam imutabilidade
  • 81.
    Estruturas de Dadosnas Linguagens 3.6 Objetos e E. de Dados Kotlin tem uma palavra reservada para definir uma estrutura de dados: “data”. A sintaxe deixa clara a diferença entre uma estrutura de dados e demais classes/objetos
  • 82.
    PedidoDTO 3.6 Objetose E. de Dados Objeto ou Estrutura de Dados?
  • 83.
    Pedido 3.6 Objetose E. de Dados Objeto ou Estrutura de Dados?
  • 84.
    Pedido Com MaisEncapsulamento 3.6 Objetos e E. de Dados Objeto ou Estrutura de Dados?
  • 85.
    Feature Envy (Invejade Funcionalidade) 3.6 Objetos e E. de Dados https://martinfowler.com/bliki/TellDontAsk.html Um objeto tem “inveja” da funcionalidade de que deveria ser implementada em outro objeto No exemplo abaixo, o primeiro “IF” tem inveja da funcionalidade que diz se um pedido é válido, mas pedido é um OBJETO Numa ESTRUTURA DE DADOS isso não seria problema Princípio “Tell Don’t Ask” Indireção Sobre uma Estrutura de Dados Sobre um Objeto
  • 86.
    Procedural x Orientadoa Objetos (OO) 3.6 Objetos e E. de Dados E se precisar calcular o perímetro? (as estruturas de dados não serão afetadas) E se precisar criar a classe triângulo?
  • 87.
    Espectros de Objetos/ Estrutura de Dados 3.6 Objetos e E. de Dados Encapsulamento Estrutura de Dados ObjetosHíbridos Imutabilidade Facilita a adição de novas funcionalidades Facilita a adição de novas classes Triângulo Perímetro
  • 88.
    Feature Envy noModelo de Figuras (Shape) 3.6 Objetos e E. de Dados
  • 89.
    Feature Envy +Efeitos Colaterais 3.6 Objetos e E. de Dados
  • 90.
    Lei de Demetersobre Objetos 3.6 Objetos e E. de Dados x = a.getB().getC().getD()x = a.b.c.d Train Wrecks (Acidente de Trem) a b c d NullPointer Exception (null) Estrutura de Dados Objetos - Imutabilidade - Proibição de “null” - Estados mutáveis - Possibilidade de “null” x = a?.b?.c?.d (Navegação Segura)
  • 91.
    Parte 3.7Parte 3.7 Tratamentode ErroTratamento de Erro
  • 92.
    Filosofia sobre Tratamentode Erro 3.7 Tratamento de Erros - Use exceções em vez de retornar códigos - Prefira exceções não verificadas (unchecked) - Forneça exceções com contexto e sem abafamento - Pense no design do “try-catch-finally” antes - Defina exceções pensando no chamador (e.g. Libs) - Cada “catch” faz apenas uma coisa - Não retorne nem passe “null” - Dê preferência às exceções já fornecidas (efective java)
  • 93.
    Código de ExceçãoRuim 3.7 Tratamento de Erros Problemas - Não retorna uma exceção - Abafa exceção do Gson - Retorna “null” - Imprime direto no console Consequências - Contrato baseado em “null” - Omissão do erro raiz (causa) - Força a testar nulidade: kotlin: ?. java: if (result != null) - Log inadequado e ineficiente
  • 94.
    Código de Exceçãocom Perda da Causa Raiz 3.7 Tratamento de Erros Problemas - Não retorna uma exceção - Abafa exceção do Gson - Retorna “null” - Imprime direto no console Consequências - Contrato baseado em “null” - Omissão do erro raiz (causa) - Força a testar nulidade: kotlin: ?. java: if (result != null) - Log inadequado e ineficiente
  • 95.
    Código Melhorado (Repassandoa Causa Raiz) 3.7 Tratamento de Erros O que acontece se “json” ou “clazz” forem nulos? Por que nunca se deve passar “null” como parâmetro?
  • 96.
    Código de TesteObtendo a Causa Raiz (Gson) 3.7 Tratamento de Erros
  • 97.
    Questão Sobre aCriação de Classes de Exceção 3.7 Tratamento de Erros Existe realmente a necessidade de criar a exceção “JsonException”? Não seria melhor usar as exceções prontas do Gson?
  • 98.
  • 99.
    Filosofia sobre Fronteiras3.8 Fronteiras - Código de terceiro quase sempre é “infraestrutura” - Infraestrutura deve ser isolada do negócio - Testes de aprendizado são uma boa dica
  • 100.
    Estudo de Casodo Parsing de Json 3.8 Fronteiras Necessidade Fazer parsing e serialização de Json em várias partes da aplicação Inicialmente usando o “Gson” Opcionalmente pode ser usado outra biblioteca como “Jackson” A infraestrutura deve ser isolada Domain ControllerController JsonParser Interface toJson() fromJson() JsonParser Interface toJson() fromJson() GsonParserGsonParser JacksonParserJacksonParser
  • 101.
    Estudo de Casodo Parsing de Json 3.8 Fronteiras Terceiros Infraestrutura Infraestrutura Aplicação API de Terceiros
  • 102.
    Estudo de Casodo Parsing de Json 3.8 Fronteiras GsonParserGsonParser JacksonParserJacksonParser
  • 103.
    Parser Baseado noGson 3.8 Fronteiras GsonParserGsonParser Encapsula o Gson É um JsonParser
  • 104.
    Injetando Dependência 3.8Fronteiras Criação manual Injeção de dependência Controller Parser Interface toJson() fromJson() GsonParser JacksonParser
  • 105.
    Teste de Aprendizadodo Gson 3.8 Fronteiras
  • 106.
    Parte 3.9Parte 3.9 Testesde UnidadeTestes de Unidade
  • 107.
    Filosofia sobre Testesde Unidade 3.9 Testes de Unidade - Teste de unidade dá feedback sobre o design - O feedback deve chegar o quanto antes - TDD é uma boa opção para tornar mais fácil - Testes de unidade são atividade de construção - Cobertura de testes provê confiança - Refatoração sem cobertura pode ser uma aventura - Teste também é código e deve ser limpo
  • 108.
    Cenário de Construçãocom TDD em 3 Iterações 3.9 Testes de Unidade Requisitos do Contador de Constantes 1. Criar uma função que conte todas as constantes inteiras de uma classe passada como parâmetro (atributos estáticos e “final”) 2. Parâmetro “null”, classes abstratas e enuns são ignorados e deve ser retornado “-1” como resultado da função 3. A contagem deve incluir todas as superclasses
  • 109.
    As 3 Regrasdo TDD 3.9 Testes de Unidade Refatora Falha Passa 1. Você não pode escrever nenhum código até ter escrito um teste que detecte uma possível falha. 2. Você não pode escrever mais testes de unidade do que o suficiente para detectar a falha – não compilar é não ter efeito. 3. Você não pode escrever mais código do que o suficiente para passar nos testes.
  • 110.
    TDD – Escrevera Primeira Versão do Teste e Falhar 3.9 Testes de Unidade Falha 1. Criar uma função que conte todas as constantes inteiras de uma classe (estáticos e “final”)
  • 111.
    TDD – Escrevero Código Real e Passar 3.9 Testes de Unidade Passa
  • 112.
    TDD – Refatoraro Código Real e Passar (Apenas Melhoria) 3.9 Testes de Unidade Passa Extração da lista Extração do método
  • 113.
    TDD – Refatoraro Teste para o Requisito 2 (Iteração 2) 3.9 Testes de Unidade 2. Classes abstratas e enuns são ignorados (retornar -1), inclusive “null” Refatora
  • 114.
    TDD – TesteRefatorado Vai Falhar 3.9 Testes de Unidade Falha Falha Aqui
  • 115.
    TDD – Ajustedo Código para Atender o Teste (Iteração 2) 3.9 Testes de Unidade Passa Adição do requisito 2
  • 116.
    TDD – Refatoraro Teste para o Requisito 3 (Iteração 3) 3.9 Testes de Unidade 3. A contagem deve incluir as superclasses Refatora
  • 117.
    TDD – TesteRefatorado Vai Falhar (Iteração 3) 3.9 Testes de Unidade Falha Tem 2 constantes Falha Aqui
  • 118.
    TDD – Ajustedo Código para Atender o Teste (Iteração 3) 3.9 Testes de Unidade Passa Adição do requisito 3
  • 119.
  • 120.
    Filosofia sobre Classes3.10 Classes - Classes devem ser pequenas - Devem ter somente uma responsabilidade (SRP) - Ter apenas um motivo para mudar - Devem ter coesão interna* * Poucas variáveis de instância * Cada método manipula uma variável ou mais - Devem encapsular seus dados ao máximo - Devem ter baixo acoplamento a outras classes
  • 121.
    Jogando “Pedra, Papele Tesoura” 3.10 Classes Requisitos do Melhor de 3 (Pedra, Papel e Tesoura) 1. Criar uma simulação de dois jogadores jogando “pedra, papel e tesoura” por um número variável de rodadas (3, 5 etc). 2. O jogo deve parar se um jogador já for o vencedor antes da última rodada (cenário de vitória antecipada). 3. Ao final deve ser indicado o vencedor (ou empate) e listados os resultados de todas as rodadas.
  • 122.
    Código Fornecido 3.10Classes Enum Mão: Possibilidades de escolha (Pedra, Papel ou Tesoura)
  • 123.
    Código Fornecido 3.10Classes Enum Resultado: Resultado em relação ao primeiro jogador: Perde: -1 Empata: 0 Vence: 1 Abstração de pedraPapelTesoura
  • 124.
    Código Fornecido 3.10Classes Enum ResultadoJogada: Resultados de um match (Primeiro Vence, Empate ou Segundo Vence)
  • 125.
    Implementação Procedural Simples3.10 Classes pedraPapelTesoura(char,char):int Problemas - Um método faz tudo - Muitos conceitos juntos: “Jogador”, “Match”, “Resultados” - “Rodadas” constantes - Nomes “hard coded” - Não pára em vitória antecipada Questões Como se livrar do código legado pedraPapelTesoura ? A solução é muito procedural? Como testar isso? 2 escolhas aleatórias
  • 126.
    Modelo Lógico: PossívelSolução OO 3.10 Classes Níveis de Abstração - O Jogo e os resultados - Uma Disputa entre jogadores - O resultado de uma disputa - Jogador com nome e escolha - A opção de jogada
  • 127.
    Modelo Lógico: Análisedos Conceitos do Jogo 3.10 Classes Inicialização e Contexto Conceito: 1 JogadorConceito: 1 Disputa Conceito: O Jogo em si Várias rodadas e resultado Código “Legado”: Lógica do jogo Conceito: Resultado de uma Disputa Abstração sobre -1,0,1 Opções do Jogo: R, P e S
  • 128.
    Implementação OO -Main 3.10 Classes Instanciação de dependências Inicialização em “jogar()” I/O = Efeito colateralI/O = Efeito colateral
  • 129.
    Classe MelhorDeTres 3.10Classes Responsabilidade: representa um jogo de “Pedra, Papel e Tesoura” com a definição do número de rodadas (3 por padrão) e armazena os resultados (estado) API - Executa o jogo (play) - Retorna se tem vencedor - Retorna o vencedor (se houver) - Retorna os resultados Delega para a classe Match o conhecimento sobre a disputa entre dois jogadores e seu resultado Indireção para Jogada Requisito número 2 Dependência será resolvida via construtor
  • 130.
    Classe JogadaLegada (ImplementaJogada) 3.10 Classes Representa uma disputa entre dois jogadores e seu resultado (imutável) API: Executa a disputa (play) e gera um resultado Delega para os jogadores a escolha da “mão” que será jogada. Delega para a função rockPaperScissors a lógica de quem venceu a disputa com base nestas escolhas
  • 131.
    Classe Jogador 3.10Classes Representa um jogador que deve fazer uma escolha de qual mão usar na disputa Delega para Mao a escolha de forma aleatória, mas encapsula esta decisão O jogador poderia ser criado com a escolha já feita anteriormente
  • 132.
    Solução OO xProcedural 3.10 Classes A solução OO tem mais código, mas cada parte é mais fácil de entender que o todo Permite testes de unidade por classe Cada abstração está em uma classe Cada classe tem uma responsabilidade A necessidade de manutenção tende a impactar somente uma parte do código
  • 133.
    Refatoração: Livrando-se doCódigo Legado 3.10 Classes Como remover pedraPapelTesoura? Qual classe deve conhecer esta regra de quem vence quem? Como implementar a regra de forma a gerar o menor impacto possível? Qual seria o impacto de alterar e testar na solução procedural?
  • 134.
    Especificação da Regra“Pedra/Papel/Tesoura” Legada 3.10 Classes
  • 135.
    Especificação da Regra“Pedra/Papel/Tesoura” OO 3.10 Classes
  • 136.
    Responsabilidade da Classe“Mao” 3.10 Classes Código expressivo sobre a regra do jogo Função (API) que externaliza a regra
  • 137.
    Impacto: Nova ClasseImplementando “Jogada” 3.10 Classes Implementação alternativa de “Jogada” livre do código legado O método “jogar” expressa o negócio de forma simples e elegante Função (API) que externaliza a regra
  • 138.
    JogadaLegada x JogadaSimples(Nova) 3.10 Classes - Mais semântico e claro - Dispensa o enum “Resultado” - Delega para o método “vence” de uma outra classe (“Mao”) Kotlin infix
  • 139.
    Impacto da Refatoraçãona Classe “Main” 3.10 Classes Criação da classe “JogadaSimples” (Troca de “JogadaLegada” por “JogadaSimples”) A classe “MelhorDeTres” não teve nenhum impacto e ainda recebe a dependência Responsabilidades: - Criar Jogadores - Criar Jogada - Inicializar o Jogo ... - Conexão de Banco ? - I/O, Integrações ?
  • 140.
  • 141.
    Filosofia sobre Testesde Unidade 3.11 Sistemas Complexos - Sistemas precisam de separação de preocupações - Separe a inicialização do uso de um sistema - Sistemas beneficiam-se do uso de uma DSL
  • 142.
    Modularização e Separaçãode Preocupações 3.11 Sistemas Complexos - Criação de objetos e escopos superiores - Conexão com BD, I/O e efeitos colaterais DDD e Preocupações Transversais Main main() Negocio Módulo A Domain Service Módulo B Função X1 Classe X Função X2 Função X3 Factory Create Módulo C Função Y1 Classe Y Função Y2 Função Y3 Repository Save Log Segurança BD I/O
  • 143.
    Inicialização e Contexto Conceito:1 JogadorConceito: 1 Disputa Conceito: O Jogo em si Várias rodadas e resultado Código “Legado”: Lógica do jogo Conceito: Resultado de uma Disputa Abstração sobre -1,0,1 Opções do Jogo: R, P e S Separe a Construção do Uso no Sistema 3.11 Sistemas Complexos As demais classes não devem conhecer sobre contexto e inicialização Devem ser projetadas como se isso fosse ser resolvido para elas… E será! Main conhece o sistema Sistema ignora o Main Função pura ignora tudo fora do seu escopo
  • 144.
    Injeção de DependênciaVia Construtor 3.11 Sistemas Complexos O uso de CDI com @inject faz o mesmo trabalho automaticamente Injeção de dependência minimiza o acoplamento entre classes além de facilitar os testes de unidade
  • 145.
    DSL – DomainSpecific Language 3.11 Sistemas Complexos DSL: Código Expressivo DSL encapsula a lógica Main main() Negocio Módulo A Domain Service Módulo B Função X1 Classe X Função X2 Função X3 Factory Create Módulo C Função Y1 Classe Y Função Y2 Função Y3 Repository Save Classes e Funções são negócio destilado O domínio do problema é descrito na solução
  • 146.
  • 147.
    Filosofia sobre Simplicidade3.12 Simplicidade - Todos os testes devem passar (deve haver testes) - Nenhuma duplicação de código ou configuração - O código deve expressar o negócio e sua intenção - A solução deve usar o mínimo de elementos - Simples não é Simplório (pelo contrário) - Simplicidade é a sofisticação máxima
  • 148.
    As 4 Regrasda Simplicidade 3.12 Simplicidade Testes Tempestivos Refatoração Tempestiva https://martinfowler.com/bliki/BeckDesignRules.html
  • 149.
    Regra 1 deProjeto Simples: Efetue Todos os Testes 3.12 Simplicidade 1 2 3 Teste 1: Afere se a regra entre as opções está funcionando: Pedra vence Tesoura, Tesoura vence Papel e Papel vence Pedra Teste 2: Afere se o SmartMatch retorna o resultado certo dado que já se sabe o que os jogadores vão escolher (mock) Teste 3: Afere que, de 7 rodadas, irá parar na quarta com 4 vitórias de “Bob”
  • 150.
    Regras de 2a 4 de Projeto Simples: Refatoração 3.12 Simplicidade Conceitos - O Jogo e os resultados - Uma Disputa entre jogadores - O resultado de uma disputa - Jogador com nome e escolha - A opção de jogada DSL: Código Expressivo A: Reúso B: Refactoring Regra 1 conceito p/ classe
  • 151.
    já sei cleancode? técnicatécnica, treino e tempo, treino e tempo abordagem de atuação profissional não é sobre códigonão é sobre código é sobreé sobre fazer códigofazer código
  • 152.
  • 153.
    Laboratório de Refatoração4 Refatoração treinotreino github.com/refactown/lab
  • 154.
    REFERÊNCIAS BECK, Kent. Padrõesde Implementação. Porto Alegre, Bookman, 2013. EVANS, E. Domain-Driven Design – Atacando as complexidades no coração do software. 2a edição, Rio de Janeiro, Alta Books, 2010. FOWLER, Martin. BeckDesignRules, https://martinfowler.com/bliki/BeckDesignRules.html FOWLER, Martin. TellDontAsk, https://martinfowler.com/bliki/TellDontAsk.html HUNT, Andrew; THOMAS, David, O Programador Pragmático, Bookman, 2010 MARTIN, Robert, O Codificador Limpo, Alta Books, Rio de Janeiro 2012 MARTIN, Robert, Código Limpo, Alta Books, Rio de Janeiro 2011
  • 155.
    Programação Funcional XOrientação a Objetos 155/155 1 42 3 5 Prática para encerrar... Obrigado! Douglas Siviotti douglas.siviotti@gmail.com github.com/siviotti Teoria