Como eu parei de trabalhar e meu gestor ainda não sabe disso. Ou não sabia.
0
0

Como eu parei de trabalhar e meu gestor ainda não sabe disso. Ou não sabia.

Entrou no artigo achando que ia aprender algum hack para parar de trabalhar? Achou errado!

Caique
6 min
0
0

Como eu parei de trabalhar e meu gestor ainda não sabe disso. Ou não sabia.

Entrou no artigo achando que ia aprender algum hack para parar de trabalhar? Achou errado!

Mas posso te falar que codificar detectores e regras de Lint vão te ajudar a reduzir as dores de cabeças com problemas em code base extensas. Além disso, você pode terceirizar o processo de tech migration. Ou garantir que ninguém vá ferir padrões arquiteturais adotados pelo time. Ou garantir a sua sexta...

“Lint?”

Tá, muito de vocês devem estar pensando:

É o troço que pinta meu xml de amarelo ou que coloca cobrinha vermelha no meio do meu código.

Mas pera lá, Lint não é só isso. Na real, a ferramenta foi entregue com o compilador C e tinha como função ir além da análise estática que o compilador realizava. Bom, já o nosso lint foi nomeado em honra a essa nobre ferramenta, por ter salvo a sexta de inúmeros desenvolvedores.

Porém, para entendermos como funciona essa análise, vamos explorar um conjunto de definições, a fim de termos uma linguagem única quando se trata de lint.

Conceitos

Bom, na seção anterior, falamos que essa ferramenta tem como finalidade executar uma análise estática do seu código. Mas o que é isso? Simples, ele tem como fim verificar um dado escopo a fim de encontrar problemas. Cada um desses problemas é chamado de Issue.

O responsável por verificar um dado escopo é o Detector, além disso, ele também é responsável por reportar os incidentes. Incidentes são instâncias de uma Issue. 

Escopo, problema, instância, detector e incidentes. Todos os conceitos foram definidos, agora, iremos nos aprofundarmos em cada um deles, mas não na ordem apresentada acima.

Issue

Classe responsável por modelar algo que vai tirar a sua short-friday. Nela vamos ter metadados para realizarmos uma análise dos possíveis problemas que iremos encontrar no código e, a partir daí, tomar uma ação.

Criando uma Issue

Por convenção, uma Issue é declarada no Companion Object de seu Detector, dessa forma, podemos ter uma visão mais clara da responsabilidade desse objeto. Além disso, também, é uma boa prática adicionar nome aos argumentos da função

Tendo isso em mente, vamos definir o nosso primeiro BO:

Adicionar texto alternativo

Email image

Você pode ver que há uma série de atributos que o método create pede. Bora dar uma olhada em cada um deles, prometo que vai ser rápido.

  1. id é um identificador único para a nossa Issue.  
  2. briefDescription é uma descrição breve que vai ser colocada no cabeçalho do seu relatório. Todos os incidentes do mesmo tipo estarão agrupados nessa seção.
  3. explanation é uma descrição longa. Aqui a gente fala o motivo daquilo ser errado e o que o desenvolvedor deveria fazer para resolver o problema apontado.
  4. category outro nome bonito pra ID. 
  5. severity é o atributo que vai servir para identificar se o seu problema é um aviso ou um erro. Para cada tipo, a IDE e o build irá se comportar de alguma forma.
  6. moreInfo pode conter uma URL de uma wiki que contenha mais informações.
  7. implementation é a cola entre todos os dados anteriores, o detector e um dado escopo.

Com o nosso problema modelado em uma Issue, podemos nos concentrar na construção de nosso Detector.

Criando um Detector

Lembra de quando nós éramos pequenos e passava Hércules no SBT? Então, tá lembrado daqueles 12 trabalhos que o Hércules teve de fazer? Então, a tarefa de codificar o Detector é semelhante àquilo..

Mas para facilitar nossa vida, o Lint faz a busca por problemas de forma ordenada:

  1. Manifest;
  2. Resource files;
  3. Java sources;
  4. Java classes;
  5. Gradle files;
  6. Generic files;
  7. Proguard files;
  8. Property files.

Além dessa busca ordenada, há duas chamadas que possibilitam o setup, teardown ou report:

Email image

Na real, tem uma cacetada de função que o Detector te fornece para facilitar sua vida na hora de descobrir um problema. Você pode conferir todas acessando o link.

Bora botar tudo isso daqui em prática?

Email image

No exemplo anterior, utilizei um ResourceXmlDetector para facilitar a minha vida. Essa classe nada mais é que um Detector especializado para achar bucha em XML. Com ele, vamos ter acessos aos hooks:

1. getApplicableAttributes: Lista de atributos que vão ser analisados;

2. appliesTo: Indica se o Folder deve ser analisado;

3. visitAttribute : Te fornece o contexto do documento sendo analisado e o nó a ser examinado.

Mas como eu testo?

Dependências

Para verificarmos uma regra customizada de lint, devemos adicionar em nosso dependencies as seguintes dependências

Email image

LintDetectorTest

Para facilitar a escrita de um teste lint, a plataforma nos provê uma classe que provê alguns métodos para validar um Detector. A classe, em questão, é a LintDetectortask, a qual requer duas coisas:

  1. Definir um Detector;
  2. Definir quais Issues estarão sob teste.
Email image

Teste

Os passos para se criar um teste lint são:

  1.  Criar um TestLintTask;
  2.  Prover todos os TestsFiles que queremos testar. Eles servirão como os mocks de nossos XML ou classes Java/Kotlin;
  3.  Prover configurações necessárias para o setup do estado;
  4. Rodar a task;
  5.  Realizar assertions no TestLintResult.

Provendo um arquivo de test

Assim como em outros testes unitários, temos a utilização de mocks nesse tipo de teste. No caso de testes para verificação de uma regra lint, utilizamos o TestFile. Para prover esse arquivo basta:

Email image

Do trecho de código acima, podemos ver que a função xml possuí dois parâmetros:

  1. fileName
  2. fileContents

Provendo configurações adicionais

Podemos prover algumas configurações adicionais para nosso teste. Como, por exemplo, permitir que nossa execução não precise de um SDK instalado ou forçar que ele seja executado em um SDK específico. 

Você pode conferir a lista de configurações adicionais logo abaixo e para maiores detalhes, basta verificar o seu contrato:

  1. requireCompileSdk
  2. allowMissingSdk
  3. allowCompilationErrors
  4. allowDuplicates
  5. allowDelayedIssueRegistration
  6. allowNetworkAccess
  7. allowObsoleteLintChecks
  8. allowSystemErrors

Bora ver como ficou?

Chega de teoria!

Bora colocar nossa mão na massa e realizar um teste. Para isso, imagine que escrevemos um Detector que busca se há ou não valores de dimens hardcoded em nosso código xml, o XmlHardcodedDimensDetector.

Email image

E agora , José?

Tá, o artigo era só isso. Conseguimos salvar sua sexta-feira.

Brincadeiras a parte, a gente conseguiu ver como funciona o mundo por trás do Lint. Agora cabe a você e ao seu time implementarem regras que façam sentido ao seu contexto! Ah, não esquece de publicar elas no git para que a comunidade possa utilizá-las.

É claro que o exemplo utilizado é bem simples e não utiliza dos conceitos de UAST e PSI, má isso daqui é tipo prova. Você estuda X e cai Y. Porém, se você tem interesse em escrever algumas regras para Kotlin/Java, fideliza o like aqui no artigo.

Bibliografia

  • Improve your code with lint checks, Android Documentation, 24 de junho. de 2022. Disponível em:<https://developer.android.com/studio/write/lint>. Acesso em: 10 de julho de 2022.
  • Implementing yout first Android Lint Rule. Disponível em <https://proandroiddev.com/implementing-your-first-android-lint-rule-6e572383b292>. Acesso em: 09 de julho de 2022
  • Coding in style: Static analysis with Custom Lint Rules (Android Dev Summit '19) Disponível em <https://www.youtube.com/watch?v=jCmJWOkjbM0>. Acesso em: 10 de julho de 2022.
  • Photo by Craig Whitehead on Unsplash