código limpo
TRANSCRIPT
Código LimpoHENRIQUE SMOCO
DesenvolvManutençã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 SujoCODE 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áriosList usuarios = getUsuarios();
//Pega os usuários novamente porque o cache pode estar desatualizadoList usuarios = getUsuarios();
Comentários Limpos
Se precisar usar comentários, provavelmente deveria criar um método no lugar dele
List idClientes = ...//Pega clientes do bancofor (Cliente cli : idClientes) { ...}
List idClientes = ...getClientesDoBanco(idClientes);
Comentários Limpos
// Verifica se o empregado é elegível a todos os benefíciosif ((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