SOLID e um acronimo de cinco principios de design orientado a objetos que tornam o software mais compreensivel, flexivel e manutenivel. Formulados por Robert C. Martin (Uncle Bob), sao fundamentais para qualquer desenvolvedor que queira escrever codigo profissional. Este guia explica cada principio com exemplos praticos.
S – Single Responsibility Principle (SRP)
Principio: uma classe deve ter apenas um motivo para mudar. Ou seja, cada classe deve ter uma unica responsabilidade.
Ruim:
class UserService:
def create_user(self, name, email, password):
# Validacao
if not re.match(r”[^@]+@[^@]+.[^@]+”, email):
raise ValueError(“Email invalido”)
# Criptografia
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
# Banco de dados
db.execute(“INSERT INTO users (name, email, password) VALUES (?, ?, ?)”, (name, email, hashed))
# Envio de email
smtp.sendmail(“noreply@app.com”, email, “Bem-vindo!”)
Esta classe tem 4 responsabilidades: validacao, criptografia, persistencia e envio de email. Qualquer mudanca em uma dessas areas exige alterar esta classe.
Bom:
class UserValidator:
def validate(self, name, email, password):
if not re.match(r”[^@]+@[^@]+.[^@]+”, email):
raise ValueError(“Email invalido”)
class UserRepository:
def save(self, user):
db.execute(“INSERT INTO users VALUES (?)”, user)
class WelcomeEmailService:
def send(self, email):
smtp.sendmail(“noreply@app.com”, email, “Bem-vindo!”)
class UserService:
def __init__(self, validator, repository, email_service):
self.validator = validator
self.repository = repository
self.email_service = email_service
def create_user(self, name, email, password):
self.validator.validate(name, email, password)
user = User(name, email, hash_password(password))
self.repository.save(user)
self.email_service.send(email)
Cada classe tem uma responsabilidade. Mudar como emails sao enviados nao afeta a persistencia.
O – Open/Closed Principle (OCP)
Principio: classes devem ser abertas para extensao, fechadas para modificacao. Voce deve poder adicionar comportamento sem alterar codigo existente.
Ruim:
class DescontoCalculator:
def calcular(self, tipo, valor):
if tipo == “black_friday”:
return valor * 0.7
elif tipo == “natal”:
return valor * 0.85
elif tipo == “aniversario”:
return valor * 0.9
return valor
Cada novo tipo de desconto exige modificar esta classe.
Bom:
class Desconto(ABC):
@abstractmethod
def aplicar(self, valor):
pass
class BlackFridayDesconto(Desconto):
def aplicar(self, valor):
return valor * 0.7
class NatalDesconto(Desconto):
def aplicar(self, valor):
return valor * 0.85
# Para adicionar novo desconto: crie uma nova classe. Zero modificacao no codigo existente.
L – Liskov Substitution Principle (LSP)
Principio: subclasses devem poder substituir suas superclasses sem quebrar o programa. Se B herda de A, voce deve poder usar B em qualquer lugar que espera A.
Violacao classica: Retangulo e Quadrado. Quadrado herda de Retangulo, mas ao setar largura de um Quadrado tambem muda a altura — comportamento inesperado para quem espera um Retangulo.
A solucao: prefira composicao sobre heranca. Se Quadrado nao se comporta como Retangulo em todos os cenarios, nao deveria herdar de Retangulo.
I – Interface Segregation Principle (ISP)
Principio: clientes nao devem depender de interfaces que nao usam. Prefira muitas interfaces especificas a uma interface generica grande.
Ruim: interface Worker com metodos work(), eat(), sleep(). Um robo implementa Worker mas nao come nem dorme — forcado a ter metodos vazios.
Bom: interfaces separadas Workable(work), Eatable(eat), Sleepable(sleep). O robo implementa apenas Workable.
D – Dependency Inversion Principle (DIP)
Principio: modulos de alto nivel nao devem depender de modulos de baixo nivel. Ambos devem depender de abstracoes.
Ruim:
class OrderService:
def __init__(self):
self.db = PostgreSQLDatabase() # Dependencia direta!
self.email = GmailService() # Dependencia direta!
Bom:
class OrderService:
def __init__(self, db: Database, email: EmailService):
self.db = db
self.email = email
# Injecao de dependencia:
order_service = OrderService(db=PostgreSQLDatabase(), email=GmailService())
# Em testes:
order_service = OrderService(db=InMemoryDatabase(), email=FakeEmailService())
O OrderService depende de abstracoes (Database, EmailService), nao de implementacoes concretas. Isso permite trocar implementacoes facilmente — inclusive para testes.
SOLID na pratica do dia a dia
Nao aplique SOLID cegamente. Em projetos pequenos ou scripts, SOLID pode ser over-engineering. A chave e reconhecer QUANDO o principio resolve um problema real: se voce precisa adicionar comportamento frequentemente (use OCP). Se classes estao crescendo demais (aplique SRP). Se testes exigem setup complexo (aplique DIP). SOLID e um guia, nao dogma.
Tem um projeto em mente?
Somos especialistas em transformar ideias em produtos digitais. Apps, sites, automações e IA — vamos construir juntos.