Logomarca com sobrancelhas, óculos e texto TM, com subtítulo Thales Menezes

20 Ago 2022 ~ 12 min read

O nascimento da Creche


Clique para ouvir esse artigo

Motivação do artigo

Recentemente finalizei uma versão estável de um compilado de ferramentas selecionadas ao longo de quase 2 anos testando com equipes de desenvolvimento, no formato de um modelo de repositório, mas ao compartilhar essa experiência com meus pares, apesar de acharem interessante e compartilharem da visão, viram como algo distante da realidade de seus projetos atuais, por conta do número de ferramentas ali presentes; então resolvi documentar o processo desde o começo, compartilhando os problemas que busquei solucionar com cada ferramenta e etapa do processo.

Era uma noite escura e tempestuosa

Em março de 2020, fui alocado na equipe de um aplicativo React Native, escrito em Javascript e baseado em uma API já construída; o aplicativo já havia sido iniciado, mas depois de algumas atualizações e excelente trabalho de meu colega, virou um projeto Expo atualizado com duas pastas de código legado, escritas utilizando classes e que ninguém queria mexer segundo o princípio “está funcionando, ninguém toca se não explode”.

Em outubro de 2020, me tornei o gerente desse mesmo projeto, mesmo com pouca ou nenhuma experiência prévia em gerência de equipes, comunicação com cliente e planejamento de metas para projetos de software, assumi a gerência com a saída de minha antecessora. A extensão das responsabilidades do cargo ao qual me refiro como gerente é tópico para discussão outro dia, o foco de meu artigo hoje é descrever os desafios que surgiram durante essa trajetória e ferramentas que me auxiliaram no processo, começando pela substituição quase completa da minha equipe de balanceado nível de experiência por recém-introduzidos ao mundo do desenvolvimento profissional.

E agora?

Passado o estado de negação inicial, o primeiro desafio era: como preservar a qualidade do código produzido por cada entrega com uma equipe com muito menos experiência? Primeira medida adotada foi uma postura de ditador benevolente, conhecida em alguns projetos.

Mas rapidamente essa postura se mostrou ineficiente, os principais problemas foram:

  • Longas horas: passei a pessoalmente verificar 100% do código submetido à produção, logo minha carga de trabalho foi multiplicada pelo número de desenvolvedores da equipe;
  • Corrida contra o tempo: caso demorasse a revisar uma tarefa relevante para a entrega da semana, possivelmente eu me tornaria responsável por completar as minhas tarefas e as que não conseguiria receber respostas a tempo dos desenvolvedores;
  • Documentação inconsistente: cada qual fazia commits e documentava código à sua maneira, escrevendo códigos autorais e, aumentava o trabalho de revisão por ter que “entrar na mente” de quem escreveu.

O fluxo de trabalho podia ser descrito nos passos:

1. Gerente delega tarefa a desenvolvedor;
2. Desenvolvedor escreve código;
3. Desenvolvedor faz commit das suas modificações;
4. Desenvolvedor sincroniza suas modificações com o repositório remoto;
5. Desenvolvedor abre Pull Request;
6. Desenvolvedor requisita revisão do gerente.

Esse fluxo de trabalho acabou criando um ambiente em que havia grande dependência das minhas revisões, às vezes com códigos que funcionavam parcialmente, famoso “conserta um lado e quebra o outro”. Então, busquei formas de aumentar o número de revisões que o código receberia, especialmente das partes “automatizáveis”, diminuindo o tempo entre a escrita do código “funcionando” e receber uma resposta de revisão, utilizando automações e definindo padrões a serem seguidos, porque quanto menor esse tempo, mais forte a associação de causa e consequência, se formos entrar no campo de estudos de metodologias de ensino.

Filtrando Fiapos

O momento de quebra da inércia é o mais memorável do processo; o primeiro problema que resolvi atacar foi em relação aos códigos autorais, forçando estabelecendo um formato único de escrita.

Prettier

O Prettier é um formatador de código opinado, suas configurações padrões já trazem um formato que cumpre o objetivo que buscava, contudo, ele permite modificar suas regras através de um arquivo de configuração. Também instrui aos desenvolvedores utilizarem a extensão do Prettier para seu editor de código preferido, para que durante a escrita do código ele já fosse sendo formatado a cada salvamento do arquivo.

Configuração VSCode

Extensão VSCode Prettier, de Esben Petersen @ Prettier

/* settings.json */
{
  // Configura o comportamento quando editando arquivos javascript
  "[javascript]": {
    // Formatador Padrão
    "editor.defaultFormatter": "esbenp.prettier-vscode"
    // Formatar arquivos ao salvar
    "editor.formatOnSave": true
  },
}

Mas, apesar de padronizado, ainda havia uma forte dependência na capacidade de os desenvolvedores e eu detectarmos erros que impediriam a execução do código. Descobri haver a necessidade de um linter, como diz a própria documentação do Prettier, em tradução livre, “use o Prettier para formatação e linters para capturar bugs!“.

O termo lint veio da indústria têxtil, se referindo aos pequenos pedaços de tecido que saem nas lavagens e secagens da roupa, a ideia é que os linters atuassem para o mundo de software como um filtro de bugs, semelhante às máquinas filtrando fiapos.

ESLint

Através de análise estática do código é possível detectar erros que impediriam sua execução ou, em configurações mais avançadas, avaliar complexidade e ortografia; o Prettier possui documentação sobre integração com linters, permitindo que não mais precisemos invocar as 2 ferramentas, somente o ESLint.

Eu configurei meu editor de texto para salvar automaticamente a cada 3 segundos ocioso e Ctrl+S como atalho do formatador de código

Configuração VSCode

Extensão VSCode ESLint, de Dirk Bäumer @ Microsoft

/* settings.json */
{
  // Habilita ESLint como Formatador do VSCode
  "eslint.format.enable": true,
  // Lista de linguagens a serem validadas
  "eslint.validate": [
    "javascript",
    "javascriptreact"
  ],
  // Configura o comportamento quando editando arquivos javascript
  "[javascript]": {
    // Formatador Padrão
    "editor.defaultFormatter": "dbaeumer.vscode-eslint",
    // Formatar arquivos ao salvar
    "editor.formatOnSave": true
    // Ações executadas ao salvar
    "editor.codeActionsOnSave": {
      // Executar todos os consertos automáticos do ESLint
      "source.fixAll.eslint": true
    },
  },
}

Com isso, havia se estabelecido a primeira camada de revisão automatizada, mas só seria eficaz caso os desenvolvedores tivessem a iniciativa de configurar seus ambientes com as extensões sugeridas ou tivessem a disciplina de executar as ferramentas manualmente; confiante na preguiça inerente ao engenheiro de software, resolvi ir mais fundo.

Todos usamos Git

Mesmo os mais indisciplinados, eventualmente haviam de fazer um commit, push e pull request para submeter suas alterações, então resolvi fazer uso desses eventos como gatilhos das automações, forçando induzindo a aplicação dos padrões estabelecidos.

🐶 Husky

Quem é um bom garoto? Quem conseguiria te ignorar?

O husky chegou para ser o cão de guarda, farejador de bugs, impedindo que os desenvolvedores ignorem as regras e mandem suas atualizações sem validar antes em ambiente local, executando as validações configuradas nas seções anteriores seguindo os eventos do git. Ele também modifica o caminho padrão dos git hooks para uma nova pasta que pode compor a sua base de código, facilitando o uso e manutenção dos scripts sem grandes preocupações de configuração por parte dos contribuidores.

O que são git hooks?

Scripts acionados quando ações importantes acontecem.

git commit
git push
Como ele faz isso?

Segundo a documentação dos Git Hooks, em tradução livre

Para habilitar um hook script, ponha um arquivo no subdiretório .git/hooks o qual está nomeado apropriadamente (sem extensões) e é executável.

E o caminho que esses comandos se encontram pode ser configurado, a documentação pode ser traduzida livremente da seguinte forma

git config core.hooksPath <new-path>
core.hooksPath
    Por padrão, Git buscará por seus hooks no diretório
    $GIT_DIR/hooks. Configurando para um caminho diferente, ex.
    /etc/git/hooks, e Git vai tentar encontrar seus hooks nesse
    diretório, ex. /etc/git/hooks/pre-receive ao invés de
    $GIT_DIR/hooks/pre-receive

Contudo, para uma adesão incremental de padrões de projeto, o ideal é validar e apresentar erros dos arquivos que estão sendo modificados no commit.

🚫💩 LintStaged

Uma ferramenta muito poderosa, permitindo não só a seleção dos arquivos modificados no commit, como:

  • Executar validações diferentes dependendo da extensão ou nome do arquivo, utilizando expressões regulares;
  • Validação de arquivos parcialmente em stage, ou seja, quando existem mais modificações no arquivo que não foram selecionadas no commit elas são empilhadas, as validações são executadas e as modificações são recuperadas automaticamente.
Configuração
// .lintstagedrc.json
{
  "*.js": "npx eslint --fix",
}
npx husky add .husky/pre-commit 'npx lint-staged'

Agora temos garantia de um histórico com código bem formatado, mas o histórico é legível? Observar o log do git seria simples e traria informações úteis? Essa é a próxima pergunta que busquei respostas.

A guerra contra o git commit -m "consertei"

Padrões de Commit

Assim que busquei o assunto, encontrei o guia de contribuição do Angular, apesar do foco em geração automatizada de registro das mudanças entre versões, vi que ali havia um formato que poderíamos experimentar seguir. Mas, como sabemos da confiável e constante preguiça inerente ao engenheiro de software, especialmente em situações de pressão, eu sabia que as mensagens de commit poderiam ser alvo do maior número de desculpas: “é urgente”, “depois arrumo”, “foram mudanças triviais”.

Quantas vezes você já revisou mensagens de commits antigas, especialmente depois que foram enviadas à produção?

Por essas e outras, veio a regra imposta que gerou o maior atrito em adaptação da equipe vigente.

Commitlint

Configurado para os padrões de commits estabelecidos pela equipe do Angular, e adicionado o git hook commit-msg, aqui foi onde houve a maior barreira de adesão por parte dos desenvolvedores; a experiência me levou a buscar formas de simplificar a escrita de commits, como um tutorial.

Commitzen

A salvação do onboarding, aqui escolhi não por o git hook por questões de compatibilidade com a extensão do controle de código-fonte do VSCode, editor usado pela maioria da equipe; com ambas ferramentas, era possível que os mais inexperientes no formato pudessem ser guiados a escrever uma mensagem que passasse na validação, enquanto os ousados pudessem escrever com velocidade e ser avisados em casos de erros.

Recentemente descobri o cz-git, que propõe a unificação da configuração de ambas ferramentas, evitando a duplicação de regras de commits.

Tudo parece bem até o momento correto? Mas ainda existe uma brecha ou caso a ser considerado: e aqueles que por quaisquer motivos desabilitem essas verificações no ambiente local? O ideal seria evitar que o gerente que baixar a branch remota para validar localmente o código e commits. Felizmente, havia uma solução simples o suficiente.

Todos usamos GitHub 🤷

Estávamos todos usando o GitHub como plataforma, após uma transição do Gitlab na empresa, e a sintaxe dos fluxos de trabalho do GitHub era ainda mais simples que a do Gitlab; também já haviam todas as dependências e comandos de validação prontos em ambiente local.

A transição foi, além de natural, extremamente rápida. Adicionei 2 fluxos de trabalho que passaram a virar pré requisito para minha revisão.

Se não passar no Lint e Deploy, ainda não está pronto para revisão

Deploy? Isso é novidade

Por usarmos Expo, o lançamento de atualizações era feito com um comando que demorava em torno de 8 minutos para ser concluído e a atualização estar disponível para os clientes. Quando tive meu primeiro contato com os fluxos de trabalho do GitHub, já visualizei o tempo que eu ganharia colocando deploys automáticos toda vez que o código da main era atualizado.

O que mudou até agora?

 1. Gerente delega tarefa a desenvolvedor;
-2. Desenvolvedor escreve código;
+2. Desenvolvedor escreve código que é automaticamente formatado e validado;
 3. Desenvolvedor faz commit das suas modificações;
+  3.1 Validações pré commit são executadas;
+  3.2 Desenvolvedor escreve mensagem de commit;
+  3.3 Validação da mensagem de commit executada;
+  3.4 Commit salvo;
 4. Desenvolvedor sincroniza suas modificações com o repositório remoto;
 5. Desenvolvedor abre Pull Request;
-6. Desenvolvedor requisita revisão do gerente.
+6. Aguarda CI/CD com resultados positivos;
+7. Desenvolvedor requisita revisão do gerente.

Diferenças sutis, mas tão significativas que trouxeram um aumento de produtividade significativo para os desenvolvedores e diminuíram a carga de trabalho inicial de revisão, ou seja, dá pro gasto por um tempinho.

Por que creche?

O nome veio da ideia de criar um ambiente para que os recém-introduzidos ao mundo da programação profissional pudessem se desenvolver de forma segura, um ambiente que incentivasse experimentação; e, quando fossem ganhando mais experiência, se tornasse uma rede de segurança, garantindo que o padrão do produto sendo construído não quebraria a barreira de qualidade mínima esperada.

Faz sentido, dado o que viu até agora?

FIM?

O panorama do projeto antes dessas ferramentas podia ser descrito como nebuloso: não havia certeza além do que era testado manualmente e a qualidade era garantida pela experiência dos envolvidos. Com o advento de ferramentas e processos, passou a existir uma documentação, garantias da evolução e qualidade do código escrito, criando alguns traumas e experiências engraçadas no caminho, mas nenhuma história que não combinasse com o nome creche.

Ainda houveram mais dores e melhorias feitas gradualmente a esse fluxo de trabalho, mas espero com esse artigo ter mostrado que não é necessário almejar a implantação da creche 3.0 para se ter um impacto positivo no seu dia a dia.

Busque solucionar as dores que você tem na sua equipe, seja gerente ou desenvolvedor, tome essa iniciativa de buscar por mais qualidade e facilidade no seu trabalho; somente aqueles que vivem a realidade da equipe podem customizar as soluções aos problemas, encare esse material não só uma lista a ser seguida cegamente, mas como um retrato de um processo de solução de problemas.

Vá, pesquise e tire suas próprias conclusões, por hoje é só.


Headshot of Maxi Ferreira

Olá, sou Thales Menezes, quase cientista da computação, empresário, pós junior, gerente e desenvolvedor. Apaixonado por padrões de projeto, backend e ensinar. Dá uma olhada no GitHub e LinkedIn para saber o que tenho inovado.