acúmulo de dívida técnica

Débito Técnico Não Existe: Jogando no Futuro Problemas!

É comum, durante uma planning ou refining, que a equipe receba uma data impossível de cumprir. Nesse caso, uma decisão é tomada em conjunto: abrir mão de certos requisitos de qualidade e automaticamente contrair débitos técnico.

Na situação descrita, há vários problemas ocorrendo ao mesmo tempo. Vou abordar alguns deles, sem me aprofundar em questões mais complexas. O que vou apresentar aqui servirá como um aprimoramento geral, embora seja especialmente relevante para alguns casos específicos.

O primeiro ponto é sobre a pressão.

“Mas, Manoel, é uma ordem de cima e precisa ser feito de qualquer jeito, e não há tempo suficiente para implementar.” E eu respondo: certo, vamos lá, onde está a maior dificuldade?

  • O código até é bom, mas a solicitação é complexa. Vamos abrir mão de pensar em um design eficiente por conta da pressão do tempo.
  • Ninguém do time tem domínio do negócio.
  • O código difícil de ler e manter, complexo e “macarronoso”.
  • O prazo é inviável.

Tempo inviável

Muitas vezes, o primeiro desafio não é resolver um problema, mas reconhecê-lo corretamente. Em alguns casos, um prazo pode parecer inviável simplesmente por falta de informação ou experiência — uma dificuldade que pode ser superada com melhor planejamento e compreensão do escopo. Em outros, o prazo é de fato impossível, exigindo ajustes de rota. No entanto, mesmo quando essa inviabilidade é reconhecida, a reação instintiva pode ser buscar soluções que parecem intuitivas, mas acabam prejudicando mais do que ajudando.

Uma resposta comum é contratar mais pessoas ou trazer alguém de outro time para ajudar. Porém, essa abordagem pode gerar novos desafios, como tempo de adaptação, redistribuição de responsabilidades e até um efeito negativo no desempenho da equipe. Esse fenômeno é discutido na Maldição do Conhecimento (Birch & Bloom, 2007), que mostra como aqueles que já compreendem um problema tendem a subestimar a dificuldade que outros terão para acompanhá-los. Assim, inserir novos membros em um time sob pressão pode gerar mais confusão do que alívio. Em vez de uma solução rápida, é essencial avaliar se a ação tomada realmente alinha-se com a resolução do problema ou apenas mascara a urgência da situação.

O problema é que isso não resolve o dilema de que juntar nove mulheres grávidas não vai resultar em um bebê em um mês. O fator “novo” traz diversos desafios: curva de aprendizado, necessidade de acesso a informações e integração com o time. Por isso, é natural que o desempenho da equipe caia no início, antes de voltar a se estabilizar e performar bem. Dependendo da situação, especialmente em relação a uma entrega urgente, a chegada de alguém novo pode acabar atrapalhando mais do que ajudando.

Esse fenômeno é bem explicado pela Lei de Brooks, proposta por Fred Brooks em seu livro The Mythical Man-MonthA lei afirma que “adicionar pessoas a um projeto de software atrasado apenas o atrasará ainda mais.” Isso ocorre porque, além do tempo necessário para que o novo integrante se integre à equipe e entenda os processos e sistemas existentes, ele também precisa ser treinado e frequentemente acompanhado. Como resultado, os membros atuais da equipe têm que gastar tempo para ajudar na integração do novo, o que, em um primeiro momento, reduz a produtividade geral.

Além disso, a Lei de Brooks sugere que o aumento de pessoal em um projeto frequentemente leva a comunicação mais complexa e mais propensa a erros, o que pode tornar o desenvolvimento mais desorganizado e dificultar a entrega dentro do prazo.

Outra solução comum é recorrer às horas extras. No entanto, isso leva a uma queda no desempenho devido ao cansaço, desânimo por causa do trabalho excessivo e estresse constante.

Não existe almoço grátis. Sempre há uma escolha a ser feita, com seus trade-offs. Um gestor eficiente precisa saber tomar a melhor decisão dentro desse contexto.

Um código de baixa qualidade

Em poucos projetos pelos quais passei, o código realmente recebeu cuidados com o design, a estrutura e a escrita, levando em consideração a facilidade de leitura. Isso, geralmente, é a base dos problemas, e os outros pontos mencionados acabam apenas agravando a situação.

Vamos primeiro entender a diferença entre “difícil de entender” e “complexo”. Embora pareçam significar a mesma coisa, não são.

Um código complexo, de forma simplificada para facilitar o entendimento, é aquele que possui muitos elementos integrados. Se uma classe A interage com uma classe B, temos um nível de complexidade. Se a classe A interage com B e C, então temos um grau maior de complexidade. Portanto, cada novo elemento que integrarmos para resolver um problema aumenta a complexidade do código.

Observando as leis de Lehman, a primeira e a segunda leis falam exatamente sobre o problema da necessidade de mudanças contínuas e o aumento da complexidade. Quando essas mudanças não são feitas de maneira adequada, com expertise e qualidade, entra em cena a sétima lei, que trata do declínio da qualidade do sistema.

Já um código “difícil de entender” indica que ele é de baixa qualidade, difícil de ler, sem organização ou padrão. É quando você percebe que o código está bagunçado.

Aqui, é importante distinguir entre “bagunçado” e “desorganizado”:

  • Desorganizado é quando não há um padrão claro a seguir, não se sabe onde colocar cada coisa.
  • Bagunçado é quando existe um padrão, mas o profissional é relaxado o suficiente para não seguir essas diretrizes e acaba deixando as coisas fora do lugar.

A solução aqui é clara: o time precisa adquirir maturidade técnica para escrever com qualidade, estabelecer padrões e ter expertise em refatoração e gestão do roadmap. Caso contrário, o problema só se agravará.

Há também aquele desejo de todo desenvolvedor de, em algum momento, refazer um sistema do zero. Isso até faz sentido a priori, então vou compartilhar um cenário que vivi:

Enquanto arquiteto de soluções em uma das empresas em que trabalhei, conversando com um tech lead, ele sugeriu refazer um sistema do zero. O curioso é que já havia um histórico no time de um serviço que havia sido refeito do zero há pouco tempo. Esse novo sistema foi dado como “entregue” ao negócio, com a informação de que estava em produção. No entanto, ele não estava sendo de fato usado em produção; o serviço antigo ainda estava operando e sofrendo manutenção corretiva, pois o novo serviço estava mais complexo e difícil de expandir com novas funcionalidades e corrigir problemas do que o sistema original. Minha resposta foi clara: “Se o time não amadurecer, só vamos repetir os mesmos erros.”

“Uma bagunça não é uma dívida técnica. Uma bagunça é apenas uma bagunça. As decisões de dívida técnica são feitas com base em restrições reais do projeto. Elas são arriscadas, mas podem ser benéficas. A decisão de fazer uma bagunça nunca é racional, é sempre baseada em preguiça e falta de profissionalismo, e não tem chance de se pagar no futuro. Uma bagunça é sempre uma perda.” – Uncle Bob

Ninguém do time tem domínio do negócio

Este pode ser um dos problemas mais simples de resolver, mas frequentemente é cercado de muito medo, o que torna a situação emocionalmente mais complexa. Quando esse tipo de questão surge, muitas vezes não é tratada de forma totalmente racional. O medo do desconhecido, a falta de familiaridade com o contexto e as necessidades do negócio. Gera estimativas irracionais, frequentemente exageradas, sobre a dificuldade das tarefas ou a complexidade das soluções necessárias. Esse medo, embora legítimo, acaba sendo um dos maiores obstáculos para a resolução do problema.

Quando a equipe não possui um domínio sólido sobre o negócio em que está inserida, a capacidade de realizar estimativas precisas de tempo, esforço e recursos fica seriamente comprometida. Sem esse entendimento, decisões apressadas e mal fundamentadas são tomadas com frequência. Muitas vezes, as soluções escolhidas se tornam mais complexas do que o necessário, ou atalhos são adotados para cumprir prazos, com o objetivo de minimizar a sensação de incerteza ou falta de controle.

Essas escolhas inadequadas acabam gerando débitos técnico. Por exemplo, uma estimativa equivocada pode resultar em código que não é facilmente adaptável às mudanças nas necessidades do negócio, criando áreas do sistema que são difíceis de manter e expandir. Com o tempo, essas áreas tornam-se um passivo crescente que requer cada vez mais tempo e esforço para ser resolvido. O que inicialmente poderia ser uma simples refatoração, no futuro, devido à falta de um bom entendimento do negócio, acaba se tornando uma grande reestruturação, o que impacta diretamente no tempo e nos recursos da equipe.

Como mencionado em “The Phoenix Project”:
“Sem entender o negócio, acabamos resolvendo os problemas errados. E essa é a causa raiz da dívida técnica.” – Gene Kim, Kevin Behr, George Spafford

Além disso, para construir um sistema que realmente atenda às necessidades do negócio, é fundamental que a equipe entenda esses problemas e saiba traduzi-los em soluções técnicas que sejam não apenas eficazes, mas também sustentáveis. “Para construir um sistema de sucesso, devemos entender os problemas do negócio e traduzi-los em soluções técnicas que sejam fáceis de manter e evoluir.” – Jez Humble, David Farley, Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation

Uma solução simples, mas inadequada, seria definir uma data arbitrária para a entrega do projeto. Embora isso possa parecer uma maneira de forçar a equipe a se organizar, é uma prática que demonstra falta de maturidade e planejamento adequado. Essa abordagem ignora o contexto e o tempo necessários para se alinhar corretamente com as necessidades do negócio e com as realidades do desenvolvimento. Na verdade, essa situação geralmente exige um processo de discovery ou spike.

O discovery é uma atividade com um tempo determinado para levantar as necessidades de negócio. Durante essa fase, a equipe busca compreender o que realmente precisa ser feito, consultando stakeholders e documentação para mapear com precisão os requisitos. Já o spike tem um enfoque mais técnico. Em um spike, a equipe investiga aspectos técnicos e realiza experimentos, como a criação de POCs (Proofs of Concept), para avaliar a viabilidade das soluções. Em outras palavras, o discovery serve para entender o que precisa ser feito do ponto de vista do negócio, enquanto o spike é focado em como isso será implementado do ponto de vista técnico.

Definir uma data de entrega sem ter realizado essas atividades é uma prática irresponsável, pois falta a base necessária para estimar com precisão o esforço e os recursos. Após a realização dessas atividades, que podem ser necessárias uma ou ambas. O objetivo é apresentar uma solução plausível, baseada em informações claras sobre o que precisa ser feito, tanto do ponto de vista do negócio quanto técnico. Essas atividades, com seus prazos bem definidos, fornecem os insumos necessários para garantir que o desenvolvimento e a entrega aconteçam de forma mais eficiente e sem surpresas.

Após entender o “o quê” e o “como” do que precisa ser feito, a próxima habilidade essencial é a capacidade de dividir as tarefas em unidades menores, entregáveis de forma incremental. Essa divisão é crucial para manter o controle do progresso e garantir que as entregas sejam feitas de maneira contínua e dentro das expectativas. No entanto, essa pode ser uma das maiores dificuldades que as equipes enfrentam, já que transformar um grande desafio em várias pequenas tarefas demanda um nível de clareza e organização.

O código é bom, mas a solicitação é complexa. Vamos abrir mão de pensar em um design eficiente por conta do tempo.

Neste tópico, vou compartilhar como, ao longo da minha carreira, tenho lidado com essa situação.

O que geralmente acontece é que o PO, o Gerente, o Tech Lead e os demais desenvolvedores compram a ideia de que a solução será injetar código rapidamente para resolver o problema, mas, com isso, acabam assumindo uma débito técnico.

E é importante destacar que “débito técnico” não existe como um termo legítimo em português, pois se trata de um falso cognato do inglês, que foi traduzido de forma errônea.

PalavraPronúnciaTraduçãoSignificado
Debit“DÉ-bit”débitomovimentação financeira no presente
Debt“DÉT”dívidaobrigação financeira futura

Em resumo, não temos um débito técnico, pois essa operação ocorre no presente. Mas a questão é: o que está sendo tirado e de onde? O termo correto é dívida técnica.

Agora, passando a limpo essa confusão, vamos trabalhar um pouco mais sobre o conceito de dívida técnica.

Dívida técnica

Segundo Martin Fowler, uma dívida técnica é comparável à dívida financeira. Se você contrair uma dívida, precisará pagar juros. Quando decide não refatorar ou adotar uma solução rápida, você está assumindo uma dívida técnica. Embora possa adiar o pagamento, eventualmente terá que pagá-la. Ou seja, a dívida técnica não desaparece. Se não for paga por meio de refatorações e melhorias, ela se acumula, tornando o sistema mais difícil e caro de manter.

Para mim, assim como uma dívida financeira, ao longo do tempo, a dificuldade de pagar a dívida técnica aumenta, pois os juros continuam a acumular. Isso significa que, quando não se corrige ou melhora o código no tempo adequado, ele se torna muito mais difícil e caro de manter. À medida que as necessidades do negócio crescem — como incrementar novas funcionalidades ou melhorar a experiência do cliente — o que poderia ser um simples incremento se transforma em adaptações mais complexas, já que o custo de corrigir o código se torna mais alto do que o de adaptar o sistema.

Martin Fowler cita Ward Cunningham, que apresentou em 92 a metáfora onde o dívida técnica no início de um projeto é como se endividar, decisão que pode acelerar o desenvolvimento, mas que deve ser seguido de refatoração para reduzir o endividamento e mantê-lo sob controle.

Ward Cunningham, o criador do conceito de dívida técnica, descreve da seguinte forma:

“Dívida técnica ocorre quando você opta por uma solução mais rápida e fácil, mesmo sabendo que ela trará um custo no futuro. Esse custo pode ser mais difícil e caro de resolver depois.”

Martin Fowler propôs um canvas para diagnosticar dívida técnica:

No canvas, a dívida técnica é dividida em quatro quadrantes, com base na abordagem e na intenção da equipe.

Reckless/Deliberate (Imprudente): Soluções apressadas sem planejamento, resultando em grandes dificuldades futuras e aumento rápido da dívida técnica.Prudent/Deliberate (Prudente): Decisão estratégica e consciente de contrair dívida técnica, com um plano claro para refatoração e pagamento da dívida no futuro.
Reckless/Inadvertent (Imprudente/Inadvertido): Dívida técnica acumulada sem intenção, devido a decisões impulsivas ou falta de avaliação do impacto, tornando-se difícil de resolver.Prudent/Inadvertent (Prudente/Inadvertido): Dívida técnica contraída sem consciência dos impactos, frequentemente por falta de refatoração, resultando em problemas similares aos do quadrante imprudente.

    Em resumo, o quadrante Reckless/Deliberate é o mais problemático, refletindo decisões apressadas e descontroladas. O Prudent/Deliberate representa escolhas mais equilibradas, com foco no longo prazo. Em todos os casos, é crucial estar ciente dos impactos e ter um plano para lidar com a dívida técnica.

    Mik Kersten, autor do livro Project to Product, afirma: “A dívida técnica se acumula quando o foco está no desempenho imediato e não no valor a longo prazo do produto. Isso cria um obstáculo à entrega contínua de valor.

    Jez Humble, autor de Continuous Delivery, menciona: “Quando acumulamos dívida técnica, estamos adiando o pagamento de um custo, mas, com o tempo, isso impede que entreguemos novas funcionalidades rapidamente. A dívida técnica nos força a investir mais para alcançar a mesma velocidade de entrega.”

    Uma pesquisa da McKinsey (Demystifying Digital Dark Matter: A New Standard to Tame Technical Debt) aponta que cerca de 30% dos CIOs que responderam à pesquisa acreditam que mais de 20% do orçamento de TI que poderia ser destinado a novos produtos está sendo utilizado para resolver dívidas técnicas. Além disso, empresas com alto endividamento técnico têm 40% mais chances de ver seus projetos de modernização incompletos ou cancelados.

    Assim como na vida real, não significa que você não possa contrair dívida técnica. Existem momentos em que ela é estrategicamente necessária.

    “Em alguns momentos, contrair uma dívida técnica é uma decisão válida. Às vezes, é melhor fazer algo rapidamente e corrigir mais tarde, principalmente quando o mercado exige entregas rápidas.” – Martin Fowler

    O que é importante é ter consciência dos impactos gerados pela decisão de abrir mão de algo, ter um plano claro para a correção e estabelecer um compromisso com a implementação dessa correção. Dessa forma, é possível contornar o problema de maneira controlada. Caso isso seja ignorado, os custos podem aparecer de outras formas, como a diminuição da produtividade devido à má qualidade do software. Além disso, sistemas que dependem de serviços com dívida técnica podem se tornar mais caros, devido à necessidade de adaptação a falhas de design ou problemas de qualidade. Isso exige mais horas de trabalho e ajustes frequentes para atender a novos requisitos.

    E o impacto não se limita ao sistema com a dívida técnica. Sistemas integrados a ele também podem ser fortemente afetados. Esses sistemas muitas vezes precisam se adaptar a um design ruim ou herdar responsabilidades que deveriam ser do sistema com dívida técnica. Isso pode envolver a necessidade de adicionar camadas extras de resiliência, ou até criar soluções paralelas para contornar os problemas gerados pela dívida técnica. Esses ajustes aumentam a complexidade e tornam a solução do problema original ainda mais difícil, pois as camadas de adaptação acabam criando um ciclo vicioso. Assim, o problema se enraíza mais profundamente e se torna cada vez mais difícil de resolver.

    Já vi essa situação na prática: o custo se torna mais alto devido à recorrente necessidade de ajustes e adaptações, e os sistemas integrados acabam se tornando cada vez mais entrelaçados ao problema principal, tornando a correção da dívida técnica uma tarefa mais complexa e cara no futuro.

    Neal Ford, no Agile Brazil de 2012, afirmou que todo software possui dois tipos de usuários: o visível, que se beneficia diretamente do sistema, e o oculto, representado pelos profissionais responsáveis por sua manutenção e evolução.

    Em treinamentos e mentorias, costumo enfatizar que todo engenheiro de software tem um compromisso duplo em cada tarefa: entregar valor ao negócio de forma profissional e garantir um código bem escrito, de fácil leitura, manutenível e extensível para os colegas de equipe.

    Conclusão

    Quando as equipes de desenvolvimento se veem pressionadas por prazos apertados, é comum que a qualidade do código e o design acabem ficando em segundo plano. A busca por soluções rápidas, como aumentar a equipe ou trabalhar horas extras, pode parecer uma saída imediata, mas só aumenta a dívida técnica com o tempo e não garante aumento de performance da equipe. Além disso, um código bagunçado, muitas vezes fruto da falta de cuidado e profissionalismo, só torna as coisas mais complicadas no futuro. Mesmo que, em algumas situações, a dívida técnica seja uma escolha estratégica, o problema é que, sem um planejamento adequado para corrigir as falhas, a manutenção do sistema se torna cada vez mais cara e difícil. O segredo está em encontrar o equilíbrio entre entregar rápido e garantir que o código seja bem estruturado. E é aí que práticas como discovery e spike podem ser grandes aliados, ajudando a alinhar as necessidades do negócio com a viabilidade técnica. No fim das contas, saber gerenciar a dívida técnica de maneira consciente é o que vai garantir que o projeto seja sustentável e adaptável ao longo do tempo.

    Vale destacar que alguns pontos mencionados ao longo deste texto podem ser abordados com mais profundidade em um artigo subsequente, onde posso explorar de maneira mais detalhada gestão da dívida técnica, estratégias para refatoração eficiente, a importância do conhecimento do negócio nas equipes de desenvolvimento, profissionalismo e mais. Fique atento para mais detalhes!


    Antes de mergulhar de cabeça na IA generativa, conheça os desafios que ninguém comenta!

    Bibliografia:

    No responses yet

    Deixe um comentário

    O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

    Latest Comments

    Nenhum comentário para mostrar.