Código Limpo
HENRIQUE SMOCO
Desenvolv
Manutenção de Software
 % do tempo gasto lendo código vs escrevendo
 Intelectualmente Complexo
 Documentação?
 Se não está quebrado, não arrume
 Mais dificil a cada iteração
Definição Código Limpo
 Funciona
 É facil de ler
 Simples de entender
 Eficiente (sem rodeios)
 Fácil de estender
 Limpo (alguém se importou)
Métrica de Código Limpo
“Qualquer tolo pode escrever
código que um computador
pode entender. Bons
programadores escrevem
código que humanos podem
entender.”
MARTIN FOWLER
Como escrever melhor?
Escreva para os outros
 Escreva o código como se a próxima pessoa a dar
manutenção fosse um psicopata violento que sabe
onde você mora!
Regra do escoteiro
 Quando levantar acampamento, deixe o local mais
limpo do que estava quando você chegou.
Se importe
 Nem que seja só acertar a formatação
 Evite a síndrome da janela quebrada
Não reinvente a roda
 Antes de escrever, pergunte se alguém já o fez ou se
existe uma lib que faz o que é preciso
 Menos é mais!
Estude, pergunte,
compartilhe
Código Sujo
CODE SMELLS
Detectando Código Ruim
 Código não usado
 Código duplicado
 Muitos parametros no método
 Método longo (+ de 20 linhas)
 Complexidade condicional
 Generalidade especulativa
 Comentários (o que ao invés do porque)
Para uma lista mais completa acesse: http://www.codinghorror.com/blog/2006/05/code-smells.html
Código Limpo
Conceitos Gerais
 Ajude o próximo, pois o próximo pode ser você
 Não crie abstrações pensando no futuro
 Não tenha medo de alterar, na pior das hipóteses já
estava quebrado mesmo
 Não otimize prematuramente
 Prefira composição ao invés de herança
 Evite métodos estáticos/singletons
 Deletar código é mais divertido que criar
Use Nomes Significativos
 Use nomes que revelam a intenção
 Dê preferência à linguagem do cliente (Ubiquitous
Language)
 Não economize caracteres
 Não seja engraçado
 Evite prefixos (strMinhaVariavel)
 Se não está claro, renomeie
 Não use caracteristicas da variável
 Date yyyyMMdd = ...
 Color azul = Color.RED; //CÓDIGO RUIM
Use Nomes Significativos
public List<Cell> getCelulas() {
List<Cell> lst = new ArrayList<Cell>();
for (Cell c : dados)
if (c.getStatus() == 4)
lst.add(c);
return lst;
}
Use Nomes Significativos
public List<Cell> getCelulasMarcadas() {
List<Cell> celulasMarcadas = new ArrayList<>();
for (Cell cell : gameBoard)
if (cell.isMarcada()) {
celulasMarcadas.add(cell);
}
return celulasMarcadas;
}
Métodos Limpos
 Devem ser pequenos
 Sério, ainda menores do que isso
 Devem fazer apenas uma coisa
 Melhor se organizados de cima para baixo
 Evite usar variáveis globais, use parâmetros
 Não tem side effects
 Uma entrada, uma saída
 Não tem código duplicado (DRY)
 Muitos parâmetros? Troque por uma classe
Métodos Limpos
public void printaNomeUsuario(int codigoUsuario) {
Usuario usuario = getUsuario(codigoUsuario);
if (isUsuarioExistente(usuario)) {
printaNoConsole(usuario.getNome());
}
}
private Usuario getUsuario(int codigoUsuario) {
return dao.getUsuario(codigoUsuario);
}
private boolean isUsuarioExistente(Usuario usuario) {
return usuario != null;
}
private void printaNoConsole(String mensagem) {
system.out.println(mensagem);
}
Métodos Limpos
public void printaNomeUsuario(int codigoUsuario) {
Usuario usuario = getUsuario(codigoUsuario);
if (isUsuarioExistente(usuario)) {
printaNoConsole(usuario.getNome());
}
}
private Usuario getUsuario(int codigoUsuario) {
return dao.getUsuario(codigoUsuario);
}
private boolean isUsuarioExistente(Usuario usuario) {
return usuario != null;
}
private void printaNoConsole(String mensagem) {
system.out.println(mensagem);
}
Métodos Limpos
public void printaNomeUsuario(int codigoUsuario) {
Usuario usuario = getUsuario(codigoUsuario);
if (isUsuarioExistente(usuario)) {
printaNoConsole(usuario.getNome());
}
}
private Usuario getUsuario(int codigoUsuario) {
return dao.getUsuario(codigoUsuario);
}
private boolean isUsuarioExistente(Usuario usuario) {
return usuario != null;
}
private void printaNoConsole(String mensagem) {
system.out.println(mensagem);
}
Métodos Limpos
public void printaNomeUsuario(int codigoUsuario) {
Usuario usuario = getUsuario(codigoUsuario);
if (isUsuarioExistente(usuario)) {
printaNoConsole(usuario.getNome());
}
}
private Usuario getUsuario(int codigoUsuario) {
return dao.getUsuario(codigoUsuario);
}
private boolean isUsuarioExistente(Usuario usuario) {
return usuario != null;
}
private void printaNoConsole(String mensagem) {
system.out.println(mensagem);
}
Comentários Limpos
 Explique o porque, não o que
 Evite redundância
//Pega os usuários
List usuarios = getUsuarios();
//Pega os usuários novamente porque o cache pode
estar desatualizado
List usuarios = getUsuarios();
Comentários Limpos
 Se precisar usar comentários, provavelmente deveria
criar um método no lugar dele
List idClientes = ...
//Pega clientes do banco
for (Cliente cli : idClientes) {
...
}
List idClientes = ...
getClientesDoBanco(idClientes);
Comentários Limpos
// Verifica se o empregado é elegível a todos os benefícios
if ((empregado.flags & HOURLY_FLAG) &&
(empregado.age > 65))
if (empregado.isEligivelTodosBeneficios())
Comentários Limpos
while ((line = in.readLine()) != null) {
...
} //fim while
// InputStream results = formatter.getResultStream();
// Reader reader = new StreamReader(results);
//TODO Validar o código recebido
Formatação Limpa
 Seu propósito é melhorar a comunicação
 Siga o padrão de formatação do projeto/time
 Declare a variável o mais perto possível de onde ela é
usada
 Sempre use chaves
if (logado) {
loginsCount++;
}
Formatação Limpa
 Use agrupamento vertical para separar código não
relacionado
List clientes = ...
clientesAtivos = selecionarAtivos(clientes);
gerarBoletosPara(clientesAtivos);
gravarFlagBoletosGerados(clientesAtivos);
gravarLogProcesso(clientesAtivos, msgSucesso);
dispararEmailsDeBoletoDisponivel(clientesAtivos);
Tratamento de Erros Limpo
 Ou você faz log ou throw, nunca os dois
 Use log4j (ou outros), System.out é mau
 Prefira RuntimeException
Tratamento de Erros Limpo
public void delete(Page page) {
try {
deletePageAndAllReferences(page);
} catch (Exception e) {
logger.log(e.getMessage());
}
}
private void deletePageAndAllReferences(Page page) throws
Exception {
deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());
}
Tratamento de Erros Limpo
 Sempre que possível, não retorne null
List<Employee> employees = getEmployees();
for(Employee e : employees) {
totalPay += e.getPay();
}
}
public List<Employee> getEmployees() {
if( .. there are no employees .. ) {
return Collections.emptyList();
}
}
Testes Limpos
 Trate seu teste igual ao código de produção
 Prefira testes unitários
 Verifique um conceito por teste
 Verifique um conceito por teste (importante)
 Sempre execute todos os testes
 Não use o construtor da classe de teste, use @Before e
@BeforeClass
 Sem setup/verificações manuais
 Quanto mais simples, melhor
Código Limpo
DEPENDE DE VOCÊ TAMBÉM
Código Limpo

Código Limpo

  • 1.
  • 2.
    Desenvolv Manutenção de Software % do tempo gasto lendo código vs escrevendo  Intelectualmente Complexo  Documentação?  Se não está quebrado, não arrume  Mais dificil a cada iteração
  • 3.
    Definição Código Limpo Funciona  É facil de ler  Simples de entender  Eficiente (sem rodeios)  Fácil de estender  Limpo (alguém se importou)
  • 4.
  • 5.
    “Qualquer tolo podeescrever código que um computador pode entender. Bons programadores escrevem código que humanos podem entender.” MARTIN FOWLER
  • 6.
  • 7.
    Escreva para osoutros  Escreva o código como se a próxima pessoa a dar manutenção fosse um psicopata violento que sabe onde você mora!
  • 8.
    Regra do escoteiro Quando levantar acampamento, deixe o local mais limpo do que estava quando você chegou.
  • 9.
    Se importe  Nemque seja só acertar a formatação  Evite a síndrome da janela quebrada
  • 10.
    Não reinvente aroda  Antes de escrever, pergunte se alguém já o fez ou se existe uma lib que faz o que é preciso  Menos é mais!
  • 11.
  • 12.
  • 13.
    Detectando Código Ruim Código não usado  Código duplicado  Muitos parametros no método  Método longo (+ de 20 linhas)  Complexidade condicional  Generalidade especulativa  Comentários (o que ao invés do porque) Para uma lista mais completa acesse: http://www.codinghorror.com/blog/2006/05/code-smells.html
  • 14.
  • 15.
    Conceitos Gerais  Ajudeo próximo, pois o próximo pode ser você  Não crie abstrações pensando no futuro  Não tenha medo de alterar, na pior das hipóteses já estava quebrado mesmo  Não otimize prematuramente  Prefira composição ao invés de herança  Evite métodos estáticos/singletons  Deletar código é mais divertido que criar
  • 16.
    Use Nomes Significativos Use nomes que revelam a intenção  Dê preferência à linguagem do cliente (Ubiquitous Language)  Não economize caracteres  Não seja engraçado  Evite prefixos (strMinhaVariavel)  Se não está claro, renomeie  Não use caracteristicas da variável  Date yyyyMMdd = ...  Color azul = Color.RED; //CÓDIGO RUIM
  • 17.
    Use Nomes Significativos publicList<Cell> getCelulas() { List<Cell> lst = new ArrayList<Cell>(); for (Cell c : dados) if (c.getStatus() == 4) lst.add(c); return lst; }
  • 18.
    Use Nomes Significativos publicList<Cell> getCelulasMarcadas() { List<Cell> celulasMarcadas = new ArrayList<>(); for (Cell cell : gameBoard) if (cell.isMarcada()) { celulasMarcadas.add(cell); } return celulasMarcadas; }
  • 19.
    Métodos Limpos  Devemser pequenos  Sério, ainda menores do que isso  Devem fazer apenas uma coisa  Melhor se organizados de cima para baixo  Evite usar variáveis globais, use parâmetros  Não tem side effects  Uma entrada, uma saída  Não tem código duplicado (DRY)  Muitos parâmetros? Troque por uma classe
  • 20.
    Métodos Limpos public voidprintaNomeUsuario(int codigoUsuario) { Usuario usuario = getUsuario(codigoUsuario); if (isUsuarioExistente(usuario)) { printaNoConsole(usuario.getNome()); } } private Usuario getUsuario(int codigoUsuario) { return dao.getUsuario(codigoUsuario); } private boolean isUsuarioExistente(Usuario usuario) { return usuario != null; } private void printaNoConsole(String mensagem) { system.out.println(mensagem); }
  • 21.
    Métodos Limpos public voidprintaNomeUsuario(int codigoUsuario) { Usuario usuario = getUsuario(codigoUsuario); if (isUsuarioExistente(usuario)) { printaNoConsole(usuario.getNome()); } } private Usuario getUsuario(int codigoUsuario) { return dao.getUsuario(codigoUsuario); } private boolean isUsuarioExistente(Usuario usuario) { return usuario != null; } private void printaNoConsole(String mensagem) { system.out.println(mensagem); }
  • 22.
    Métodos Limpos public voidprintaNomeUsuario(int codigoUsuario) { Usuario usuario = getUsuario(codigoUsuario); if (isUsuarioExistente(usuario)) { printaNoConsole(usuario.getNome()); } } private Usuario getUsuario(int codigoUsuario) { return dao.getUsuario(codigoUsuario); } private boolean isUsuarioExistente(Usuario usuario) { return usuario != null; } private void printaNoConsole(String mensagem) { system.out.println(mensagem); }
  • 23.
    Métodos Limpos public voidprintaNomeUsuario(int codigoUsuario) { Usuario usuario = getUsuario(codigoUsuario); if (isUsuarioExistente(usuario)) { printaNoConsole(usuario.getNome()); } } private Usuario getUsuario(int codigoUsuario) { return dao.getUsuario(codigoUsuario); } private boolean isUsuarioExistente(Usuario usuario) { return usuario != null; } private void printaNoConsole(String mensagem) { system.out.println(mensagem); }
  • 24.
    Comentários Limpos  Expliqueo porque, não o que  Evite redundância //Pega os usuários List usuarios = getUsuarios(); //Pega os usuários novamente porque o cache pode estar desatualizado List usuarios = getUsuarios();
  • 25.
    Comentários Limpos  Seprecisar usar comentários, provavelmente deveria criar um método no lugar dele List idClientes = ... //Pega clientes do banco for (Cliente cli : idClientes) { ... } List idClientes = ... getClientesDoBanco(idClientes);
  • 26.
    Comentários Limpos // Verificase o empregado é elegível a todos os benefícios if ((empregado.flags & HOURLY_FLAG) && (empregado.age > 65)) if (empregado.isEligivelTodosBeneficios())
  • 27.
    Comentários Limpos while ((line= in.readLine()) != null) { ... } //fim while // InputStream results = formatter.getResultStream(); // Reader reader = new StreamReader(results); //TODO Validar o código recebido
  • 28.
    Formatação Limpa  Seupropósito é melhorar a comunicação  Siga o padrão de formatação do projeto/time  Declare a variável o mais perto possível de onde ela é usada  Sempre use chaves if (logado) { loginsCount++; }
  • 29.
    Formatação Limpa  Useagrupamento vertical para separar código não relacionado List clientes = ... clientesAtivos = selecionarAtivos(clientes); gerarBoletosPara(clientesAtivos); gravarFlagBoletosGerados(clientesAtivos); gravarLogProcesso(clientesAtivos, msgSucesso); dispararEmailsDeBoletoDisponivel(clientesAtivos);
  • 30.
    Tratamento de ErrosLimpo  Ou você faz log ou throw, nunca os dois  Use log4j (ou outros), System.out é mau  Prefira RuntimeException
  • 31.
    Tratamento de ErrosLimpo public void delete(Page page) { try { deletePageAndAllReferences(page); } catch (Exception e) { logger.log(e.getMessage()); } } private void deletePageAndAllReferences(Page page) throws Exception { deletePage(page); registry.deleteReference(page.name); configKeys.deleteKey(page.name.makeKey()); }
  • 32.
    Tratamento de ErrosLimpo  Sempre que possível, não retorne null List<Employee> employees = getEmployees(); for(Employee e : employees) { totalPay += e.getPay(); } } public List<Employee> getEmployees() { if( .. there are no employees .. ) { return Collections.emptyList(); } }
  • 33.
    Testes Limpos  Trateseu teste igual ao código de produção  Prefira testes unitários  Verifique um conceito por teste  Verifique um conceito por teste (importante)  Sempre execute todos os testes  Não use o construtor da classe de teste, use @Before e @BeforeClass  Sem setup/verificações manuais  Quanto mais simples, melhor
  • 34.