Você está na página 1de 13

1

Clean Code - Desenvolvimento com qualidade


Fique por dentro
Este artigo til porque fornece algumas propostas para um melhor uso da orientao a objetos, a fim de
que seja possvel deixar o cdigo menos acoplado, mais inteligente e limpo.
Tambm buscaremos apresentar aspectos dos modelos anmico e de domnio, mostrando as principais
diferenas na hora de optar por um deles.
A mxima popular afirma que para bom entendedor, meia palavra basta. Seguramente tambm poderamos
utiliz-la na nossa profisso e afirmar: para um bom programador, meio cdigo basta. Quando o cdigo
bem escrito, qualquer programador pode compreend-lo sem grandes dificuldades e entende rapidamente a
real funo da implementao em questo.
Como diria Martin Fowler, qualquer um pode escrever um cdigo que o computador entenda. Bons
programadores escrevem cdigos que os humanos entendem. Este o verdadeiro desafio do desenvolvedor.
Neste contexto, o objetivo deste artigo, como o prprio ttulo sugere, propor aspectos que tornem o cdigo
mais claro, de modo que ele possa ser compreendido com facilidade por outros profissionais.
Para a criao de um cdigo limpo nos termos de Robert C. Martin, torna-se necessrio seguir algumas
regras bsicas. Segundo este autor, a possibilidade de um fcil entendimento e manuteno decorre do
cumprimento de determinadas regras.
Existe uma significativa literatura referente ao tema cdigo limpo. Neste artigo faremos comentrios sobre o
que o cdigo limpo e como alcan-lo, atravs de um breve resumo baseado no livro Clean Code, de
Robert C. Martin.
Neste livro, so descritas regras que definem, por exemplo, a nomenclatura adequada para classes, mtodos
e atributos, o correto uso dos comentrios, a melhor formatao do cdigo, o tratamento de erros e at
mesmo testes unitrios.
Martin, mais conhecido como Uncle Bob, um grande nome na comunidade de desenvolvimento de
software, trabalhando na rea desde 1970. Fundador e presidente da Object Mentor Inc, um dos 17
membros do Manifesto gil e publicou diversos artigos e livros sobre o assunto.
Contudo, no adianta apenas ter um cdigo limpo e bem escrito, se o mesmo for aplicado a um modelo de
domnio mal estruturado. Para resolver este problema sero abordadas as diferenas entre o modelo anmico
e o modelo de domnio.
Estes modelos so tipos de padres que o programador poder utilizar para o desenvolvimento das
funcionalidades de seu respectivo projeto. Apesar disso, atualmente o modelo anmico considerado um
anti-pattern, ou seja, ele um anti-padro. Como curiosidade, a maioria dos profissionais ainda insiste em
utiliz-lo.
Com base nisso, neste artigo procuraremos expor algumas razes que confirmem as limitaes deste
modelo, e como alternativa, apresentaremos o modelo de domnio (domain model), que consiste numa viso
e numa tcnica para lidar tanto com os casos de domnios mais simples at os altamente complexos.
Para a definio correta do domnio, teremos como base o uso da prtica do DDD, tcnica criada por Eric
Evans, autor do livro Domain-Driven Design e um lder nos estudos sobre design de software e modelagem
2

de domnio. Assim, sero propostas algumas sugestes para que o desenvolvedor possa criar cdigos claros,
eficazes e de fcil compreenso para outros desenvolvedores.
Como anda o seu cdigo?
Em primeiro lugar, devemos ter, de forma clara, a ideia do que se entende por cdigo limpo (ver BOX 1). O
cdigo limpo no deve ser apenas desejvel devido sua organizao, mas tambm pela facilidade com que
outros profissionais podero futuramente manuse-lo.
Quando um cdigo no est bom, ele s tende a piorar com o decorrer do tempo, pois o desenvolvedor que
tiver de fazer alguma manuteno, possivelmente no o far com tanta organizao porque encontrou o
trabalho inicial j desestruturado. como o exemplo do carro com um dos vidros quebrados.
BOX 1. Cdigo Limpo
Segundo Kent Beck, um dos integrantes do Manifesto gil, Cdigo Limpo (Clean Code), de forma
resumida, o cdigo fcil de entender, fcil de modificar e fcil de testar.
Foi realizada uma experincia nos Estados Unidos que consistia em deixar um carro trancado e com apenas
uma das janelas quebradas numa esquina. Aps alguns dias, o mesmo j possua mais janelas quebradas. Ao
longo de mais algumas semanas, o carro j estava todo amassado e depenado.
Para comparao, outro carro foi deixado no mesmo local, s que dessa vez sem problema algum. Este
automvel permaneceu assim por semanas e ao final da experincia, nenhum dano lhe foi causado.
Com este exemplo queremos dizer que as pessoas tm zelo por aquilo que est arrumado, que est sob bons
cuidados. O mesmo acontece com o cdigo.
Quando o desenvolvedor escreve-o de qualquer forma, ou seja, sem nenhum padro, os outros profissionais
que posteriormente manusearem seu cdigo iro danific-lo ainda mais. Em outras palavras, o profissional
tende a perpetuar uma desestruturao j existente.
Um cdigo limpo aquele que segue determinados padres e regras de implementao, desde a escolha do
nome da classe, atributos e mtodos, at o uso correto da orientao a objetos. Para exemplificar esses
padres e regras, apresentaremos sub tpicos que explicam de forma breve as etapas para tornar o cdigo
eficaz e limpo.
Nomes que fazem sentido
Os nomes que fazem sentido so os nomes pronunciveis. A nomenclatura dada aos atributos, mtodos e
classes deve ser autoexplicativa, ou seja, deve esclarecer sua real funo de imediato. Portanto, no
economize nas palavras e evite abreviaes. Veja dois exemplos na Listagem 1.
Listagem 1. Evite abreviaturas. No poupe as palavras.
public class Aluno {

//COM ABREVIAO
private String cadMatAluno() {
//implementao
}

//SEM ABREVIAO O mais indicado
private String cadastrarMatriculaDoAluno() {
//implementao
3

}
}
Como indicado no exemplo, os nomes devem refletir exatamente o significado da funo do mtodo. Deste
modo, defina-os de forma objetiva e clara, de modo que a leitura seja simplificada. Alm disso, evite as
chamadas notaes hngaras, que ocorrem quando o tipo do objeto vem junto do nome (ex: listaDisso ou
mapaDaquilo).
A nomenclatura das classes deve ser elaborada a partir de substantivos e no deve conter verbos.
Diferentemente dos nomes dos mtodos, que devem sim possuir verbos, pois representam uma determinada
ao.
Classes e mtodos
Tanto as classes quanto os mtodos devem ter o menor tamanho possvel. Quanto menores eles forem, mais
fcil se tornar o seu entendimento. No prprio livro Clean Code existem algumas normas voltadas aos
mtodos informando que estes devem ter no mximo vinte linhas e cada linha de cdigo precisa ter no
mximo cem caracteres, ao passo que a classe deve possuir entre duzentas e quinhentas linhas.
No entanto, se o desenvolvedor tiver uma classe com 550 linhas, ou seja, se ele exceder 50 linhas, no
preciso reescrever todo o seu cdigo. O fato de ter ultrapassado um pouco no significa que o profissional
tenha que alterar toda a sua implementao para restringir-se s quinhentas linhas. Para isso existe o bom
senso.
Tambm importante que mtodos e classes tenham apenas uma funo. Esta norma chama-se princpio da
responsabilidade nica ou, no ingls, Single Responsibility Principle. Dessa forma o entendimento torna-se
muito mais rpido e preciso.
Uma sugesto para detectar essa responsabilidade nica identificar se determinado trecho de cdigo est
realizando uma funo diferente alm da proposta. O trecho de cdigo que realiza outra tarefa deve ser
movido para um novo mtodo.
Alm disso, busque evitar os mtodos que recebem parmetros demais. Mtodos com muitos parmetros
acabam por se tornar confusos. A passagem de muitos parmetros indica justamente que o seu mtodo est
realizando coisas demais.
E se for este o caso, os mtodos devem possuir uma justificativa plausvel. importante entender que
quando falamos em cdigo limpo, deve-se ter em mente a ideia de que Menos sempre Mais.
Outra sugesto seguir a norma do DRY Dont Repeat Yourself, que no portugus significa No repita a
si mesmo. Sendo assim, preste muita ateno repetio de cdigo. Evite a duplicidade reaproveitando os
seus mtodos.
Ademais, necessrio prestar ateno no grau de coeso das classes. Como informado anteriormente, menos
pode significar mais. Dessa forma, nossas classes devem fazer apenas a funo descrita em seu nome.
Um exemplo disso seria uma suposta classe Imprime, criada com o simples objetivo de imprimir. Portanto,
ela deveria executar apenas esta funo, no precisando se preocupar em estabelecer conexo com o banco
de dados, salvar os arquivos ou verificar se o usurio tem permisso de acesso.
Quando uma classe possui mais responsabilidades, alm da que ela se prope, ela se mostra claramente
incoerente, pois cada classe deve cumprir uma nica responsabilidade.
Comentrios
4

Evite o mximo possvel fazer comentrios. Se partirmos do princpio explicado anteriormente, j podemos
eliminar alguns tipos desnecessrios de comentrios, pois teremos seguido todas as regras para a
nomenclatura de nossas classes e mtodos.
Sendo assim, um comentrio com o propsito de explicar a funo de um mtodo se torna desnecessrio.
No entanto, e se o projeto for um legado no qual se est realizando apenas uma manuteno, podemos inserir
novos comentrios? De forma alguma. Devemos apenas verificar se os comentrios que j existem ainda
fazem sentido em relao ao cdigo do mtodo. Caso contrrio, preciso alter-los, deixando-os coerentes
com o cdigo novamente.
Quando for necessrio realizar manutenes no cdigo de um projeto antigo, nunca se esquea de alterar
tambm o comentrio do mtodo, caso eles existam.
Ao lermos um comentrio, o correto seria no precisarmos olhar para o restante do cdigo para entend-lo.
Caso precisemos voltar ao cdigo depois de ver o comentrio, ento este ltimo precisa ser alterado. Como
diria o prprio Uncle Bob: Qualquer comentrio que faa voc olhar para outras partes do cdigo para
entend-lo, no vale nem os bits que ele consome.
Porm, h situaes em que os comentrios so necessrios. Eles podem ser teis em casos como, por
exemplo, no aviso de consequncias que um trecho de cdigo possa vir a causar. Como uma lentido
causada no banco de dados e a recomendao de que se faa uma alterao da procedure usada.
Ou seja, o comentrio deve mostrar a real inteno por trs de uma deciso tomada, pois ocasionalmente fica
difcil mostrar apenas com o nome do mtodo o porqu daquele cdigo ter sido feito de uma determinada
maneira. Enfim, so raros os casos em que o comentrio pode vir a ser necessrio de fato. O ideal
evitarmos a sua utilizao.
Existem tambm os trechos de cdigo comentados. No entanto, um trecho de cdigo comentado deve ser
algo deixado ali apenas por um breve momento, s servindo como uma rpida referncia. Se o mesmo j no
tem nenhuma utilidade, apague-o sem medo, pois os controles de verso existem para isso, resgatar uma
verso anterior para que possa ser novamente utilizada.
Formatao
A formatao do cdigo muito importante porque uma das formas como ns, desenvolvedores, nos
comunicamos uns com os outros. A partir dela outros desenvolvedores podero olhar para o cdigo e
entend-lo com mais facilidade. Ela , portanto, componente fundamental para a comunicao.
A ordem dos mtodos outro fator essencial. Mtodos com conceitos relacionados devem ficar
verticalmente prximos. Assim, criado um fluxo de leitura que melhora a legibilidade do cdigo.
Outro fator importante o cuidado com a indentao do seu cdigo. Esta no deve possuir mais do que dois
nveis, como o caso dos ifs mostrados na Listagem 2, que chegam a ter um terceiro nvel. Caso isso
ocorra, deve-se extrair o terceiro nvel para outro mtodo.
Listagem 2. Ateno indentao. Observe o erro comum na estruturao dos ifs.
if(situacao == 1) {
if(situacao == 2) {
if(situacao == 3) {

}
}
5

}
preciso cuidado tambm com relao aos espaamentos dados no cdigo. O espaamento correto entre os
operadores, parmetros e vrgulas fazem uma grande diferena no momento da leitura e da compreenso do
que foi codificado. Podemos ver um simples exemplo das duas percepes na Listagem 3.
Listagem 3. Observe o uso correto do espaamento.
//SEM ESPAAMENTO
public class CalculaDesconto {

public void caucula(Integer val1,Integer val2){
Integer resultado=val1+val2;
System.out.println(O resultado :+resultado);
}
}

//COM ESPAAMENTO
public class CalculaDesconto {

public void caucula(Integer val1, Integer val2) {
Integer resultado = val1 + val2;
System.out.println(O resultado : + resultado);
}
}
Tratamento de erros
O tratamento de erros de suma responsabilidade do desenvolvedor. As coisas podem sempre dar errado e
nosso dever garantir que o nosso cdigo possua o correto tratamento para cada situao.
Neste contexto, importante que o desenvolvedor d prioridade ao uso de excees, em vez de apenas
retornar cdigos de erro. O uso de cdigos de erro pode causar certa confuso, pois o mtodo que invocou
determinada funcionalidade acaba tendo que se preocupar em tratar esses cdigos retornados e esse processo
pode ser facilmente esquecido.
As excees devem indicar a localizao exata de um erro. Portanto, ao lanar uma exceo, use mensagens
que realmente informem o erro ocorrido, mencione o que de fato aconteceu, o que estava tentando fazer e o
porqu do erro.
Alm disso, evite usar excees para regras de negcio. Sempre use-as para os erros inesperados, como
NumberFormatException. Para os tratamentos de erros de negcio, no devemos criar excees conforme
o caso mostrado no exemplo da Listagem 4, pois so situaes especficas e difceis de serem previstas.
Nestas situaes, devemos preferir o uso de ifs, pois torna o nosso cdigo mais organizado e de melhorar
manuteno, como podemos constatar na Listagem 5.
Listagem 4. Cuidado com o mau uso das excees.
Despesas despesasComFestas = new Despesas();
try {
despesasComFestas = despesasDao.getFestas();
resultado += despesasComFestas.getSoma();
}
catch (DespesasComFestasNotFoundException e) {
resultado += despesasComFestas.getSomaParcial();
}
6

Listagem 5. O correto uso de ifs para o tratamento de erros de negcio.
Despesas despesasComFestas = new Despesas();
despesasComFestas = despesasDao.getFestas();

if(despesasComFestas.getSoma() != 0) {
resultado += despesasComFestas.getSoma();
}
else {
resultado += despesasComFestas.getSomaParcial();
}
Outro fato importante que tambm deve ser observado quanto ao tratamento de erros o de nunca
retornamos null nos nossos mtodos, pois fatalmente poderemos causar uma exceo de
NullPointerException. Tal exceo ocorre devido a um simples esquecimento, que seria o de tratar o trecho
de cdigo com o if (qualquerObjeto != null).
Mas o tratamento com o uso do if causa uma enorme duplicao de cdigo, devido grande quantidade de
lugares nos quais teramos que repetir esse mesmo procedimento. Em vez disso, podemos optar por usar um
pattern conhecido como Special Case Objects, que um padro responsvel por criar objetos especiais
justamente para atender a essa necessidade.
Esse pattern consiste na criao de um objeto do mesmo tipo da interface, com mtodos que retornem
qualquer valor padro, como vazio para um atributo do tipo String e zero para um atributo do tipo Integer.
Um exemplo pode ser visto no cenrio da Listagem 6.
Nesta listagem uma classe denominada NullEmpregado, do mesmo tipo da interface Empregado, criada
com mtodos que retornaro valores padres ao invs de retornar null.
Listagem 6. Usando o pattern Special Case Object.
public interface Empregado {

String nome();
String sobrenome();

}

//Nosso objeto especial
public class NullEmpregado implements Empregado {

private static final String VALOR_PADRAO = ;

@Override
public String getNome() {
return VALOR_PADRAO;
}

@Override
public String getSobrenome() {
return VALOR_PADRAO;
}

}

public class Diretor implements Empregado {

@Override
public String getNome() {
return Pedro;
7

}

@Override
public String getSobrenome() {
return Otvio;
}
}

public class Funcionario implements Empregado {

@Override
public String getNome() {
return joao;
}

@Override
public String getSobrenome() {
return Augusto;
}
}

//Nossa classe de testes
public final class Escritorio {

Empregado empregado = new NullEmpregado();

public Escritorio() {}

public Escritorio(Empregado empregado) {
this.empregado = empregado;
}

public String imprimirNomeCompletoDoFuncionario() {
return empregado.nome() + " " + empregado.sobrenome();
}

public static void main(String[] args) {
//Aqui o novo objeto no foi passado, o que nos retornaria NullPointerException,
//mas com o uso do special case object isso no acontece.
Escritorio escritorio = new Escritorio();
System.out.println(escritorio.imprimirNomeCompletoDoFuncionario());

escritorio = new Escritorio(new Funcionario());

escritorio = new Escritorio(new Diretor());
System.out.println(escritorio.imprimirNomeCompletoDoFuncionario());
}
}
Neste exemplo da classe Escritorio podemos ver que ela tambm foi instanciada tendo um construtor vazio.
Isso certamente acarretaria em NullPointerException na execuo do mtodo
imprimirNomeCompletoDoFuncionario(), pois o mesmo necessita de informaes oriundas de um
Empregado. Contudo, essa exceo no ocorre porque Empregado j foi inicializado antes, com a classe
NullEmpregado, garantindo assim o retorno de seus mtodos nome() e sobrenome() com o valor vazio, ao
invs de null.
Testes unitrios (TDD)
Um Desenvolvedor que no faz testes como um cirurgio que no lava as mos (Robert C. Martin).
Testes unitrios so os responsveis pela garantia do seu trabalho e da lgica que foi implementada no
cdigo.
8

O TDD (Test Driven Development) uma das prticas mais conhecidas para a escrita de testes unitrios.
Com ele, escrevemos nosso cdigo guiado pelos testes, ou seja, comeamos pelos testes da funcionalidade
antes da sua codificao de fato. Assim, nosso cdigo j validado antes mesmo de sua escrita.
Existem trs leis sobre o TDD, definidas por Uncle Bob, que servem como guia durante o processo de
desenvolvimento. So elas:
1. No se pode comear a escrever o cdigo de produo at que se tenha criado um teste que apresente erro;
ou seja, devemos sempre criar o teste primeiro;
2. No se pode escrever mais testes do que sejam necessrios para testar a condio do erro. preciso
preocupar-se em criar o mnimo de testes, desenvolvendo apenas o suficiente para testar a condio de erro;
3. No se pode escrever mais cdigo de produo do que o suficiente para compilar o teste unitrio que
apresentava erro.
Robert C. Martin, no livro Clean Code, tambm recomenda o uso de cinco regras para realizao dos testes
unitrios. A juno da primeira letra de cada um desses conselhos forma o acrnimo FIRST, que significa:
Fast Os testes devem ser rpidos. Quando os testes so lentos, certamente o desenvolvedor no vai
querer execut-los com frequncia. Deste modo, deixamos de encontrar os problemas logo no incio da
codificao, o que permitiria solucion-los de forma mais rpida e fcil;
Independent Os testes no devem depender uns dos outros, ou seja, o resultado de um teste no deve ser
condio para a execuo do prximo teste. Eles precisam ser executados de forma independente e em
qualquer ordem.
Quando um teste depende do outro, o primeiro que falhar causar uma reao em cadeia, fazendo com que
todos os outros testes abaixo na hierarquia produzam erro, dificultando diagnsticos e escondendo outros
defeitos;
Repeatable Os testes precisam estar aptos a serem executados repetidas vezes sem nenhuma interveno.
Eles no podem depender de nenhum servio ou recurso externo que poder estar indisponvel em
determinado momento.
A execuo dos testes deve sempre apresentar o mesmo resultado, no importando o ambiente em que sua
aplicao esteja rodando, seja no ambiente de desenvolvimento ou no ambiente de produo;
Self-validating Os testes devem ter uma sada, uma resposta booleana, no importando se o retorno do
mesmo indicou sucesso ou erro. No devemos depender de agentes externos para validar os nossos testes,
como por exemplo, um arquivo de log. A resposta precisa ser imediata, ou verdadeiro ou falso;
Timely O teste deve ser criado antes do cdigo da funo a ser testada. Quando optamos por criar vrias
funes sem os devidos testes, fica muito mais difcil lembrar depois os testes que devem ser
implementados.
Alm disso, o desenvolvedor poder vir a optar por criar um super teste, abrangendo todas as regras dessas
funes passadas, e isso certamente ir acarretar em uma lentido na hora de sua execuo. Outro problema
a grande dificuldade na hora de realizar a manuteno nesses testes, pois cada vez que determinada funo
inserida nele for alterada, precisaremos encontrar nesse super teste o ponto exato de verificao da funo
em questo.
9

Por fim, importante ter em mente o fato de que, ao alterarmos um cdigo, devemos nos lembrar de tambm
alterar o seu teste.
Modelo Anmico x Modelo de Domnio
Uma modelagem orientada a objetos visa ser uma representao fiel do mundo real. Essa representao se
d atravs do uso de classes que devem ter seus estados e comportamentos bem definidos. Numa abordagem
tcnica, dizemos que as classes (objetos) devem possuir propriedades, definindo o seu estado e mtodos, que
implementam seu comportamento.
Partindo da ideia do que a orientao a objetos, apresentaremos motivos para a no utilizao da
modelagem anmica, visto que a mesma fere, por exemplo, o uso do encapsulamento no momento em que as
suas classes de domnio so criadas apenas como um aglomerado de mtodos Getters e Setters sem uso real,
servindo apenas como mtodos assessores para nossos atributos.
Essas classes no possuem estado ou comportamento, indo justamente na contramo do que prega a
orientao a objetos.
Para a correta modelagem de nosso domnio, devemos considerar o uso do DDD (Domain-Driven Design),
que prega a ideia de que classes de domnio devem possuir suas regras de negcio dentro delas mesmas,
adquirindo assim estado e comportamento. Com isso, encapsulamos verdadeiramente a nossa
implementao, podendo alter-la sem prejudicar outras classes que a utilizem.
Os problemas com o uso do Modelo Anmico
Quando pensamos em orientao a objetos, nos vem rapidamente a ideia de classes que representem o
comportamento e estado de objetos do mundo real, como por exemplo, uma classe do tipo Carro, que
possui o mtodo andar().
Outro conceito fundamental da orientao a objetos o do encapsulamento. Ele indica que no devemos
expor os detalhes de implementao de nossos objetos.
Isto , as demais classes no precisam saber como o procedimento de andar, mas apenas utilizar tal
comportamento. Quando encapsulamos determinada implementao, podemos facilmente alter-la e com
isso no interferir em outras classes, pois no existir outro cdigo que dependa diretamente desses detalhes.
Ento, diante do que se sabe sobre uma boa modelagem de objetos, fato que toda nossa implementao
deveria partir desses princpios, mas infelizmente no assim que acontece na prtica. Quando optamos pelo
uso do modelo anmico, deixamos de lado as boas prticas da orientao a objetos porque os objetos do
domnio nele criados no possuem qualquer comportamento.
Assim, a nossa classe Carro deixa de ser a responsvel pelo comportamento de andar, passando essa funo
para uma classe intermediria. Por esse motivo o modelo anmico hoje considerado um anti-pattern.
Em um modelo desse tipo, getters e setters gerados a partir dos atributos declarados como privados dentro
das classes de domnio no passam apenas de mtodos pblicos chamados de assessores, onde sua nica
funo fornecer acesso a esses mesmos atributos privados. Na internet encontramos facilmente vasto
material para iniciantes no desenvolvimento Java que disseminam o equivocado ensinamento de indicar que
precisamos criar mtodos assessores para trabalhar com esses atributos, como podemos ver no exemplo da
Listagem 7.
Listagem 7. Criando os mtodos assessores, getters e setters no modelo anmico.
10

public class Salario {

private double liquido;
private double bruto;

public double getLiquido() {
return liquido;
}

public void setLiquido(double liquido) {
this.liquido = liquido;
}

public double getBruto() {
return bruto;
}

public void setBruto(double bruto) {
this.bruto = bruto;
}
}
A classe Salario possui mtodos que ferem a ideia do encapsulamento, como por exemplo, o setLiquido(),
que nos permite o acesso direto ao atributo liquido, alterando o seu valor a qualquer momento na
implementao. Nesse caso no interessante que o nosso atributo seja alterado de forma direta, j que para
se obter o salrio lquido, alguns clculos de desconto so necessrios, como o caso do INSS e o IRPF.
importante no criar um getter ou um setter sem necessidade. Ao implementar qualquer mtodo em uma
classe, a sua funo precisa ser clara e objetiva. Os getters e setters, quando criados, por diversas vezes no
so invocados, e grande parte daqueles que esto sendo utilizados poderia ser substituda por mtodos de
negcio do prprio domnio.
Essa prtica de cri-los para todos os atributos declarados como privados nas classes de domnio vem do
incio da AWT, quando era recomendado criar getters e setters para serem invocados no preenchimento dos
campos visuais da interface grfica com o usurio. Essa prtica deu origem ao termo JavaBean, que uma
classe com atributos privados que so acessados por mtodos pblicos.
Quando se permite esse tipo de prtica, trechos como salario.setLiquido(salario.getBruto()
(salario.getBruto() * 0,15)) sero encontrados ao longo de toda a aplicao.
E se por acaso o clculo mudar, teremos que procur-lo e alter-lo por todo o nosso cdigo. Uma alternativa
para contornar esse problema seria criar uma classe que ficasse responsvel pela lgica do clculo, como o
exemplo da classe ContraCheque, que pode ser vista na Listagem 8.
Listagem 8. Classe intermediria responsvel pelo negcio referente ao clculo do Salrio.
public class ContraCheque {

public double calcularSalario(Salario salario, double desconto) {
if(salario == null) {
throw new InvalidArgumentException(salario no informado!);
}
if(desconto == null) {
throw new InvalidArgumentException(desconto no informado!);
}
return salario.getBruto() (salario.getBruto() * desconto);
}
}
11

No entanto, essa soluo ainda mostra outros problemas, pois a classe ContraCheque apresenta-se de forma
procedural, isto , possui validaes executadas em sequncia dentro do mesmo mtodo que realizar o
clculo, ao invs de estarem em mtodos especficos.
Lembre-se, devemos sempre separar as responsabilidades. E o que temos neste caso so procedimentos
diferentes sendo realizados juntos (validaes e regra de negcio). Alm disso, a classe tambm possui uma
forte ligao com a classe Salario, conhecendo demais a sua implementao.
Isto se d a partir do momento em que a classe Salario disponibilizada como parmetro, dando assim
acesso a todos os seus mtodos pblicos. Quando uma classe de domnio invocada dessa forma, a quebra
do encapsulamento pode ser claramente notada, pois comportamentos e estados da classe passam a ser
acessados de forma direta.
O ideal nesse caso deixar de pedir em excesso o valor dos atributos, como faz o mtodo getBruto(), que
serve apenas para trazer o valor do atributo bruto e a partir desse valor, realizar o clculo do salrio lquido.
Portanto, importante definir claramente o que o objeto deve fazer, para que ele internamente seja
responsvel pelas suas prprias regras de negcio (como por exemplo, pagar o salrio lquido). Este
justamente o princpio do Tell, dont ask (Diga, no pea).
Como este princpio no foi aplicado classe Salario, esta simplesmente parece no ter qualquer
responsabilidade no sistema. Sem estado ou comportamento, ela se mostra como um fantoche, com mtodos
sets e gets que servem apenas para fornecer e recuperar as informaes da classe.
Para dar alguma ao ao domnio Salario, foi necessria outra classe, a ContraCheque. Devido a isso,
qualquer alterao no domnio tambm ir acarretar modificaes na classe ContraCheque, porque ela
conhece muitos detalhes da implementao de Salario.
Na modelagem anmica dito que no devemos colocar qualquer lgica de negcio nos objetos de domnio.
Contudo, o ideal exatamente o contrrio. Por que no deixar que cada objeto de domnio fique responsvel
pelas suas prprias regras de negcio, unindo assim a lgica de negcio aos dados? Dessa forma
eliminaramos os mtodos que apenas acessam e modificam diretamente os atributos.
O fato que lgica de negcio e dados podem ser unidos de uma maneira simples, fazendo com que a classe
de domnio passe a ter seus prprios mtodos de negcio, como mostrado na Listagem 9. Assim, tambm
podemos remover os mtodos desnecessrios que apenas acessam e alteram o estado da classe de forma
direta.
Listagem 9. Atribuindo responsabilidade ao domnio Salario na viso do modelo de domnio.
public class Salario {

private double bruto;
private double liquido;
private double desconto;

public Salario(double bruto, double desconto) {
this.bruto = bruto;
this.desconto = desconto;
}

private void validarAtributos() {
if(this.bruto == null) {
throw new InvalidArgumentException(valor bruto no informado!);
}
if(this.desconto == null) {
12

throw new InvalidArgumentException(desconto no informado!);
}
}

private void calcularSalario() {
validarParametros();

this.liquido = this.bruto (this.bruto * desconto);
}

public double getLiquido() {
calcularSalario();

return this.liquido;
}
}
Como pode ser observado, o mtodo getLiquido() foi mantido, pois este faz parte do domnio e retorna o
valor do salrio lquido j calculado. Quanto ao mtodo calcularSalario(), ele ficou responsvel apenas por
realizar a regra de negcio. A validao dos atributos foi removida para outro mtodo, o validarAtributos().
Desse modo, temos as responsabilidades definidas de forma correta e qualquer alterao feita no clculo do
salrio lquido, como por exemplo, a incluso de um novo desconto, no causar quaisquer alteraes numa
outra classe que se utilize de getLiquido(). No momento em que a classe de domnio passa a ter seus
prprios mtodos de negcio, ela deixa de ser uma mera estrutura de dados com Getters e Setters.
Quando falamos em definio das responsabilidades, precisamos ressaltar que a mesma deve ser pertinente
ao domnio. Tambm importante enfatizar que o comportamento dentro dos objetos de domnio no deve
contrariar a ideia da separao em camadas do projeto, abordagem tradicionalmente pregada pelo MVC
(Model-View-Controller). Sendo assim, domnio e lgica devem ficar restritos camada de modelo.
O uso do DDD (Domain-Driven Design)
Todo sistema nasce com o objetivo de resolver questes que envolvam determinado problema do mundo
real. Para esse problema que ser resolvido com a implementao do nosso sistema, damos o nome de
Domnio.
Para uma correta modelagem do domnio devemos considerar o uso do DDD (Domain-Driven Design). Este,
conforme a definio do site DDDComunity.org, no se trata de uma tecnologia ou uma metodologia, mas
de uma maneira de definir prioridades, que objetiva acelerar o desenvolvimento dos projetos de software que
lidam com domnios complexos.
De acordo com o DDD, preciso que os desenvolvedores tenham um entendimento do domnio, no to
profundo quanto o dos analistas de negcio (que so os especialistas do domnio), mas uma compreenso
suficiente para que eles possam desenvolver guiados pelo domnio. E para que isso acontea, muito
importante criar uma forma de comunicao entre todos os que iro lidar com o domnio.
Essa conversa deve ocorrer entre os membros da equipe, se tornando o ponto chave para que uma
linguagem comum se estabelea entre desenvolvedores e especialistas. Dessa forma, todos os membros da
equipe iro criar, juntos, os termos ou vocbulos a serem utilizados.
O conjunto de termos criados neste procedimento conhecido como Linguagem Ubqua.
Definida uma terminologia comum e um entendimento das necessidades do domnio, os desenvolvedores j
possuem um modelo a ser seguido para a implementao do cdigo, que deve ocorrer respeitando a
13

sequncia de desenvolvimento acertada nas conversas com os especialistas do domnio, item por item. Caso
haja qualquer mudana no modelo, ela dever ser refletida no cdigo.
Essa interao entre modelo e cdigo nos mostra que com o uso do DDD ocorre uma mudana de nfase.
medida que o modelo mantido pelos analistas sofre alteraes, elas tambm precisam ser refletidas no
cdigo mantido pelos desenvolvedores, tanto atravs da criao e remoo de funcionalidades, quanto
atravs da refatorao.
Para os desenvolvedores e analistas de negcio interessados numa abordagem mais profunda sobre DDD,
recomendamos a leitura do livro Domain-Driven Design, de Eric Evans.
Neste artigo, o nosso objetivo ao analisar as tcnicas de cdigo limpo de Martin Fowler, foi oferecer auxlio
ao programador para que ele desenvolva melhor suas funcionalidades no cotidiano, com o mximo de
clareza e eficincia. Dessa forma, quando este cdigo for manuseado por outro profissional, ele no ter
dificuldades para continuar um trabalho que no foi iniciado por ele.
Aliado s tcnicas de cdigo limpo, muito importante atentar para a escolha de como implementar o seu
modelo de negcio. Conforme constatado, a escolha pelo modelo anmico fere as boas prticas do uso da
orientao a objetos. Portanto, opte sempre pelo modelo de domnio.
Por fim, recomendamos para a correta implementao do modelo de domnio, a prtica do DDD, que tem
como ponto principal estabelecer uma forma de comunicao entre desenvolvedores e analistas de negcio,
para que ambos possam caminhar juntos no ciclo de desenvolvimento.
Links
DDD Community Discusses sobre o assunto, diversos casos de estudo e exemplos do uso do DDD.
http://dddcommunity.org
Special Case Pattern, por Martin Fowler.
http://martinfowler.com/eaaCatalog/specialCase.html
Anemic Domain Model, por Martin Fowler.
http://www.martinfowler.com/bliki/AnemicDomainModel.html
Clean Code, escrito por Robert C. Martin.
Domain-Driven Design, escrito por Eric Evans.
Introduo Arquitetura e Design de Software, escrito por Paulo Silveira, Guilherme Silveira, Srgio
Lopes, Guilherme Moreira, Nico Steppat e Fbio Kung.

Você também pode gostar