Regra da Exceção, Coincidência ou Tendência.

Evitando o Big Design Up Front, criando o menor design de código possível

Miere Liniel Teixeira
4 min readMar 31, 2016

Conforme vamos nos interessando por técnicas para deixar nossos códigos fontes limpos e melhor organizados, acabamos nos deparando com uma série de técnicas e Design Patterns novos. E quando identificamos que as estas técnicas teriam solucionado melhor problemas que já vivenciamos, torna-se tentador aplicá-la para solucionar todos os novos problemas que virão. Mas é preciso lembrar que, por tratar-se de lógica de programação, um mesmo problema pode ter mais de uma [boa] solução. Um mesmo design pattern pode se encaixar melhor em determinadas situações, mas criar complexidade desnecessária em outras.

O grande problema que vem quando começamos a fazer um design de código muito elaborado já no início do projeto é que ele torna-se rapidamente complexo. É comum acreditarmos que estamos preparando o terreno para uma possível inclusão de feature que um cliente já pediu outrora. Fica fácil imaginar clientes que não fecharam o projeto, em que a equipe de desenvolvimento sonha com um dia livre para repensar estes trechos do sistema com tranquilidade. A este mal, dá-se o nome de Big Design Up Front. Ele, juntamente com a falta de testes automatizados (unitários ou não), são os grandes responsáveis pela criação dos softwares legados que temos hoje.

Com o tempo, depois de muito treino, nossas técnicas ficam melhores, e passamos a identificar com mais clareza em quais momentos usar determinadas técnicas. Confesso que não conhecia outra forma de se aplicar estas técnicas senão através do treino diário que mantinha.

Em determinado momento passei a treinar as equipes onde trabalhava explicando alguns conceitos sobre DDD, Orientação a Objeto e SOLID. Depois de muito tempo, tive a oportunidade fazer coaching de equipes de outras empresas a convites de amigos e parceiros. Foi nesta época que me deparei com a seguinte situação: “como fazer com que o time que recém aprendeu determinadas técnicas não as aplique desordenadamente, forçando um design de código que talvez não seja realmente necessário?

Coincidentemente, naquela época, eu estava estudando estatística novamente; mais especificamente, curvas de tendencias e amostragens não significantes. De lá, tive um clique e apresentei a seguinte regra para a equipe que iria treinar após o horário:

A primeira vez que um determinado tipo de problema precisa ser resolvido, ele deverá ser tratado como uma exceção. Sendo assim, deverá ser feito o menor código possível para resolver o problema.

A segunda vez que este mesmo tipo de problema aparecer, devemos considerá-lo uma coincidência. O código pode ser refatorado, mas a lógica deve ser simples o suficiente para atender apenas o primeiro caso e o caso atual, sem preocupar-se com uma possível terceira ocorrência.

Quando acontecer uma terceira ocorrência, então, temos uma tendencia. Isso significa que há uma tendência de que este mesmo comportamento volte a acontece. Sendo assim, o código deve ser refatorado de forma que seja possível atender os casos que aconteceram até então e, idealmente, atender novas ocorrências deste mesmo problema, com pouca (ou nenhuma) modificação na lógica feita.

Na prática, somente deveria ser criadas soluções genéricas e mais elaboradas para resolver um problema quando ele ocorresse 3 ou mais vezes. Quando acontecer a primeira ou segunda vez, deverá ser tratado como mera coincidência e aplicar o menor design possível para resolver o problema.

Na prática

Tecnicamente falando, situações consideradas exceção ou coincidência passam a ser resolvidas objetivamente, com classes pequenas (quando necessário) ou simples métodos. Há casos em que um (e eu disse 1) simples “IF/ELSE” já resolve elegantemente o problema.

Quando o problema passa a ser uma tendência, ou os requisitos entre si são relacionados de tal forma que outros podem se valer da mesma lógica, então técnicas mais elaborados são bem vindas, como os patterns Strategy, Adapter, Visitor, etc. Se pensamos em aplicar os princípios de SOLID da orientação a objetos, esta abordagem ajuda claramente à segmentar as classes em uma única responsabilidade, e permite criar trechos de código fechados para modificação e abertos à extensões.

Ambos os casos são técnicas complementares, e não descartam a necessidade de um bom teste unitário[1][2][3] para garantir a saúde do software.

Reação dos times em seu primeiro contato

Irá haver criticismo por parte de algumas equipes, mas isso vai da cultura do time e da empresa envolvida. Um feedback que frequentemente recebi de uma equipe da Ibratan, era de que seus clientes queriam determinadas coisas e por isso já precisavam antecipar o design do código para fosse mais fácil incluí-las posteriormente.

Neste caso, eu fiz um levantamento destes pedidos dos clientes para entender estas necessidades. Simulando o desenvolvimento destas features, e aplicando a regra acima, notamos que quando implementamos os requisitos na ordem que chegaram sem termos conhecimento dos outros que estavam por vir, tínhamos códigos mais reativos à mudança e feito com poucas linhas de código.

Conclusões

Desde então, ao usar esta abordagem, as equipes por onde passei e apliquei esta abordagem passaram a fazer menos códigos desnecessários, mais fácies de se manutenir e dispostos a receberem modificações.

E você, já conhecia a regra acima? Já precisou lidar com situações similares?Compartilhe sua experiência, especialmente, se você passou por uma situação onde este tipo de prática não ajudou!

--

--

Miere Liniel Teixeira

Developer, Entrepreneur, Punk Rocker, Friend, Husband and Dad!