Guia Básico sobre Princípios de Programação e SOLID
Published: 2021-10-24 14:12:26

Estudando um pouco sobre Clean Code e boas práticas no desenvolvimento de software, me deparei com os princípios de programação e princípios SOLID. Aliados com o Clean Code, eles são uma ferramenta poderosa para mantermos um código de fácil entendimento, fácil refatoração e com o menor número possíveis de bugs.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/inatq0uh416gm7iu383e.jpeg)

Princípios de programação são recomendações concretas que os desenvolvedores devem seguir para atender às propriedades de projeto. Cinco destes princípios formam os Princípios SOLID (em português, são eles: Responsabilidade Única, Aberto/Fechado, Substituição de Liskov, Segregação de Interfaces e Inversão de Dependência). Estes princípios, aliados com as práticas de Clean Code, permite que desenvolvemos códigos mais maleáveis, que são mais fáceis de se refatorar e melhorar. Vou descrever um pouco dos princípios do SOLID, além de falar sobre o princípio de "Prefira Composição a Herança" e do princípio de "Demeter".

**1. Princípio de Responsabilidade Única**

Este princípio (relacionado a coesão) diz que cada classe (pode ser aplicado a funções, componentes, entidades entre outros) deve ter apenas uma responsabilidade, ou seja, deve existir apenas um motivo para modificar qualquer classe em um sistema.

Ou seja, este princípio prega que não devemos criar uma "Classe Deus" que, por exemplo, valida e-mail, lê arquivo, acessa o banco de dados, grava no banco de dados, consulta uma API, entre outros. Como cada classe deve ter apenas uma função, neste exemplo devemos ter uma classe apenas para acessar o banco de dados, outra apenas para ler um arquivo, outra para validar um e-mail e assim por diante, cada qual com sua função.

**2. Princípio Aberto/Fechado**

Este princípio diz que uma classe deve estar fechada para modificações e abertas para extensões. Seu objetivo é a construção de classes flexíveis e extensíveis, capazes de se adaptarem a diversos cenários de uso sem modificações no seu código fonte.
Neste princípio, o projeto da classe possibilita extensões e customizações, através do uso de herança, funções de mais alta ordem (ou funções lambda) e padrões de projeto (como Abstract Factory, Template Method, Strategy).

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vzj928vdhgzwx9vuk0ta.jpg)

**3. Princípio da Segregação de Interface**

Este princípio define que as interfaces têm que ser pequenas, coesas e especificas para cada tipo de cliente. Trata-se de um caso particular de Responsabilidade Única com foco em interfaces (relacionado a coesão também), o objetivo deste princípio é evitar que clientes dependam de interfaces com métodos que eles não irão usar.

Ou seja, se você não for utilizar algum dos métodos daquela interface na classe que pretende implementá-la, é melhor criar uma nova interface específica para aquela classe do que sobrescrever métodos que não serão utilizados.

**4. Princípio da Substituição de Liskov**

Este princípio explicita regras para redefinição de métodos de classes bases em classes filhas. Apesar de herança não ser muito utilizada, ela pode ser útil em alguns casos específicos. A sua vantagem é que comportamentos (métodos) comuns a classe base e subclasses podem ser implementados uma única vez (na classe base) e poderão ser herdados em todas as subclasses.

Alguns exemplos de classes que violam este princípio são aquelas que sobrescrevem ou implementam (através de uma interface) métodos que não fazem nada (pois alguns métodos desta interface só está sendo utilizado por uma outra classe específica, por exemplo), lança uma exceção inesperada, ou que retorna valores de tipos diferentes da classe base.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vzj928vdhgzwx9vuk0ta.jpg)

**5. Princípio de Inversão de Dependência**

Este princípio recomenda que uma classe cliente deve estabelecer dependências prioritariamente com abstrações e não com implementações concretas, pois as abstrações (interfaces) são mais estáveis do que implementações concretas (classes).

A ideia levantada por este princípio então é de inverter as dependências, ou seja, ao invés dos clientes dependerem de classes concretas, eles devem depender de interfaces. A vantagem deste princípio é que, quando um cliente se acopla a uma interface, ele fica imune a mudanças na implementação dessa interface.

**6. Prefira Composição a Herança**

Este princípio recomenda o uso de composição a herança, pois quando usamos herança, isso acaba gerando um forte acoplamento entre superclasses e subclasses. A herança expõe para subclasses detalhes de implementação das classes, fazendo com que a implementação das subclasses se torna tão acoplada à implementação da classe pai, que qualquer mudança nelas pode forçar modificações nas subclasses. Uma outra vantagem de se utilizar composição é que a relação entre as classes não é estática, permitindo assim, fazer mudanças em tempo de execução.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ksudny5u60g8wt3ysa34.jpeg)

**7. Princípio de Demeter**

Este princípio defende que a implementação de um método deve invocar apenas os seguintes outros métodos:

- Da sua própria classe (caso 1);
- De objetos passados como parâmetros (caso 2);
- De objetos criados pelo próprio método (caso 3);
- De atributos da classe do método (caso 4);

O objetivo deste princípio é evitar problemas de encapsulamento em projeto de sistemas orientados a objetos, ele recomenda que os métodos de uma classe devem falar apenas com métodos da própria classe ou com métodos de objetos que eles recebem como parâmetros (ou que eles criam).