SOLID: 5 Princípios para Escrever Código Limpo e Escalável
12 de março de 2026 às 19:23 - Por Larissa Santos

A programação não se resume apenas a escrever linhas de código. O verdadeiro desafio está em resolver problemas e garantir que o código que você cria seja sustentável, fácil de manter e escalável. Um conjunto de princípios que tem se mostrado extremamente eficaz para melhorar a qualidade do código é o SOLID.
SOLID é um acrônimo que representa cinco princípios fundamentais para o design de software, especialmente no contexto da programação orientada a objetos (OOP). Neste post, vamos entender o que significa SOLID, explorar cada um dos seus princípios e aprender como aplicá-los de forma prática.
O que é SOLID?
SOLID é uma coleção de 5 princípios de design que ajudam os desenvolvedores a criar software mais robusto e flexível. Esses princípios foram propostos por Robert C. Martin (Uncle Bob) e têm como objetivo promover a criação de sistemas mais coesos, de fácil manutenção e com menos acoplamento entre suas partes. Vamos analisar cada um desses princípios e entender como podemos aplicá-los no nosso código.
1. Single Responsibility Principle (Princípio da Responsabilidade Única)
O Single Responsibility Principle (SRP) diz que cada classe ou módulo deve ter uma única responsabilidade. Isso significa que cada classe deve ter uma razão única para mudar, o que facilita a manutenção e melhora a coesão do código.
Exemplo prático (em JavaScript):
class UserService {
createUser(user) {
console.log('Usuário salvo no banco')
}
}
class EmailService {
sendWelcomeEmail(user) {
console.log('E-mail de boas-vindas enviado')
}
}
Aqui, temos duas classes: UserService (que lida com a criação do usuário) e EmailService (que lida com o envio de e-mail). Cada classe tem uma responsabilidade única, de modo que a manutenção de uma não afeta a outra.
2. Open/Closed Principle (Princípio Aberto/Fechado)
O Open/Closed Principle (OCP) afirma que as entidades de software (como classes e módulos) devem ser abertas para extensão, mas fechadas para modificação. Ou seja, devemos ser capazes de adicionar novas funcionalidades sem alterar o código existente.
Exemplo prático (em JavaScript):
class PixPayment {
pay(value) {
return `Pagamento via PIX: R$ ${value}`
}
}
class CardPayment {
pay(value) {
return `Pagamento via Cartão: R$ ${value}`
}
}
class Checkout {
constructor(paymentMethod) {
this.paymentMethod = paymentMethod
}
finish(value) {
return this.paymentMethod.pay(value)
}
}
Neste exemplo, a classe Checkout não precisa ser modificada para adicionar um novo método de pagamento. Podemos facilmente adicionar um novo método de pagamento, como Boleto ou PayPal, sem alterar o código de Checkout. Isso torna o sistema mais flexível e fácil de estender.
3. Liskov Substitution Principle (Princípio da Substituição de Liskov)
O Liskov Substitution Principle (LSP) diz que, se uma classe A é uma subclasse de B, então podemos substituir a classe A pela classe B sem alterar o comportamento esperado do sistema.
Exemplo prático (em JavaScript):
class Bird {
move() {
return 'O pássaro está se movendo'
}
}
class Sparrow extends Bird {
move() {
return 'O pardal está voando'
}
}
class Penguin extends Bird {
move() {
return 'O pinguim está nadando'
}
}
function showMovement(bird) {
console.log(bird.move())
}
Aqui, Sparrow e Penguin são subclasses de Bird. Cada uma tem sua própria implementação de move(), mas ainda assim é possível substituir qualquer uma delas sem quebrar o comportamento esperado de showMovement.
4. Interface Segregation Principle (Princípio da Segregação de Interfaces)
O Interface Segregation Principle (ISP) afirma que uma classe não deve ser forçada a depender de métodos que não utiliza. Em vez disso, devemos criar interfaces menores e mais específicas, adaptadas às necessidades de cada classe.
Exemplo prático (em JavaScript):
const canPrint = {
print(doc) {
console.log('Imprimindo:', doc)
}
}
const canScan = {
scan() {
console.log('Escaneando documento')
}
}
class SimplePrinter {}
Object.assign(SimplePrinter.prototype, canPrint)
class MultiFunctionPrinter {}
Object.assign(MultiFunctionPrinter.prototype, canPrint, canScan)
Nesse exemplo, SimplePrinter não precisa ter a capacidade de escanear, e MultiFunctionPrinter pode fazer tanto a impressão quanto a digitalização. As interfaces são separadas para evitar que uma classe implemente métodos que não são necessários para ela.
5. Dependency Inversion Principle (Princípio da Inversão de Dependência)
O Dependency Inversion Principle (DIP) nos diz que devemos depender de abstrações (como interfaces ou classes abstratas) e não de implementações concretas. Isso promove o desacoplamento entre módulos e facilita a manutenção e testes.
Exemplo prático (em JavaScript):
class StripeGateway {
pay(value) {
return `Pago com Stripe: R$ ${value}`
}
}
class PaypalGateway {
pay(value) {
return `Pago com PayPal: R$ ${value}`
}
}
class PaymentService {
constructor(gateway) {
this.gateway = gateway
}
checkout(value) {
return this.gateway.pay(value)
}
}
Neste caso, PaymentService não depende diretamente de um gateway específico como Stripe ou PayPal. A dependência é invertida ao utilizar a abstração de gateway, permitindo que o serviço de pagamento seja facilmente substituído por outra implementação.
Conclusão
Adotar os princípios SOLID no seu desenvolvimento pode transformar a maneira como você cria software. Eles ajudam a melhorar a coesão, reduzir o acoplamento e tornar o código mais flexível para alterações futuras. Ao seguir essas práticas, você será capaz de criar sistemas mais modulares, testáveis e sustentáveis.
Aplique SOLID em seus projetos e veja a diferença no processo de desenvolvimento.