★ wanayoo — archive 1999 https://github.com/lucassklp/code-smells-in-javaNouvelle recherche | Portail wanayoo
Skip to content
master
Go to file
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 

README.md

Code Smells em Java

You can also read in English (EN)

Smell em inglês significa cheiro, odor, etc. Trazendo esse conceito pro mundo do código, Code Smell significa aquele código que não parece cheirar bem, apesar de está funcionando corretamente.

Sua reação ao ver um code smell

Esta é a sua reação ao ver um code smell

Creio que todos os desenvolvedores já devem ter tido a sensação de olhar pra um código e pensar:

"Cara, que código terrível! Como eu posso deixar isso melhor?"

Se isso já aconteceu com você, não se preocupe - isso é mais normal do que você imagina. Porém, é importante saber você também produz code smell e isso é absolutamente normal, pois a maioria das pessoas não percebem quando estão estão fazendo 💩 no código.

Aqui, vamos aprender algumas coisas importantes para escrever bons códigos em Java: Como identificar um code smell e tambémcomo remover code smells (refactoring).

Mas antes, precisamos falar sobre alguns princípios de Programação Orientada a Objetos

Pilares da Programação Orientada a Objetos

Paradigma Procedural (a.k.a Código "Macarrônico")

Qual o problema do código abaixo

//Código fonte obtido em https://github.com/emacdona/tictactoe/blob/master/main.c
#include <stdio.h>
#include "board.h"
int main(int argc, char* argv[])
{
   //Variáveis de controle
   char board[3][3];
   char input[3];
   int moveTo;
   int turn = 0;
   char player;

   //Definição da função
   initBoard(board);

   //Lógica do Jogo
   while(1){
      player = (turn % 2) ? 'o' : 'x';
      system("clear");
      drawBoard(board);

      if(state(board) == 1){
         printf("\nWinner!\n");
         return 0;
      }

      if(state(board) == -1){
         printf("\nDraw!\n");
         return 0;
      }

      printf("\n(turn #%i) To which square would you (player %c) like to move? ", turn, player);
      fgets(input, 3, stdin);
      moveTo = atoi(input);

      if(mv(board, moveTo, player))
         turn++;

      printf("\n");
   }

   return 0;
}

Programação orientada a objetos

  • Encapsulamento
  • Abstração
  • Herança
  • Polimorfismo

Uma solução mais simples ao jogo da velha:

public class Program {
    public static void main() {
        Game game = new TicTacToe();
        game.play();
    }
}

public interface Game {
    void play();
}

public class TicTacToe implements Game {
    private Player player1;
    private Player player2;
    private Board board;
    private Player currentPlayer;
    public TicTacToe(){
        this.player1 = new Player("X");
        this.player2 = new Player("O");
        this.board = new Board();
    }

    // Implementa toda a lógica do jogo
    public void play() { /* ... */ }

    // Lógica interna (não externalizada a quem tá utilizando a classe)
    private boolean hasWinner() { /* ... */ }

    //...
}

public class Player {
    private String symbol;
    public Player(String symbol) {
        this.symbol = symbol;
    }

    public String getSymbol() {
        return this.symbol;
    }
}

public class Board {
    private String[][] board;
    public Board() {
        this.board = new String[3][3];
    }
    
    public void draw() { /* ... */ }
}

S.O.L.I.D

S.O.L.I.D é um acrônimo para cinco princípios de programação orientada a objetos. Esses princípios são importantes para identificar quando o

Qual o problema com esse código

public class UserService extends DatabaseConection {
    
    public void register(User user){

        // Valida o e-mail

        if(user.getEmail() == null){
            throw new Exception("E-mail informado é nulo");
        }

        if(!isValidEmail(user.getEmail())){
            return new Exception("O e-mail informado não é válido");
        }

        // Verifica se o usuário existe na base
        Connection conn = super.getConnection();
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT ID FROM USERS WHERE EMAIL = " + user.getEmail());
        
        //Se não existir, insere na base


        rs.close();
        stmt.close();
        conn.close();


    }

    private boolean isValidEmail(String emailStr) {
        String regEx = "^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$";
        Pattern pattern = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(emailStr);
        return matcher.find();
    }
}

Solução um pouco mais elegante:

public abstract class Validator<T> {
    public abstract ValidationResult isValid(T item);

    public boolean isValidEmail(String email){
        String regEx = "^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$";
        Pattern pattern = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(emailStr);
        return matcher.find();
    }

    // ...

}

public class ValidationResult {
    private List<String> errors = new ArrayList();

    public void addError(String error){
        this.errors.add(error);
    }

    public boolean hasErrors(){
        this.errors.size() > 0;
    }

    public List<String> getErrors() {
        return this.errors;
    }
}


public class UserValidator extends Validator<User> {
    public ValidationResult isValid(User user) {
        ValidationResult results = new ValidationResult();
        if(user.getEmail() == null){
            results.addError("E-mail informado é nulo");
        }

        if(!isValidEmail(user.getEmail())){
            results.addError("E-mail informado é inválido")
        }

        // ...

        return results;
    }
}

public abstract class Repository<T> {
    public abstract T create(T item);
    public abstract T read(long id);
    public abstract T update(T item);
    public abstract void delete(long id);
    public abstract bool exists(T item);
}


public class UserService {

    private Validator<User> validator;
    private Repository<User> repository;

    public UserService(Validator<User> validator, Repository<User> repository) {
        this.validator = validator;
        this.repository = repository;
    }

    public void register(){
        if(validator.isValid() && ){

        }
    }
}

Qual o problema com esse código?

enum TipoPagamento {
    BOLETO,
    CARTAO_CREDITO,
    CARTAO_DEBITO
    //EM_ESPECIE
}

public class PagamentoService {

    public void pagar(double valor, TipoPagamento tipoPagamento, Cliente cliente){
        if(tipoPagamento.BOLETO){
            /* Implementação do código */
            salvaNoBanco(pagamentoBoleto, cliente);
        }
        
        if(tipoPagamento.CARTAO_CREDITO){
            /* Implementação do código */
            salvaNoBanco(pagamentoCartao, cliente);
        }
        // ...
    }
}

Single Responsibility Principle (SRP)

Uma classe deve ter um, e somente um, motivo para ser modificada

Open-Closed Principle (OCP)

Aberto para extensão (open), fechado para modificação (closed)

Liskov Substitution Principle (LSP)


Interface Segregation Principle (ISP)

Dependency Inversion Principle (DIP)

Dependa sempre de abstrações, não de implementações

Code Smells

  • São indícios em um código que indicam que eles não estão seguindo os bons princípios da OO e do SOLID.
  • São derivações dos pilares da POO.

Code smells a nível de aplicação

Code smells a nível de classe

Code mells a nível de método

A importância do processo de desenvolvimento de software

Eu sei, a maioria dos programadores não gostam de falar de processos, pois as vezes nós temos uma sensação que eles mais atrapalham do que ajudam.

Extreme Go Horse

eXtreme Go Horse

O eXtreme Go Horse (XGH) é uma sátira genial de como os softwares são desenvolvidos sem nenhuma metodologia.

Alguns axiomas do XGH (a.k.a como os softwares são feitos hoje em dia)

1. Pensou, não é XGH.

XGH não pensa, faz a primeira coisa que vem à mente. Não existe segunda opção, a única opção é a mais rápida.

9 - Seja autêntico, XGH não respeita padrões.

Escreva o código como você bem entender, se resolver o problema, commit e era isso.

20 - Teste é para os fracos.

Se você meteu a mão num sistema XGH, é melhor saber o que está fazendo. E se você sabe o que está fazendo, vai testar pra que? Testes são desperdício de tempo, se o código compilar, é o suficiente.

Benchmark

Benchmark do Go Horse Process

Code Review

Testes unitários e TDD

Releases

No releases published

Packages

No packages published
You can’t perform that action at this time.