Ortogonalidade você sabe o que é?

O princípio da ortogonalidade aplicado ao desenvolvimento de software

A primeira vez que ouvi falar sobre este termo foi no livro The Pragmatic Programmer: A Pragmatic Approach do Andrew Hunt e David Thomas. Desde então, venho tentando entender melhor o conceito e como aplicar no dia a dia. Saber projetar um sistema não é uma tarefa trivial. Existe uma infinidade de princípios e padrões que podem ser aplicados em praticamente qualquer cenário e que te prometem ajudar a criar sistemas mais robustos, flexíveis e fáceis de manter.

O autor do livro, Andy Hunt, sugere que a ortogonalidade é um dos princípios mais importantes para o design de software. Ele argumenta que sistemas ortogonais são mais fáceis de entender, modificar e estender. Um dos pontos apresentados no livro é que a ortogonalidade pode ser aplicada em diferentes níveis de abstração, desde o design de classes e módulos até a arquitetura do sistema como um todo.

Eixos ortagonais

Ortogonalidade é uma palavra muito chique, mas o conceito é simples e faz todo sentido. O conceito que vem da geometria e que se refere a um sistema de coordenadas onde os eixos são ortogonais, ou seja, são perpendiculares entre si.

Os segmentos de linha AB e CD são ortogonais entre si

Um exemplo de sistema de coordenadas ortogonal é o sistema de coordenadas cartesiano, onde os eixos X e Y são perpendiculares entre si. O conceito serve para representar um tipo de independência entre os eixos. Ou seja, o movimento de um eixo não afeta o movimento do outro eixo.</span>

Sitema de coordenadas ortogonal Plotagem de funções lineares, neste caso a função y = x + 1.

E talvez agora você esteja se perguntando: “mas o que isso tem a ver com desenvolvimento de software?”. A resposta é simples: o conceito de ortogonalidade pode ser aplicado ao design de sistemas, onde, os componentes do sistema são independentes entre si, assim como os eixos de um sistema de coordenadas ortogonal.

Independência Estrutural VS Independência de Comportamento

Já se perguntou o que faz um código ser fácil de entender e modificar? A resposta está em três conceitos-chave que, apesar de parecerem técnicos, são extremamente simples de visualizar: coesão, acoplamento e ortogonalidade. Vamos desmistificar isso de um jeito que faz sentido.

Imagine que você está construindo um carro.

A Força da Coesão (Relação Interna)

A coesão é a cola que mantém as coisas juntas. Pense no motor do carro. Ele é uma unidade que faz uma única coisa: gerar potência. Todas as peças — pistões, velas, trabalham juntas, de forma coesa, para esse propósito.

Em programação, um módulo com alta coesão é como esse motor: ele tem uma única responsabilidade bem definida. Cada função, classe ou método ali dentro existe para cumprir esse objetivo. Isso é bom, porque facilita o entendimento e a manutenção. Se você precisa mexer na forma como o carro gera potência, você sabe exatamente onde procurar: no motor.

A Leveza do Acoplamento (Relação Externa)

O acoplamento é o contrario. Ele se refere à dependência entre as partes. No carro, o motor precisa se conectar à transmissão para transferir a potência. Essa conexão é o acoplamento.

Sitema de coordenadas ortogonal

Um acoplamento baixo é ideal. Significa que a conexão entre o motor e a transmissão é o mais simples possível. Se você precisar trocar a transmissão por uma mais moderna, você vai conseguir sem precisar reconstruir o motor inteiro. Eles são independentes o suficiente um do outro.

No código, um sistema com baixo acoplamento é mais flexível. Se você mudar a forma como um módulo funciona, as alterações em outros módulos serão mínimas ou inexistentes.

A Independência da Ortogonalidade (Conceitos Separados)

Agora, a ortogonalidade é um conceito um pouco diferente e mais abrangente. Ela foca na independência dos conceitos, não apenas das partes.

De volta ao carro. A buzina e o limpador de para-brisa são ortogonais. Buzinar não tem impacto nenhum no funcionamento do limpador, e vice-versa. A operação de um não causa efeitos colaterais no outro. Eles resolvem problemas totalmente diferentes e não compartilham nenhuma lógica.

Trazendo para o conceito de ortogonalidade a gente entende que cada recurso ou funcionalidade pode ser alterado de forma independente, sem afetar outros recursos. Ou seja, é a independência de comportamento. Um sistema não-ortogonal seria aquele em que, se ao mudar a cor da fonte, você acidentalmente mudasse também o tamanho do botão. Isso torna o código imprevisível e difícil de gerenciar.

Lados opostos de uma mesma moeda

A coesão é sobre quão bem as coisas de dentro de um módulo se dão, e o acoplamento é sobre quão dependentes os módulos estão um dos outros. Juntos, eles formam a base para uma boa arquitetura de software.

A ortogonalidade complementa esses caras, garantindo que os diferentes conceitos e comportamentos do sistema vivam em seus próprios “cantos”, sem se atrapalharem. Um sistema com alta coesão, baixo acoplamento e alta ortogonalidade é a receita para um software robusto, escalável e, acima de tudo, fácil de trabalhar.

Os frutos no meio do caminho

  1. Modularidade: agora tudo é mais fácil de entender.
  2. Reutilização: penso em “formatos” e não em “funcionalidades”.
  3. Melhor escalabilidade: ok, tudo bem, conseguimos fazer isso.

Alinhando a prática com a teoria

Coesão (fazer uma coisa e fazer bem)

Princípio da Responsabilidade Única (Single Responsibility Principle - SRP): Cada classe, módulo ou função deve ter apenas uma razão para mudar. Pense em uma classe que lida com o cálculo de impostos: a responsabilidade dela é apenas calcular impostos, e não gerar relatórios ou enviar e-mails. Se uma função está fazendo muitas coisas, divida-a em funções menores e mais específicas.

Acoplamento (pouca dependência entre as partes)

Interfaces e Abstrações: Em vez de fazer um módulo depender diretamente de outro, faça-o depender de uma interface (ou contrato). Assim, a implementação pode ser trocada no futuro sem afetar o módulo que a utiliza.

Injeção de Dependência: Em vez de um módulo criar as dependências de que precisa, receba-as por meio de construtores ou métodos. Isso facilita a substituição de dependências e a escrita de testes. Eventos e Mensagens: Use sistemas de eventos ou filas de mensagens para que os componentes se comuniquem de forma indireta, sem saberem da existência uns dos outros.

Ortogonalidade (independência de conceitos)

Mantenha lógicas diferentes em partes separadas do seu código: Por exemplo, se você tem uma lógica de autenticação e uma lógica de autorização, mantenha-as em módulos separados. Assim, mudanças na autenticação não afetarão a autorização.

Evite Efeitos Colaterais: Garanta que uma função ou módulo não mude o estado de outras partes do sistema de forma inesperada. Uma função de cálculo, por exemplo, não deve alterar uma variável global sem necessidade.

Conclusão

Depois de ter chegado até aqui, talvez você pode estar pensando: “ok, Aristóteles é fera no assunto!” e a verdade é que não. Escrevo enquanto estou lendo e aprendendo sobre o assunto e com ajuda da AI. Mas a diferença esta em entender e querer aplicar os conceitos na prática. Se manter atento para fazer uma boa leitura da situação te ajuda a evoluir com a prática.

Muitas vezes, a teoria é simples, mas a prática é desafiadora. A ortogonalidade é um desses conceitos que, quando bem aplicado, pode transformar a forma como você projeta e mantém seus sistemas.

Referências