Aqueles que trabalham, trabalharam comigo ou me acompanham sabem que gosto de automatizar o máximo possível e que odeio soluções complexas para problemas simples. Sabem que tenho aversão ao ecossistema nodejs e fujo de qualquer projeto que me peça para executar npm como o diabo foge da cruz, e o ecossistema Python quase segue pelo mesmo caminho! Enquanto utilizador, eu não quero saber das dependências: quero instalar a aplicação pelo gestor de pacotes e quero que funcione; no limite, quero agarrar no binário da aplicação e executá-lo, e se conseguir evitar a utilização de ficheiros de configuração, ainda melhor! Já vos tinha dito que sou preguiçoso? Se não, ficam a saber! Quero que as ferramentas sejam simples, façam o que têm de fazer e pronto! Óbvio que, em alguns casos, isto nem sempre é possível, mas esses são a exceção, não a regra.

Ninguem quer pensar!

Prontos para me “lerem” a resmungar? Em qualquer projeto que faça sentido, a primeira coisa que adiciono é o versionamento automático. Para tal, sigo algumas regras:

  • a primeira: todos os meus projetos seguem o versionamento semântico, ou semver; deste modo, há clareza sobre o que acontece em cada versão!
  • A segunda: commits convencionais; assim, cada commit tem mensagens com significado e está diretamente relacionado com o versionamento!

Estas duas regras simples, combinadas com ferramentas como go-semantic-release, permitem não só versionar, como também criar releases e release notes de uma só vez! Tudo de forma automática: comunicação, transparência e significado! Git commit > Git push e voilà! Poucos minutos depois, tenho uma release, com release notes, imagens Docker, binários – tudo aquilo que faz falta para tornar a vida mais fácil, não só a mim, como criador de ferramentas, mas também a qualquer utilizador que faça uso delas! Sim… sim… já vos estou a ouvir a apontar o dedo aos vários problemas do semver e dos commits convencionais; sim, estou bem a par! Mas querem uma série de opiniões não populares? Sabem porque é que não gostam de ambos?

Porque vos obriga a pensar antes de fazer alguma coisa!

Porque, das duas uma: ou alguém faz esse trabalho por vocês manualmente, e já está “manualmente automatizado”, como gosto de lhe chamar; ou porque acham que se sentem valiosos e indispensáveis por serem os detentores do conhecimento das releases e do versionamento, e que é um trabalho demasiado importante para ser feito por uma máquina! Sabem que mais? Já lá vão 20 anos a automatizar merdas, e continuo com trabalho; continuo a ser dispensável com ou sem conhecimento, a vida segue em frente sem vocês. Por isso, quanto mais automatizarem, mais tempo têm para coisas fixes! Sabem porque é que gosto tanto de combinar ambos? Pelas mesmas razões que vocês não gostam! Porque sou obrigado a segmentar o meu trabalho: se estou a trabalhar na funcionalidade X, não vou fazer o refactor da função Z que só afeta a funcionalidade Y! Sim… só tira um minuto ou dois; logo, esse minuto ou dois podem ser tratados mais tarde. Adiciono às minhas notas e, quando acabo a funcionalidade X, então adiciono o refactor da função Z, e deste modo é bem claro tudo o que fiz! Sou obrigado a trabalhar de trás para a frente, com os meus utilizadores em mente! Nada me aborrece mais do que atualizar uma aplicação que supostamente segue semver, adiciona uma funcionalidade, incrementa a versão menor e, no final, deixa de funcionar porque alteraram a API de forma incompatível, ou mudaram um comportamento sem documentar ou informar! Assim, penso duas vezes antes de quebrar comportamentos ou APIs; e se tiver de o fazer, não tenho problema nenhum, pois será devidamente comunicado nos commits, no versionamento e nas release notes! Mundo maravilhoso, certo? Quantos problemas são resolvidos aqui apenas por se seguirem duas regras simples? No fim, estas duas regras tornaram-me um melhor profissional. Mas, como não podia deixar de ser, a seguir a uma solução vem sempre outro problema!

O mundo em que vivemos

Da mesma forma que ninguém quer pensar, ninguém quer ler documentação. README? O que é isso? Regras de contribuição? Então, mas agora tenho de seguir regras para fazer commits no Git? Estou a fazer-te um favor ao contribuir para o teu projeto e ainda tenho de seguir regras? Releases? Release notes? Alguém há de fazer. Acho muito giro que existam, enquanto utilizador, mas isso não é para eu me preocupar! A maior parte dos contribuidores gosta de ver tudo a acontecer de forma automática; a maior parte dos programadores só quer abrir o seu editor, fazer as alterações que quer, como quer, sem rei nem roque, git commit -m "Arrangei esta merda que não funcionava!", git push e siga caminho, que é o que é bom! Quem vier atrás que feche a porta, ainda que sejam eles os mais beneficiados por seguir regras simples.

Ferramentas complexas para problemas simples

Por todas estas razões, decidi procurar um linter para os commits. Não segues as regras? Nem olho para a tua pull request! Quando tiver as bolinhas todas verdes, logo me preocupo em olhar! Mas, para variar, tal como acontece com os commits convencionais, estão também documentadas várias ferramentas relacionadas, e nem uma única que se dedique a ser simplesmente… simples! Não quero entrar em detalhes, pois cada projeto nesta lista foi feito com o intuito de resolver os problemas de quem os criou (que talvez nem eu entenda bem). Dito isto: NPM? Não, obrigado. Python? Não, obrigado. PHP? Passo! Go, sim por vafor! No entanto, não consegui entender nenhuma das opções (skill issues?). Outras fazem outro tipo de tarefas, como releases e release notes, mas nenhuma se dedica a ser simplesmente um linter! Correr localmente ou num ambiente de CI e avisar que os commits não estão em ordem, antes sequer de se tentar lançar uma nova versão. Que possa correr numa pull request e notificar que os commits não estão de acordo com as regras… E por isso, mais uma vez, decidi arregaçar as mangas e criei o convcommitlint.

Convcommitlint

O convcommitlint dedica-se a ser apenas isso: simples! Um linter que pode correr localmente ou num ambiente de CI, que se foca única e exclusivamente nos princípios básicos dos commits convencionais. Como não podia deixar de ser, escrito em Go, permite produzir apenas um binário que pode ser descarregado em qualquer ambiente e executado para fazer a sua tarefa: se os commits não seguirem as regras dos commits convencionais, imprime os erros e termina com código de saída 1; se não houver erros, simplesmente não diz nada. Obviamente, adicionei mais uns perlimpimpins, por exemplo, uma GitHub Action que pode ser integrada em qualquer workflow com apenas uma linha: uses: coolapso/convcommitlint@v0. Por defeito, simplesmente funciona e faz o que tem a fazer: não há configurações necessárias, não há regras a serem definidas, nem ficheiros de configuração. E não! Não quero, nem vou, suportar todos os casos e diferentes variantes de commits convencionais; foco-me apenas no essencial, mas sem sacrificar a flexibilidade. Todos os interruptores da aplicação CLI são também acompanhados de variáveis de ambiente que podem ser utilizadas para ligar/desligar funcionalidades, seja localmente ou no ambiente de CI. Não querem validar pull requests? Só têm de desativar a funcionalidade com o interruptor ou variável de ambiente. Simples! Não é preciso agradar a gregos e a troianos; às vezes, chega ser só isso: pequeno e simples!

No fundo, convcommitlint é o meu modesto contributo para um ecossistema de desenvolvimento um pouco menos caótico e, quem sabe, mais produtivo. Pode não ser a solução para todos os males, nem pretende agradar a gregos e troianos, mas se conseguir que alguns programadores pensem duas vezes antes de complicar o que pode ser simples, ou antes de ignorar regras que beneficiam todos, então a minha ‘birra’ e o esforço já valeram a pena. Afinal, o objetivo é que as coisas funcionem, de preferência sem que tenhamos de arrancar os cabelos no processo.