image

Acesse bootcamps ilimitados e +650 cursos pra sempre

60
%OFF
Roberth Oliveira
Roberth Oliveira14/08/2025 11:37
Share
Suzano - Python Developer #2Recommended for youSuzano - Python Developer #2

Como os princípios SOLID moldam um bom Engenheiro de Software

    image

    Como estudante de Engenharia de Software e desenvolvedor que atua no ecossistema Java, constantemente me deparo com um desafio central em nossa área: como criar um software que não apenas funcione hoje, mas que seja fácil de manter, escalar e modificar no futuro?

    A resposta, muitas vezes, reside em um conjunto de cinco princípios de design conhecidos pelo acrônimo SOLID.

    Criados por Robert C. Martin (o "Uncle Bob"), esses princípios são a base do design de software orientado a objetos e nos guiam para a criação de sistemas mais compreensíveis, flexíveis e robustos. Para mim, eles não são apenas regras, mas uma mentalidade que conecta a teoria da engenharia com a prática da programação.

    A imagem que acompanha este artigo ilustra perfeitamente os cinco pilares que vamos desvendar agora:

    image

    S - Single Responsibility Principle (Princípio da Responsabilidade Única)

    Este princípio afirma que uma classe deve ter um, e somente um, motivo para mudar.

    • O que significa? Em vez de criar "super classes" que fazem de tudo (gerenciam usuários, conectam ao banco de dados, geram relatórios), devemos quebrar nosso código em classes menores e coesas. Cada classe deve ter uma única responsabilidade bem definida.
    • No mundo Java: Pense em uma classe UsuarioService. Em vez de colocar nela os métodos para salvarNoBanco() e enviarEmailDeConfirmacao(), o SRP nos incentiva a ter classes distintas: uma UsuarioRepository para a persistência e uma EmailService para o envio de notificações. Isso torna o código mais fácil de testar, depurar e reutilizar.
    • Link com a Engenharia de Software: Este é o pilar da modularidade. Módulos independentes são mais fáceis de gerenciar e entender, reduzindo o acoplamento e o risco de que uma pequena mudança em uma parte do sistema quebre outra inesperadamente.

    O - Open-Closed Principle (Princípio Aberto-Fechado)

    O princípio diz que entidades de software (classes, módulos, funções) devem ser abertas para extensão, mas fechadas para modificação.

    • O que significa? Você deve ser capaz de adicionar novas funcionalidades sem alterar o código-fonte existente.
    • No mundo Java: Isso é frequentemente alcançado com o uso de interfaces e classes abstratas. Imagine um sistema que calcula o imposto para diferentes tipos de contrato (CLT, PJ). Em vez de um if/else gigante na classe de cálculo, criamos uma interface CalculadoraDeImposto com um método calcular(). Cada novo tipo de contrato implementa essa interface. Assim, para adicionar um novo contrato "Estagiário", basta criar uma nova classe CalculadoraImpostoEstagiario; o código principal, que usa a interface, não precisa ser tocado.
    • Link com a Engenharia de Software: Isso se chama escalabilidade e manutenibilidade. O sistema cresce de forma organizada e segura, minimizando o risco de introduzir bugs em funcionalidades que já estavam funcionando (regressão).

    L - Liskov Substitution Principle (Princípio da Substituição de Liskov)

    Este princípio estabelece que objetos de uma superclasse devem ser substituíveis por objetos de suas subclasses sem quebrar a aplicação.

    • O que significa? Se uma classe Gato herda da classe Animal, qualquer parte do código que espera um Animal deve funcionar perfeitamente se receber um Gato, sem saber da diferença. A subclasse não pode violar o "contrato" da superclasse.
    • No mundo Java: O exemplo clássico é a falácia do "Quadrado herda de Retângulo". Se a classe Retangulo tem métodos setAltura() e setLargura(), um Quadrado que herda dela teria um comportamento estranho (ao mudar a altura, a largura também teria que mudar), quebrando o contrato do Retangulo. Isso nos ensina que a herança deve modelar uma relação de "é um" que respeite o comportamento, não apenas os atributos.
    • Link com a Engenharia de Software: Garante a confiabilidade e a integridade do sistema. O polimorfismo só funciona de maneira previsível se este princípio for respeitado, levando a um design de hierarquias de classes mais robusto.

    I - Interface Segregation Principle (Princípio da Segregação de Interface)

    O ISP afirma que nenhum cliente deve ser forçado a depender de métodos que não utiliza.

    • O que significa? É melhor ter várias interfaces pequenas e específicas do que uma única interface grande e genérica.
    • No mundo Java: Imagine uma interface Trabalhador com os métodos trabalhar(), almocar() e receberSalario(). Se formos modelar um RoboTrabalhador, ele seria forçado a implementar o método almocar(), o que não faz sentido. A solução do ISP é segregar a interface em Trabalhavel e Alimentavel. O HumanoTrabalhador implementaria ambas, enquanto o RoboTrabalhador implementaria apenas Trabalhável.
    • Link com a Engenharia de Software: Promove o baixo acoplamento e um design mais enxuto. Evita que classes carreguem "bagagens" desnecessárias, tornando o sistema mais claro e eficiente.

    D - Dependency Inversion Principle (Princípio da Inversão de Dependência)

    Este princípio tem duas partes:

    1. Módulos de alto nível que devem depender de módulos de baixo nível. Ambos devem depender de abstrações.
    2. Abstrações não devem depender de detalhes. Detalhes devem depender de abstrações.
    • O que significa? Em vez de uma classe de regra de negócio (CheckoutService) instanciar diretamente uma classe de infraestrutura (MySqlDatabase), ela deve depender de uma interface (Database). A classe concreta (MySqlDatabase) é então "injetada" em tempo de execução.
    • No mundo Java: Este é o coração de frameworks como Spring, com sua Injeção de Dependência (DI). Ao usar @Autowired, não estamos acoplando nossa classe de serviço a uma implementação específica, mas a uma abstração (interface). Isso nos permite trocar facilmente um banco de dados MySQL por um PostgreSQL ou usar um "mock" para testes unitários, sem alterar a classe de negócio.
    • Link com a Engenharia de Software: É a chave para a flexibilidade e testabilidade. A inversão de dependência desacopla as camadas do software, permitindo que elas evoluam de forma independente e facilitando drasticamente a criação de testes automatizados.

    Conclusão

    Dominar os princípios SOLID não é um exercício puramente acadêmico; é um investimento direto na qualidade do nosso trabalho como desenvolvedores e engenheiros de software. Em Java, onde a orientação a objetos é central, aplicá-los nos permite construir aplicações mais limpas, resilientes e preparadas para o futuro.

    E você, qual princípio SOLID considera mais desafiador de aplicar no dia a dia? Ou qual deles trouxe o maior impacto positivo para os seus projetos?

    Adoraria ler suas experiências nos comentários!

    #SOLID #Java #DesenvolvimentoDeSoftware #EngenhariaDeSoftware #POO #CleanCode #BoasPraticas #Programacao #SoftwareDesign

    Share
    Recommended for you
    Avanade - Back-end com .NET e IA
    Akad - Fullstack Developer
    Suzano - Python Developer #2
    Comments (2)
    Roberth Oliveira
    Roberth Oliveira - 14/08/2025 11:57

    O princípio mais desafiador de aplicar consistentemente em projetos reais é o Liskov Substitution Principle (LSP), devido à complexidade de garantir que subtipos respeitem invariantes e comportamentos definidos por suas superclasses. Isso exige um design cuidadoso de hierarquias de herança, evitando armadilhas como a "falácia do quadrado-retângulo".

    Como superar:

    • Preferir composição sobre herança quando a relação "é um" não é perfeita.
    • Definir contratos claros (via interfaces ou classes abstratas) com pré/pós-condições e invariantes documentados.
    • Validar comportamentos em testes unitários para garantir que subtipos não violem expectativas.

    Exemplo prático: Em um projeto com Spring Boot, utilizei interfaces (PaymentService) com implementações distintas (CreditCardPaymentPixPayment), garantindo que cada subtipo cumpra o contrato sem efeitos colaterais inesperados. Testes de contrato (JUnit + AssertJ) foram essenciais para validar a substituibilidade.

    O LSP, quando bem aplicado, elimina surpresas em runtime e facilita a extensão do código, mas demanda disciplina no design inicial.

    DIO Community
    DIO Community - 14/08/2025 11:48

    Roberth, seu artigo sobre os princípios SOLID é uma excelente síntese de como conceitos teóricos podem se traduzir em práticas concretas para desenvolver software robusto e sustentável. A forma como você detalhou cada princípio, com exemplos em Java e ligação direta à engenharia de software, facilita muito a compreensão, especialmente para quem está aprendendo ou revisitando esses fundamentos.

    Na DIO, acreditamos que aplicar SOLID vai além de seguir regras: é construir uma mentalidade que promove modularidade, testabilidade e escalabilidade. O cuidado que você demonstrou ao conectar os exemplos às boas práticas do dia a dia mostra como esses princípios realmente impactam a qualidade do código e a vida útil dos projetos.

    Na sua experiência, qual princípio você considera mais desafiador de aplicar de forma consistente em projetos reais, e como você superou essa dificuldade?

    Recommended for youSuzano - Python Developer #2