Débito técnico em uma startup: quando, como e por que? - Ship It!
Primeiro, independente da fase da empresa, temos que tomar alguns cuidados em relação ao débito e ao processo como um todo.
O primeiro cuidado é não confundir débito técnico com bagunça. Criar arquiteturas ruins e fazer código sujo por desconhecimento não é o mesmo que escolher conscientemente um caminho mais rápido.
Outro ponto crucial é o uso de testes automatizados. Sem testes você não terá segurança para refatorar o código no futuro – e nem vai saber se ele está funcionando no presente. Nunca pule os testes! Repito, nunca pule os testes! Eles vão evitar muitas horas extras e noites em claro.
Além disso, sempre é bom contar com ferramentas que minimizem o erro humano, como integração contínua, análise de qualidade de código, análise de cobertura e deploy automatizado. Aqui na RD utilizamos o Circle CI e o Code Climate integrados com o GitHub e deploy via chat. Todo novo pull request é analisado automaticamente. Caso haja testes falhando ou a qualidade do código tenha caído, o robô de deploy, também chamado de Capybot, se recusa a colocar o código no ar.
Essas ferramentas ajudam muito a forçar a tomada de decisão, mas de forma alguma substituem um bom programador.
Antes do "product-market fit" o principal objetivo deve ser validar o modelo de negócio. Nessa fase é muito importante lançar o MVP do produto o mais rápido possível. E dependendo do negócio, o MVP pode ser grande (como no caso do RD Station, que oferece como um dos principais valores ser uma plataforma integrada).
Aqui um pouco de débito técnico pode valer a pena, desde que seja consciente e justificado. O que ajuda muito nessa fase é ter programadores bons e experientes, que só vão tomar um atalho se realmente for necessário. Por exemplo, já vi muita gente pulando os testes porque não tinha experiência em TDD e testes automatizados.
Depois de validado o modelo de negócio, começa o crescimento. O principal objetivo técnico aqui é continuar acrescentando funcionalidades e melhorando as existentes sem aumentar a complexidade do código. Queremos evitar aquele cenário comum em sistemas antigos, em que qualquer mudança começa a ficar tão cara que é melhor reescrever tudo.
Nessa fase vamos ter que começar a matar alguns débitos técnicos da fase anterior. Provavelmente haverá áreas do sistema que estão com problemas de performance, áreas com arquiteturas muito rígidas que impedem mudanças e áreas de código simplesmente fedido.
E como arrumar isso? Dificilmente teremos tempo para um grande refactoring de qualidade. Estaríamos parando de gerar valor para o cliente, o que é ruim para qualquer empresa, e para uma startup é ainda pior.
O que fazer então? Aqui na RD temos atacado os débitos que estão afetando diretamente os clientes (ex: problemas de performance) ou que estão dificultando mudanças em funcionalidades ou a criação de novas. Em um nível mais micro, adotamos a regra do escoteiro aplicada ao código: "sempre deixar o código um pouco melhor do que ele estava quando começou a mexer". Por fim, atacamos também as classes que estejam com a qualidade ruim e que tenham uma taxa de modificação muito alta (grande potencial de introduzir bugs), de acordo com o gráfico de qualidade versus churn do Code Climate:
Também precisamos ser mais exigentes com novas funcionalidades. Algumas coisas que temos feito: discutir arquiteturas de funcionalidades grandes com mais pessoas, revisão rigorosa de pull requests (nosso fluxo de desenvolvimento é tema para um próximo post), envolvimento do time de performance e operação e envolvimento do QA.
Por que ter todo esse trabalho no futuro, se já poderíamos "fazer direito" desde o início? Por dois motivos:
Primeiro: é difícil saber quais áreas do sistema vão mudar mais. É preciso se preocupar com extensibilidade, mas programar para o presente, se não corremos o risco de gastar tempo e recursos a toa.
Segundo: no início de uma startup o tempo é mais importante. Se você demorar demais para lançar seu produto, pode estar gastando recursos em algo que não tem mercado.