Transforme preguiça em código: Como melhorar o desenvolvimento de software com Interfaces
Como um desenvolvedor preguiçoso melhorou sua rotina de trabalho e legibilidade dos códigos com Patterns e Principles ao trabalhar com Interfaces. Thiago traz dicas valiosas e reflexões sobre arquitetura e senioridade.
Praticamente todo desenvolvedor(a) passa por uma fase em que acredita ter um conhecimento técnico e/ou experiência avançados, quando, na verdade, ainda existe um caminho considerável para chegar no ponto em que se acredita estar - se é que se chega nesse ponto algum dia!
Eu mesmo já acreditei ser sênior quando ainda era só um pleno com um rei na barriga. Nessa época, falava “orientação a objetos é uma falácia! Repetição de código? Claro! Copiar e colar é vida!”
Confesso que, como desenvolvedor, um dos meus maiores defeitos é ser preguiçoso. Luto diariamente contra a preguiça e, naquela época, eu tinha muito trabalho.
Não que hoje eu não tenha muito trabalho, mas antes eu me dava um trabalho burro mesmo: sempre repetia muito código e, mesmo que acreditasse escrever tudo limpo, depois de alguns meses, ao rever, não era nada fácil de entender aquela bagunça.
Meu objetivo aqui neste primeiro artigo de uma série é: apresentar melhor as Interfaces para que Principles e Patterns sejam mais bem aproveitados nos desenvolvimentos de vocês - já que as Interfaces são uma base para falarmos de P&P.
A maioria das pessoas aprende dentro de um paradigma procedural, sequencial e programa de forma linear e sem tomar conhecimento de P&P. Por isso, a maneira que você aprendeu a programar pode ser determinante para que sua aplicação seja escalável e com código limpo.
Mas, como o Jack Estripador, vamos por partes...
Interfaces e suas possibilidades
Quando decidi estudar e descobri um mundo de Interfaces, percebi que toda definição que encontrava era: “interfaces são contratos”. E, logo, eu pensava que não fazia sentido adicionar burocracia ao meu código.
E para que serve uma interface, afinal? Interfaces servem para deixar seu código genérico para que você consiga trabalhar com abstrações em vez de implementações.
Calma! Vamos na prática, então?
Imagine que você precise consumir uma biblioteca de logística da transportadora Anunciação para calcular o frete de um item do estoque central até um destino qualquer:
Alguns meses passam e o Product Owner fala que a empresa fechou contrato com a transportadora Lima e a aplicação deverá ser configurável para fazer o cálculo com a biblioteca de qualquer uma das transportadoras contratadas, ok?
Além disso, a nova transportadora devolve o valor em centavos:
Sim, existem ouras formas de configurar, talvez com a configuração fora da classe, com métodos diferentes, ou classes diferentes sendo instanciadas de acordo com a configuração, com um switch para “prever” futuras novas transportadoras:
Também já vi a construção com método estático, para não usar “new”. Ou evitando vários “statements” em uma linha.
De qualquer forma, você está trabalhando com implementações, e isto torna seu código fortemente acoplado - de modo que a manutenção seja cada vez mais complexa e torne cada vez mais difícil suportar as mudanças.
Se nem os Vingadores dependem do Capitão América, sua aplicação também não deveria depender das suas implementações!
Leia também: DMP x CDP x CRM: Diferenças e Benefícios Estratégicos
Agora, sua solução poderá trabalhar com a interface (abstração), em vez de criar instâncias das implementações, sua aplicação utilizará uma variável dinâmica (IFrete frete) que será instanciada em tempo de execução com uma das implementações.
A partir dessas mudanças, sua aplicação é fracamente acoplada e muito mais flexível. Isso significa que mudanças nas implementações causarão pouco impacto - além de código mais limpo, legível e testável.
Alguns podem até pensar: “Mas antes eu tinha escrito menos código, agora tem mais classes.”
Sim, verdade.
Porém, cada vez que a empresa contratar uma nova transportadora você precisará mudar regras, fazer adequações na sua aplicação como um todo, e isto gera um risco muito maior de bugs.
Uma vez que você mudou uma linha sequer do código de outra transportadora, TODOS os casos de testes para TODAS as transportadoras vão precisar ser executados novamente. Estes são exatamente os tipos de problema que devemos nos preocupar com um código fortemente acoplado.
Ou seja, quando você destrava o seu entendimento de Interfaces, a orientação de objetos fica muito mais fácil de entender.
Leia também: Design System: O que é e por que sua empresa precisa de um
Mas e a configuração?
Existem várias formas para que a variável “frete”, por exemplo, tenha, em tempo de execução, uma instância de uma das implementações feitas.
Podemos ter, por exemplo, factory, strategy e injeção de dependência para resolver isto. Mas vou deixar isso para os próximos artigos.
E se você está se perguntando o que isso tem a ver com senioridade, é simples: Design Patterns começaram a se popularizar no mundo com o livro de título homônimo escrito pela “Gang of Four”. Este livro foi lançado em 1994. Está perto de fazer 30 anos, deveria ser literatura obrigatória em cursos e faculdades, e raramente é sequer mencionado.
Você é sênior? E se o seu software fosse um avião?
Colocaria sua mãe nele para voar ou iria rever algumas coisas?
Existem várias formas de se fazer, cada um tem a sua lógica, mas ao aplicar as técnicas e princípios adequados, você irá trabalhar menos - um viva para os preguiçosos de plantão - e de forma muito mais inteligente!
Nos próximos artigos, vamos aprofundar ainda mais nos Principles e Patterns e explorar ainda mais o SOLID dentro dos Design Principles para que qualquer um que veja seus códigos possa pensar “nossa, que código mimoso” e você não precisará mais se sentir nu(a) ou envergonhado(a)!
Design Principles – SOLID:
Single Responsability Principle
Open-Closed Principle
Liskov substituition Principle
Interface Segregation Principle
Dependency Inversion Principle
Comentários