CODE SMELLS

2018-09-26 @ 7Masters

Davi Marcondes Moreira - @devdrops

Photo by Braydon Anderson on Unsplash

$ ~ whoami


- Davi Marcondes Moreira

- Software Developer @ Pagar.me

- @devdrops

- PHP, JavaScript, Kotlin e o que mais vier \,,/

- Mending > Making

Photo by Steve Harvey on Unsplash

Photo by Daniil Silantev on Unsplash

"I have an occasion to ask people if they've heard of code smells, and everyone say yes. (...) Then I ask them to list five, and no one can."

Sandi Metz

A LISTA É GRANDE

- Alternative classes with different interfaces

- Comments

- Data Class

- Data Clumps

- Divergent change

- Duplicated code

- Feature envy

- Inappropriate Intimacy

- Incomplete library client

- Large class

- Lazy class

- Long method

- Long parameter list

- Message chain

- Middle man

- Parallel inheritance hierachies

- Primitive obsession

- Refused bequest

- Shotgun surgery

- Speculative generality

- Switch statements

- Temporary fields

3

bons

EXEMPLOS

MÉTODOS LONGOS

public function submit()
{
    $this->load->model('checkout/order');
    $this->load->model('account/customer');
    $order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']);
    $customer = $this->model_account_customer->getCustomer($order_info['customer_id']);

    $discountPercentage = $this->config->get('checkout_boleto_discount_percentage');
    $discountAmount = ($this->cart->getSubtotal() * $discountPercentage) / 100;

    $json=array();
    $json['amount'] = str_replace(array(".", ","), array("", ""), number_format($order_info['total'], 2, '', ''));
    $json['button_text'] = $this->config->get('checkout_texto_botao') ? $this->config->get('checkout_texto_botao') : "Pagar";
    $json['boleto_discount_amount'] = number_format($discountAmount, 2, '', '');
    $json['button_class'] = $this->config->get('checkout_button_css_class');
    $payment_methods = $this->config->get('checkout_payment_methods');
    if (count($payment_methods) == 1) {
        $json['payment_methods'] = $payment_methods[0];
    } else {
        $json['payment_methods'] = $payment_methods[0] . ',' . $payment_methods[1];
    }
    $card_brands = '';
    $card_brands_array = $this->config->get('checkout_card_brands');
    foreach ($card_brands_array as $card_brand) {
        if (reset($card_brands_array) == $card_brand) {
            $card_brands .= $card_brand;
        } else {
            $card_brands .= ',' . $card_brand;
        }
    }

    $json['card_brands'] = $card_brands;

    /* Máximo de parcelas */
    $max_installment = $this->config->get('checkout_max_installments');
    $order_total = $order_info['total'];
    $max_installment_value = $this->config->get('checkout_max_installment_value');

    if($max_installment_value) {
        $installments = floor($order_total / $max_installment_value);
    }else{
        $installments = 0;
    }

    if($installments <= $max_installment) {
        $json['max_installments'] = $installments;
    }else{
        $json['max_installments'] = $max_installment;
    }
    $json['free_installments'] = $this->config->get('checkout_free_installments');
    $json['ui_color'] = $this->config->get('checkout_ui_color');
    $json['postback_url'] = HTTP_SERVER . 'index.php?route=payment/checkout/callback';
    $json['customer_name'] = trim($order_info['payment_firstname']) . ' ' . trim($order_info['payment_lastname']);

    $json['customer_address_street_number'] = 'Sem número';
    $json['customer_address_complementary'] = '';

    /* Pega os custom fields de CPF/CNPJ, número e complemento */
    $this->load->model('account/custom_field');
    $custom_fields = $this->model_account_custom_field->getCustomFields($customer['customer_group_id']);
    foreach($custom_fields as $custom_field){
        $this->log->write($custom_field['name']);
        if($custom_field['location'] == 'account'){
            if((strpos(strtolower($custom_field['name']), 'cpf') !== false) || (strpos(strtolower($custom_field['name']), 'cnpj') !== false)){
                $json['customer_document_number'] = $order_info['custom_field'][$custom_field['custom_field_id']];
            }
        }elseif($custom_field['location'] == 'address'){
            if(strpos(strtolower($custom_field['name']), 'numero') !== false || strpos(strtolower($custom_field['name']), 'número') !== false){
                $json['customer_address_street_number'] = $order_info['payment_custom_field'][$custom_field['custom_field_id']];
            }elseif(strpos(strtolower($custom_field['name']), 'complemento')){
                $json['customer_address_complementary'] = $order_info['payment_custom_field'][$custom_field['custom_field_id']];
            }
        }
    }

    $json['customer_email'] = $order_info['email'];
    $json['customer_address_street'] = $order_info['payment_address_1'];
    $json['customer_address_neighborhood'] = $order_info['payment_address_2'];
    $json['customer_address_city'] = $order_info['payment_city'];

    $this->load->model('localisation/zone');
    $uf = $this->model_localisation_zone->getZone($order_info['payment_zone_id']);

    $json['customer_address_state'] = $uf['code'];
    $json['customer_address_zipcode'] = $this->removeSeparadores($order_info['payment_postcode']);
    $json['customer_phone_ddd'] = substr(preg_replace('/[^0-9]/', '', $order_info['telephone']), 0, 2);
    $json['customer_phone_number'] = substr(preg_replace('/[^0-9]/', '', $order_info['telephone']), 2);
    $json['interest_rate'] = $this->config->get('checkout_interest_rate');


    $this->response->setOutput(json_encode($json));
}

middle man

Photo by rawpixel on Unsplash



class User
{
    private $phone;

    public function getPhone()
    {
        return $this->phone;
    }

    public function getPhoneDdi()
    {
        return $this->phone->getDdi();
    }

    public function getPhoneDdd()
    {
        return $this->phone->getDdd();
    }

    public function getPhoneNumber()
    {
        return $this->phone->getNumber();
    }
}


class User
{
    private $phone;

    public function getPhone()
    {
        return $this->phone;
    }

    public function getPhoneDdi()
    {
        return $this->phone->getDdi();
    }

    public function getPhoneDdd()
    {
        return $this->phone->getDdd();
    }

    public function getPhoneNumber()
    {
        return $this->phone->getNumber();
    }
}

aglomerado de dados



# Mudamos disso
class PostRepository

  def draft(title, description, author)
    # code code code 
  end

  def publish(title, description, author)
    # code code code 
  end

  def update(id, title, description, author)
    # code code code 
  end

end



# Mudamos disso
class PostRepository

  def draft(title, description, author)
    # code code code 
  end

  def publish(title, description, author)
    # code code code 
  end

  def update(id, title, description, author)
    # code code code 
  end

end



# Mudamos disso
class PostRepository

  def draft(title, description, author)
    # code code code 
  end

  def publish(title, description, author)
    # code code code 
  end

  def update(id, title, description, author)
    # code code code 
  end

end

# Para isso
Post = Struct.new(:title, :description, :author)

class PostRepository

  def draft(post)
    # code code code
  end

  def publish(post)
    # code code code
  end

  def update(id, post)
    # code code code
  end

end

 


CONCLUSÃO

Aprender code smells torna mais fácil identificar problemas no seu código.

REFERÊNCIAS

- Code Refactoring: Learn Code Smells And Level Up Your Game! (https://www.youtube.com/watch?v=D4auWwMsEnY)

 

- Smells to Refactoring Quick Reference Guide (http://www.industriallogic.com/wp-content/uploads/2005/09/smellstorefactorings.pdf)

 

MUITO OBRIGADO! :D

@devdrops

devdrops.me/about

bit.ly/7masters-code-smells

Code Smells

By Davi Marcondes Moreira

Code Smells

Talk realizada no 7Masters - Qualidade de Código (https://setemasters.imasters.com.br/edicoes/qualidade-de-codigo/), em 26/09/2018.

  • 993