RuboCop: Um amigo de qualidade

Jenifer Silva
Revista eQAlizando (antiga Revista TSPI)
12 min readOct 17, 2020

Durante a revisão de código é muito importante ter ferramentas que nos auxiliem nesta tarefa e nesse contexto, os linters podem agregar grande valor para o time.

Neste artigo, Jarbas Júnior e Jenifer Silva, mentorados do Júlio de Lima e alunos do TSPI💜, apresentam como os Linters podem te ajudar a revisar com mais precisão o código de sua aplicação. Além disso, apresentam um exemplo de uso do RuboCop, que é uma ferramenta de análise estática de código Ruby e formatador de código.

Entendendo os Linters

Linters são ferramentas que auxiliam na análise estática de código, de forma automatizada, ou seja, eles podem analisar o código fonte em busca de problemas, propondo melhorias e correções de implementação.

Algumas das vantagens dos linters são:

  • Menos erros indo para o ambiente de produção;
  • Código legível, sustentável e mais consistente;
  • Menos discussões sobre estilo de código e escolhas estéticas durante as revisões de código;
  • Medição objetiva da qualidade do código;
  • Código mais seguro e eficiente.

É importante salientar que temos diversos tipos de linters e eles devem ser escolhidos de acordo com a necessidade do seu projeto.

Tipos de Linter

Erros de sintaxe

Esse tipo de análise verifica erros de sintaxe a exemplo de falta de sinais no código, como ponto e vírgula ou chaves, sendo identificados antes mesmo da build no projeto ser concluída.

Convenção de codificação/formatação

A verificação de convenções e formatação é feita de acordo com a linguagem do código. Tais convenções facilitam a leitura, entendimento e manutenção do que está sendo desenvolvido.

Code Smells

Uma ferramenta lint pode identificar funções muito extensas ou complexas. Para metrificar a complexidade do código os linters utilizam, por exemplo, a ABC Software Metric.

Segurança

Segurança é um item muito importante durante a codificação e algo inseguro pode causar, por exemplo, problemas financeiros para a empresa detentora do sistema. Ferramentas de lint podem auxiliar nesta análise, identificando, por exemplo, se métodos YAML no seu código estão carregando dados inseguros.

RuboCop

O RuboCop é uma ferramenta de análise estática de código Ruby e formatador de código. Sua análise é baseada nas diretrizes descritas no Ruby Style Guide da comunidade Ruby.

Instalação

Como pré-requisito você precisa ter instalados em seu computador o Ruby e o Bundler.

A instalação do RuboCop pode ser feita de duas formas em seu computador:

  1. Execute o comando gem install rubocop a partir de seu terminal. Após o término de sua instalação, você deve visualizar uma mensagem similar a da figura abaixo. Obs.: A versão mais recente do RuboCop até o momento da escrita do presente artigo é a 0.93.1, e talvez ela possa variar a depender do dia que você esteja consultando este artigo.
Execução do comando gem install rubocop

2. Declare a gem ‘rubocop’ a partir do arquivo Gemfile de seu projeto. Caso não tenha, você pode acompanhar os exemplos a seguir, clonando nosso projeto a partir deste link. Opcionalmente, você pode adicionar a versão na declaração da Gem. No nosso exemplo utilizaremos a versão 0.93.1.

Declaração da Gem no projeto

Observação: Ao fazer a instalação descrita no item 2, será necessária a instalação do RuboCop via Bundler. Para isto, abra o terminal a partir da pasta raiz do projeto e execute o comando bundle install. Ao término da execução você perceberá que novas Gems foram instaladas, sinalizadas pela cor verde.

Execução do comando bundle install

Ao concluir a instalação, seja de que modo você tenha escolhido, verifique se o RuboCop foi instalado com sucesso executando o seguinte comando em seu terminal:

rubocop -v
Execução do comando rubocop -v

O comportamento do RuboCop pode ser controlado por meio do arquivo de configuração .rubocop.yml. Este arquivo permite habilitar/desabilitar algumas verificações e comportamentos do RuboCop. O arquivo pode ser adicionado em seu diretório inicial, diretório de configuração XDG ou em algum diretório de projeto.

Conceitos básicos: Ofensas e Cops

Os itens identificados pelo RuboCop são chamados de ofensas. As ofensas são baseadas em Cops, que nada mais são que verificações realizadas pelo RuboCop. Ou seja, cada ofensa possui um Cop associado a ela.

Com o RuboCop devidamente instalado e configurado, acesse via terminal a pasta raíz do seu projeto Ruby e execute o comando a seguir para visualizar as ofensas:

rubocop

O resultado será parecido com o da imagem abaixo:

Exemplo de resultado da execução do RuboCop

No exemplo acima, podemos observar no final da imagem que o RuboCop inspecionou 20 arquivos no projeto e dentro deles foram detectadas 25 ofensas, das quais ele informa que 20 são autocorrigíveis.

Mas o que o RuboCop considera como ofensa? E quais o RuboCop pode corrigir automaticamente?

Sempre que o RuboCop verificar os arquivos de seu projeto e perceber que qualquer trecho de código está em desacordo com as boas práticas definidas pela comunidade do Ruby Style Guide, será exibido um alerta informando quantas ofensas ele encontrou.

Correções automáticas de ofensas

Um recurso muito interessante do RuboCop é a possibilidade de correções automáticas de ofensas. Antes de executar o comando de correções automáticas tenha em mente que:

  • Para algumas ofensas, não é possível implementar a correção automática.
  • Mesmo que a correção automática seja possível, a mesma pode não ter sido implementada no RuboCop ainda.
  • Algumas correções automáticas podem alterar (ligeiramente) a semântica do código, o que significa que produziriam um código que é basicamente equivalente ao código original, mas não 100% equivalente. Chamamos esse comportamento de autocorreção de “inseguro”.

A correção automática pode ser feita de duas formas:

  1. Executando o comando rubocop -a (-a é a abreviação de --auto-correct), o qual corrige automaticamente as ofensas quando o RuboCop julgar seguro.
  2. Executando o comando rubocop -A (-A é a abreviação de --auto-correct-all), este por sua vez corrige automaticamente as ofensas que o RuboCop considera seguras e inseguras.

Vamos executar o primeiro comando em nosso projeto e verificar o resultado:

rubocop -a
Execução do comando rubocop -a

Huum… Pelo visto nada mudou no nosso projeto, provavelmente ele considerou como não seguro corrigir automaticamente. Contudo, no final da mensagem ele informa que pode ser corrigido com o nosso segundo comando (rubocop -A). Vamos executá-lo e ver qual será a saída?

Execução do comando rubocop -A

Vamos analisar detalhadamente o que ocorreu fazendo um De-Para do trecho final entre as duas últimas imagens.

Primeira execução
Segunda execução

Na primeira imagem tínhamos 25 ofensas detectadas e na segunda imagem esse número subiu para 45. E por quê só agora o RuboCop está informando sobre a correção do cop Layout/EmptyLineAfterMagicComment se na imagem anterior ele nem se quer aparecia? Pode isso Arnaldo???

Na primeira execução foi corrigida uma ofensa relacionada ao Cop Style/FrozenStringLiteralComment. Para entender o que é esse cop podemos consultar a documentação dos cops, realizando uma busca na caixa de pesquisa para verificar sobre o que esse cop é responsável por “fiscalizar”.

Busca na documentação de Cops

Ao clicar na primeira opção da busca, somos direcionados para uma página, a qual informa que trata-se de um cop de estilo (por isso é escrito Style/FrozenStringLiteralCommenttipo/nome do cop). Nessa página temos o detalhamento do cop com alguns exemplos, os quais a comunidade Ruby considera como boas e más práticas.

Informações sobre o cop Style/FrozenStringLiteralComment

Como podemos ver na documentação esse cop adiciona a linha # frozen_string_literal: true no topo dos arquivos, também chamada de comentário mágico, o qual permite você optar por Strings imutáveis alterando o final do comentário para true ou false, cuja finalidade é oferecer um melhor desempenho quando ela for atribuída como true. Para mais detalhes recomendamos a leitura deste artigo.

E o cop Layout/EmptyLineAfterMagicComment, por que apareceu repentinamente? Vamos consultar também sua documentação para conferir.

Informações sobre o cop Layout/EmptyLineAfterMagicComment

Como podemos observar na documentação, este é um cop de layout, o qual verifica se após o comentário mágico (exatamente o # frozen_string_literal: true) há uma linha. Entendeu agora o porquê do aumento das correções automáticas?

Após essas alterações, vamos ver o que o RuboCop fez em nosso código? Aqui no artigo vamos utilizar o Source Control do VSCode para verificar as alterações, mas fique a vontade para utilizar a IDE e controle de versionamento de sua preferência!

Abra o terminal a partir da pasta raiz do projeto e execute o comando code . para abrir o VSCode exatamente a partir da pasta raiz do nosso projeto.

Execução do comando code .

Com o VSCode aberto clique no ícone Source Control.

Source Control no VSCode

Em nosso projeto o RuboCop indicou as correções necessárias em diversos arquivos, dos quais utilizaremos windows_spec.rb para exemplificar. Selecione o arquivo windows_spec.rb para vermos o que o RuboCop alterou conforme ilustra a figura abaixo.

Seleção de arquivo no Source Control

Clique novamente no ícone do Source Control ou utilize o atalho Ctrl + b (caso ele não tenha sido modificado em seu VSCode) para visualizar melhor o código. Veja no código do lado direito as linhas destacadas em verde no seu contorno, a linha 1 (# frozen_string_literal: true), refere-se ao comentário mágico adicionado pelo RuboCop, o qual adicionou também uma linha em branco (linha 2).

Comparativo de versões do arquivo windows_spec.rb

Podemos observar no código modificado à direita que o que nos foi dito pelo RuboCop no terminal (imagem abaixo), foi de fato aplicado em nosso código.

Execução do comando rubocop

Os dois tipos de cop’s que comentamos até o momento foram de estilo e de layout, porém há vários outros listados abaixo, os quais você encontrará mais detalhes na documentação.

  • Bundler
  • Gemspec
  • Lint
  • Metrics
  • Migration
  • Naming
  • Security

Então, basta utilizar os comandos rubocop -a ou -A que sempre teremos a convenção e formatação aplicadas no nosso código?

Errado jovem! Não é bem assim BB.

Personalizando alguns Cops

Estabelecer na equipe as diretrizes de codificação, embora seja na maioria dos casos algo difícil (e há quem diga impossível), será de grande valia para todos membros de um time, se for realizada da maneira correta.

Considerando que sua equipe alcançou este feito (pare de dar risadas irônicas, acredite jovem, tenha fé) e considerando que ela desenvolve em Ruby on Rails, podemos configurar a convenção definida no projeto dentro do arquivo .rubocop.yml e com ele poderemos habilitar, desabilitar e personalizar alguns cops. A seguir veremos na prática como configurar este arquivo.

Primeiro vamos reverter a correção automática que fizemos antes. Siga os passos a seguir:

  1. Clique no botão Source Control do VSCode;
  2. Clique no arquivo alerts_spec.rb;
  3. Pressione Shift;
  4. Clique no arquivo windows_spec.rb (deixando de fora da seleção o Gemfile e o Gemfile.lock);
  5. Em cima da seleção criada, clique com o botão direito do mouse e selecione a opção Discard Changes e confirme;
  6. Por fim, entre no arquivo Gemfile e exclua as linhas 1 e 2 adicionadas pelo Rubocop e salve o arquivo.
Reversão de código no VSCode

Agora clique no ícone Explorer do VSCode e na raiz do projeto crie um arquivo chamado .rubocop.yml.

Criação de arquivo no projeto

Vamos executar novamente no terminal o comando rubocop e você verá que teremos a mesma saída exibida logo no início deste artigo.

Execução do comando rubocop

Suponha agora que sua equipe definiu em reunião que chamaremos de “Concílio da Paz”, que não será necessário adicionar o comentário mágico # frozen_string_literal: true, fiscalizado pelo cop Style/FrozenStringLiteralComment. Então podemos declarar o seu atributo como EnforcedStyle: never no arquivo .rubocop.yml de nosso projeto, colocando assim em nosso código as convenções definidas no “concílio”.

Edição do arquivo de configuração do RuboCop

Vamos agora executar novamente o comando rubocop no terminal e ver a saída?

Execução do comando rubocop

Percebemos que diminuiu consideravelmente a quantidade de ofensas.

Observação: Caso você tenha recebido no início da verificação alguma mensagem de alerta que inicie com:

“The following cops were added to RuboCop, but are not configured. Please set Enabled to either `true` or `false` in your `.rubocop.yml` file.”

Não se preocupe, trataremos disso logo assim que terminarmos de configurar o arquivo .rubocop.yml ok?

Vamos agora analisar o cop de métricas Metrics/BlockLength, no arquivo alerts_specs.rb, mas antes, na imagem abaixo, já podemos ver no terminal que ele diz que nesse arquivo há um bloco de código com 39 linhas, enquanto ele define que o padrão é 25.

Execução do comando rubocop

Observe na imagem abaixo, que o bloco contém mais de 25 linhas, padrão definido pelo Rubocop. Caso você esteja se perguntando, por que o Rubocop falou que há 39 linhas e na imagem há 47? Vamos aos números considerados pelo cop Metrics/BlockLength:

  • Total de linhas = 47
  • Total de linhas em branco (5, 13, 21, 29, 36 e 46) = 6
  • Início e fim do bloco (describe ‘Alert’ do e end respectivamente) = 2
  • 47–6–2 = 39. Compreendido? Adiante.
Arquivo alerts_spec.rb

Digamos que no “Concílio da Paz” promovido anteriormente pela sua equipe, o caso do código abaixo foi exposto e o dev 1 disse:

Acho que um bloco de código com 25 linhas é um tamanho suficiente no desenvolvimento de um sistema.

Então o dev 2 propôs o seguinte:

Concordo, contudo o código que temos abaixo trata-se de um bloco que descreve cenários de teste para um alerta, os quais podem aumentar de quantidade. Para os projetos de testes poderíamos deixar esse bloco maior?

Considerando o cenário exposto pelo dev 2, o dev 1 acatou a proposta. E colhendo assim os frutos do “Concílio da Paz”, vamos adicionar a configuração no cop Metrics/BlockLength com o atributo Max = 50.

Alteração de configuração do RuboCop

Vamos agora executar novamente o comando rubocop no terminal e ver a saída?

Execução do comando rubocop

Agora nosso projeto não contém mais nenhuma ofensa, segundo nosso RuboCop.

Ei, calma lá. E esse “moi” de mensagem amarela aê ??? Me explique o que é e ajeite isso seu peste !!!

Segundo o controle de versionamento do Rubocop, nas suas primeiras versões, sempre que eram lançadas novas atualizações os novos cops eram habilitados por padrão, resultando em quebra de compilações e problemas com CI.

Até a data da escrita do presente artigo, os novos cops são adicionados com status de pendente e enquanto houver algum cop nesse estado, sempre que o RuboCop for executado será exibido o alerta:

“The following cops were added to RuboCop, but are not configured. Please set Enabled to either `true` or `false` in your `.rubocop.yml` file.”

Para resolver esse problema, sua equipe pode analisá-lo um a um e definir seus atributos do arquivo .rubocop.yml (olha aí uma oportunidade para o “II Concílio da Paz”), ou podem adiar o concílio (o que seria uma pena) e simplesmente habilitar ou desabilitar a aplicação de novos cops através do atributo NewCops, do cop AllCops.

No nosso exemplo iremos desabilitar a validação de novas cops:

Alteração de configuração do RuboCop

Executando o rubocop enfim pela última vez neste artigo.

Execução do comando rubocop

--

--