Neste episódio Edu Matos conversa com Sibelius Serafini, CTO na Woovi, sobre práticas de desenvolvimento que foram abolidas na Woovi, dentre elas programação orientada a objetos, design patterns e testes unitários.
Restrições fazem você ir mais rápido. Se você tiver muita liberdade, na programação ou na vida, provavelmente terá consequências ruins.
A complexidade inerente à herança, métodos virtuais e hierarquias rígidas de classes trouxe mais problemas do que soluções. Códigos difíceis de depurar, stack traces extensos e a proliferação de abstrações desnecessárias motivaram a migração para um paradigma funcional. Funções puras, imutabilidade e composição mostraram-se mais alinhadas com a matemática por trás do software: entrada → transformação → saída. Restringir opções reduziu a complexidade acidental, tornando o código previsível e fácil de raciocinar, especialmente com sistemas de tipos robustos.
A capacidade de substituir implementações em tempo de execução (como em JavaScript) torna a injeção de dependência redundante em muitos casos. A crítica principal recai sobre a "mágica" da injeção automática, que introduz indireção e obscurece a origem das implementações. Quando cada dependência exige navegar por dezenas de arquivos e classes abstratas, o custo cognitivo supera os benefícios. A simplicidade de funções diretas e mocks pontuais mostrou-se mais eficiente.
Padrões de projeto e princípios do Clean Code não são inerentemente ruins, mas sua aplicação dogmática gera complexidade artificial. Criar micro-hierarquias de classes para um CRUD simples ou funções atomizadas apenas para cumprir regras arbitrárias ("funções devem ter 5 linhas!") adiciona sobrecarga sem valor. O problema não são os padrões em si, mas usá-los sem entender quando e por que são necessários. A solução? Adotar o que funciona para o contexto, rejeitando "boilerplate" burocrático que não resolve problemas reais.
Camadas rígidas (Controllers, Services, Repositories) tornam-se obstáculos quando aplicadas indiscriminadamente. A promessa de "trocar o banco de dados facilmente" raramente se concretiza, enquanto o custo de manter abstrações desalinhadas do domínio é alto. Organizar o código por funcionalidades (ex: pasta /user
com tudo relacionado a usuários) provou-se mais prático que seguir estruturas pré-definidas. Boas abstrações devem simplificar, não complicar.
Testes unitários frequentemente validam implementações, não comportamentos, gerando mais falsos-positivos. Já os testes de integração:
Cobertura alta não é meta; evitar erros caros (ex: transações financeiras falhando) é.
Restrições intencionais, seja no código (funções em vez de classes), na infra (monorepos, tecnologias unificadas) ou nos processos (documentação assíncrona), não limitam, mas liberam. Elas reduzem custos de manutenção, aceleram a entrega e deixam espaço para o que importa: resolver problemas de negócio. Inovação não surge de complexidade, mas da coragem de questionar "Isso realmente é necessário?".
"Restrições fazem você ir mais rápido. Aprenda com opiniões diferentes, mas decida com base no seu contexto." — Sibelius Seraphini