Garantindo a Qualidade do seu Projeto

A seguir você encontrará um guia de ações a serem executadas para garantir a qualidade do seu projeto, além da motivação por trás de cada prática.

  • Informações essenciais

    • Expectativas
    • Equipe
    • Responsabilidades
  • Comunicação

    • Comunicação Síncrona
    • Comunicação Assíncrona
  • Arquitetura

    • Tecnologias
    • Infraestrutura
    • Segurança
  • CI/CD

    • Gestão de Configuração
    • Build
    • Setup
    • Execução de testes
    • Análise da qualidade do código
    • Análise de dependências
    • Ambientes
    • Releases
    • Deploys
    • Pipeline

Informações Essenciais

As informações básicas sobre o projeto são utilizados como uma forma de pré-análise. Munido dessas informações o time terá melhores condições de avaliar as necessidades, pontos críticos, impedimentos, ou mesmo pontos fortes para o projeto.

Expectativas

Outra prática importante para a saúde do projeto é o alinhamento de expectativas.

As duas palavras que mais causam tremores, até mesmo aos mais preparados, são prazo e escopo. Na verdade o perigo mora na combinação dessas duas coisas, por isso é importante que haja o alinhamento claro e franco sobre ambas logo no início do projeto. Assim será possível encontrar o mínimo denominador comum, entregando valor no timing.

Equipe

Um dos fatores mais importantes para o sucesso do projeto é a equipe. Ela tem quase a totalidade da responsabilidade pela especificação e execução do que é necessário para que o objetivo seja alcançado.

É fundamental definir logo no início qual será a composição do time. Essa decisão será pautada principalmente no escopo do projeto e nas qualificações das pessoas para executar o trabalho da forma mais eficiente.

Nesse momento também vale a pena levar em conta possíveis oportunidades de aprendizado, pois alguém que nunca teve a oportunidade de trabalhar nesse escopo, pode estar ávido a participar. Muitas vezes o interesse traz mais resultado que a experiência.

Responsabilidades

Além da composição da equipe é imprescindível definir as responsabilidades de cada integrante. Diferentes pessoas devem assumir diferentes papéis para que uma única pessoa não seja sobrecarregada com tarefas e responsabilidades além das adequadas, assim todos sabem seu papel e qual é a expectativa sobre sua participação.

As duas responsabilidades fundamentais a todos os integrantes de um time é compreender o projeto de forma completa e agir para que todas as dificuldades sejam superadas. Nada de cultivar o famigerado “esse é um problema de Front, Back, DevOps, etc.”. O mindset adequado é o de equipe, trabalhando juntos pelos objetivos comuns.

A interdisciplinaridade é uma das características mais fortes de times ágeis, pois proporciona a capacidade de analisar um problema por diferentes perspectivas.

Resumindo, todos devem sempre estar dispostos a botar a mão na massa para resolver problemas como um time!

Comunicação

Comunicação é a base das metodologias ágeis de desenvolvimento de software. Ela possibilita reduzir a burocracia e empoderar na tomada de decisão. O ponto fundamental é que todos os membros de uma equipe devem saber o status de todo o projeto, isso possibilita que decisões sejam tomadas em conjunto para priorizar atividades ou mudar de curso numa estratégia pouco efetiva. Cada membro do time devem ser capaz de manter sob controle as interdepêndencias com as outras partes do sistema. Para isso acontecer a comunicação franca e objetiva deve ser um objetivo comum e constante.

Comunicação Síncrona

Comunicação síncrona é a que demanda atenção imediata. Alguns exemplos são, discussões verbais e mensagens no canal do projeto no Slack, resumindo, qualquer tipo de discussão em tempo real.
Os pontos positivos da comunicação síncrona são, ser rápida, aumentar o engajamento e sensação de pertencimento do time. Por outro lado, isso tem um custo, a atenção dedicada à comunicação. Por isso, momentos como planning e dailies devem ser usados para maximizar o investimento de atenção. Dessa forma a necessidade por atenção durante outros períodos tende a ser reduzida, possibilitando maiores sessões de alta concentração. O que é muito importante, já que de forma geral trabalhamos solucionando problemas complexos. Outro ponto fraco da comunicação síncrona é sua efemeridade, algo que a comunicação assíncrona resolve muito bem.

Comunicação Assíncrona

Comunicação assíncrona é toda comunicação que não exige atenção imediata e é persistente. Alguns exemplos são, issues, commit messages e documentação, que possibilitam formas de comunicação persistente, contextuais e atemporais.
As issues são uma ótima forma de planejar em equipe, permitindo explorar ideias e comunicar problemas. Commit messages devem ser utilizadas para comunicar contexto junto ao código que é introduzido, tornando o entendimento muito mais fácil. Inclusive permitindo que problemas, do tipo, “mexi numa gambiarra, que tinha um motivo muito bom para existir, mas que ninguém contou, e estraguei tudo”, sejam evitados. Já a documentação é muito efetiva quando utilizada para registrar decisões importantes e motivos para alterações.
Ninguém mais quer ficar fazendo documentação extensiva, e nem é esse o caso, mas documentar pontos críticos ajuda a evitar problemas introduzidos por falta de contexto. As características mais importante da comunicação assíncrona são, o baixo custo de atenção, persistência da informação e contexto. Por isso, é uma ótima forma de comunicação para planejamento e longevidade dos projetos.

Arquitetura

A longevidade e a capacidade de evolução do projeto de software estão diretamente ligadas ao planejamento e organização. No desenvolvimento de software isso é comumente chamado arquitetura.

Seja ao escrever um pedaço de código ou ao interligar diferentes aplicações, arquitetar é trazer ordem ao caos, é criar condições para que diferentes hipóteses possam ser testadas ao longo de toda a vida útil do projeto, sem comprometer o todo.

Por isso é importante na fase inicial do projeto reservar tempo para pensar na arquitetura em diferentes camadas, deste a relação entre diferentes sistemas e aplicações, infraestrutura, tecnologias, etc.

Tecnologias

Uma boa escolha das tecnologias utilizadas para solucionar um problema pode alavancar o desenvolvimento ou enterrá-lo completamente. Quem nunca sofreu com uma escolha prematura de tecnologia que atire a primeira pedra. Por isso é importante haver consistência nas escolhas da stack tecnológica.

Evite escolher tecnologia desconhecida

Todos gostamos de experimentar coisas novas, mas a falta de domínio sobre uma ferramenta pode trazer efeitos colaterais catastróficos. Deixe as coisas exotéricas para momentos de pesquisa e estudos, esses momentos devem ser fomentados para que possamos nos desenvolver sem correr riscos. Na hora de colocar algo em produção tente manter o pé no chão, isso vai salvar muitas horas de sono, e não apenas as suas.

Decida o mais tarde possível

Essa dica parece ir contra o senso comum, pois temos a sensação de quanto antes definirmos alguma coisa menor será a chance de algo inesperado acontecer. Mas decidir por uma tecnologia cedo demais pode trazer vários tipos de problemas também.
O principal problema causado por uma decisão prematura é a dependência. Quando escolhemos uma ferramenta estamos criando uma espécie de acoplamento, por isso é importante arquitetar soluções o mais independentes possíveis, criando condições para incorporar tecnologias, sem depender demais delas. Pense que um banco de dados pode ser trocado, uma biblioteca pode ficar obsoleta, um serviço pode se tornar caro demais, e por aí vai.

Infraestrutura

Diferentes problemas exigem diferentes soluções, por isso é importante estabelecer o quanto antes a infraestrutura necessária para o software a ser desenvolvido. O objetivo é desde a primeira iteração do desenvolvimento garantir o ambiente o mais próximo do destino final. Isso é bastante crítico quando falamos de aplicações back-end, mas também é válido para apps mobile e front-end, pois existem diferentes dispositivos e browsers em que o app deverá rodar, dependendo da exigência do cliente ou do target user .

Com a infraestrutura definida, o processo de build e deploy pode ser automatizado, poupando muitas horas dos desenvolvedores, além de eliminar possíveis falhas humanas ao executar tais processos manualmente.

Para apps mobile e front isso também ajuda a definir os requisitos de teste, uma vez que sabe-se em quais devices e browsers deverá rodar.

Segurança

Segurança é sem dúvida fundamental para qualquer aplicação, além de algo que prezamos muito. Grande parte dos problemas de segurança estão envolvidos com mal gerenciamento de credencias e exposição desnecessária de informação. Por isso é imprescindível que haja desde cedo cuidado extensivo com a segurança.

A seguir estão os principais pontos a serem observados e praticados quanto a segurança. Mas segurança nunca é demais, então não limite-se ao que é sugerido aqui, sempre que possível atualize-se quanto aos padrões de segurança da informação, e caso queira complementar esse documento com mais dicas de segurança, sinta-se a vontade para fazer uma sugestão no projeto do Handbook.

Gerenciamento de credenciais

Trabalhamos com times ágeis, isso implica eficiência na comunicação e desburocratização, mas nem todos devem ter acesso a tudo, por isso cuide para que as credenciais de acesso a servidores, contas de Stores, chaves de criptografia, etc., sejam disponibilizadas apenas para quem precisa delas.

Idealmente, dados dessa natureza devem ser utilizados apenas durante o processo de setup do projeto, quando são configurados o CI, contas de Stores e coisas do tipo. Uma vez que tudo está no lugar, as credenciais devem ser guardadas sob um gerenciador de credenciais.

Dependências

Para evitar falhas de segurança causadas por terceiros é importante manter as dependências do projeto sempre atualizadas. É comum que falhas descobertas sejam rapidamente resolvidas em projetos open source, por isso mantenha-se informado sobre o estado dos projetos, serviços e APIs que você utiliza.

Comunicação entre aplicações

Aplicações são cada vez mais complexas, por isso nem tudo pode ser feito offline, assim precisamos integrar diferentes serviços e API’s para entregar valor aos nossos usuários. Isso torna a comunicação entre serviços um requisito fundamental inerente às aplicações. Por isso tome um tempo para discutir com o seu time qual é a melhor forma de integrar as diferentes aplicações de uma solução.

Os protocolos mais comuns encontrados em nossas aplicações são HTTP e WebSockets, além de diferentes protocolos de mensagens, como MQTT ou WAMP, por exemplo.
Cada um desses diferentes protocolos possuí diferentes requisitos de segurança, mas alguns cuidados são comuns a todos.

O item mais fundamental para a comunicação segura entre diferentes aplicações é a criptografia dos dados trafegados entre elas. Por isso garanta que seu projeto tem o necessário para lidar com a criptografia definida para o protocolo em uso, como o HTTPS por exemplos, ou alguma forma customizada de criptografia caso a a aplicação demande desse tipo de segurança.

Independente do protocolo de comunicação entre diferentes aplicações, precisamos sempre fornecer formas de garantir a segurança dos usuário. Por isso confiar em apenas uma senha pode não ser suficiente. Uma forma de fortalecer a segurança é valer-se de métodos de MFA(Multi-factor authentication).
Um protocolo bastante robusto, recomendado às suas aplicações é o U2F, um protocolo aberto de autenticação que simplifica e potencializa o MFA.

CI/CD

Produzir software é uma tarefa bastante complicada. Manter a qualidade e mesmo assim entregar o valor necessário no tempo certo torna-se cada vez mais um desafio para todo projeto. Por isso, precisamos de estratégias para minimizar o trabalho perigoso, o repetitivo, que não entrega valor e, além disso introduz pontos de falhas ao desenvolvimento.
Estratégias de CI/CD(Continuous Integration/Delivery) surgiram com o propósito de acabar com o trabalho perigoso, assim os desenvolvedores podem focar sua energia no trabalho que importa, o qual entrega valor e é divertido de fazer.

Consulte o handbook da sua Stack ou discuta com seu Stack Lead para descobrir qual é a forma adequada de implantar qualquer uma das etapas de CI/CD no seu projeto.

Gestão de Configuração

Configuração é sempre um ponto suscetível a falhas, uma simples variável pode causar grandes problemas quando configurada com o valor errado. Por isso é importante que toda informação necessária para configurar uma aplicação esteja sob controle e seja de fácil acesso. É ideal toda configuração que possa ser automatizada, seja, assim você elimina as chances de cometer algum erro fazendo isso manualmente. Seguindo as boas práticas de CI/CD você terá uma configuração íntegra e confiável. Além de reduzir drasticamente o chato trabalho de configurar tudo a cada build

Build

Build deve ser a segunda coisa mais chata para um desenvolvedor, logo após… Bem, na verdade deve ser a coisa mais chata, mesmo! Por isso, contar com um sistema automático de build, que além de poupar trabalho repetitivo e chato, também desafogará sua máquina para continuar trabalhando naquela feature mais interessante, que entrega mais valor ao usuário, é simplesmente Lindo!

Setup

O setup de um projeto pode ser bastante doloroso. Quanto maior o número de peças móveis e configuração necessária maior a dor para botar a coisa pra funcionar. Para facilitar o processo de onboarding de novos devs e principalmente o code review é imprescindível que o setup seja simples e rápido.

Execução de testes

Testes que não podem ser executados de forma rápida são inúteis. Uma das premissas do TDD é que você possa executar seus testes tão frequentemente quanto salva arquivos. O importante é ter o valioso feedback que os testes dão de forma rápida e prática toda vez que você faz uma alteração no código.

Claro que existem casos de testes que não podem ser executados tão rápido ou frequentemente, como os de integração ou de interface, mas mesmo esses não devem ser onerosos para serem executados, ou a tendência é que sejam abandonados.

Análise da qualidade do código

Nem todo reviewer tem olhos de águia para pegar problemas de estilo ou bugs semânticos. Por isso, análise de qualidade de código é muito importante, pois automatiza e potencializa a capacidade de encontramos problemas antes mesmo de integrarmos código à base.

Análise de dependências

As dependências de um software são possíveis pontos de falha. Por isso, é importante acompanhar de perto se elas estão em boa forma. Os principais aspectos para mantermos sob controle são, vulnerabilidades e compatibilidade.

Normalmente nos preocupamos em pesquisar os detalhes de uma dependência quando decidimos adicioná-la ao projeto, mas só isso não basta. É importante manter um olhar atento às dependências durante toda a vida de um software, assim podemos evitar que um problema originado numa dependência chegue em produção.

Ambientes

Diferentes ambientes causam diferentes problemas. Projetos que utilizam ambientes para organizar o processo de desenvolvimento, estão sujeitos aos mais diversos tipos de inconsistências, que podem ser causados desde uma variável errada até diferença no hardware. Seja no back-end com diferentes servidores, mobile com diferentes modelos de smartphones ou front-end com diferentes browsers, cada projeto tem que lidar com isso de um jeito ou de outro.
Por isso é importante mapear os diferentes ambientes em que a aplicação deverá funcionar, fazendo as adequações necessárias para garantir o correto funcionamento. Em casos aplicáveis, como projetos back-end, deve-se buscar manter os ambientes o mais semelhantes possível, para que a aplicação não precise lidar com isso desnecessariamente.

Releases

Controlar as mudanças num projeto de software pode ser uma tarefa árdua. Mas ter o controle do que está disponível em cada versão ajuda a encontrar problemas e a organizar dependências, sejam elas bibliotecas ou serviços. Por isso, é importante manter um histórico de releases com número de versão da sua aplicação, bem como dos serviços que ela depende.
Outro aspecto importante do versionamento é o planejamento das milestones, permitindo introduzir features e fixes na hora mais adequada à estratégia do projeto. Já o controle de versão das dependências evita problemas de incompatibilidade e integração, evitando sessões de debug desnecessárias.

Para saber como versionar sua aplicação consulte o handbook de versionamento.

Deploy

Já está pronto, agora só falta fazer o deploy. Esse tipo de situação não é mais aceitável para os padrões de desenvolvimento de software atuais. Uma feature só estará pronta quando entrar em produção, por isso é importante planeja o processo de deploy desde o início do seu desenvolvimento. Mesmo que a aplicação não seja disponibilizada para o usuário final, o processo de deploy deve ser utilizado em diferentes ambientes para teste e homologação, assim evitam-se as dores de cabeça na hora de botar uma nova versão em produção.

Pipeline

Manter o controle de cada etapa no desenvolvimento de software é um trabalho oneroso e chato. Por isso todas as boas práticas descritas anteriormente precisam ser orquestradas por um sistema de CI/CD. Para isso utilizaremos as pipelines do GitLab, elas permitem automatizar todas as ações necessárias para garantir que tudo saia como o planejado, além disso é uma ferramenta valiosa para acelerar a capacidade dos times de fazer code review, pois garante que o que deve ser revisado já está de acordo com os padrões de qualidade.