Regras de negócio definem decisões importantes. Elas capturam políticas e lógica da organização. Primeiramente, uma simulação aplica essas regras repetidamente. Dessa forma, permite testar cenários antes da implementação real. Por exemplo, “se renda maior que 2000 então aprovar crédito”. Sem regras, o código fica cheio de if-else espalhados. Além disso, alterar regras exige mudanças no código fonte. Com simulação declarativa, as regras ficam isoladas. Portanto, a manutenção se torna muito mais simples. Assim, os especialistas de negócio podem validar diretamente. Empresas ágeis adotaram essa abordagem. Consequentemente, erros são detectados mais cedo.
Características fundamentais da simulação com regras
Uma característica central envolve a separação lógica-dados. As regras residem em um módulo isolado da aplicação. Outra propriedade importante é o encadeamento de regras. Uma regra pode disparar outra automaticamente. Isso se chama inferência em cadeia. O motor de regras gerencia esse fluxo complexo. Além disso, regras podem ter prioridades diversas. Regras mais específicas sobrepõem as genéricas. Isso resolve conflitos de decisão naturalmente. Uma fórmula que representa uma regra é:
Outra característica consiste na transparência da decisão. Cada regra pode usar documentação em linguagem natural. Isso facilita auditoria e conformidade regulatória. Por exemplo, “cliente VIP recebe 15% de desconto”. Os stakeholders entendem sem conhecimento técnico. Consequentemente, a comunicação melhora significativamente.
Quando utilizar simulação baseada em regras
Use simulação para sistemas de aprovação automatizada. Crédito, empréstimos e seguros são exemplos clássicos. Além disso, use para motores de recomendação de produtos. Sistemas de precificação dinâmica se beneficiam muito. Outro bom uso aparece na validação de formulários complexos. Regras de elegibilidade para benefícios fiscais se aplicam. Da mesma forma, use para simular cenários “e se”. “E se aumentarmos o desconto para 20%?” é testável. Por outro lado, evite regras para processos com muitas exceções. Se o número de regras ultrapassar 500, avalie alternativas. Primeiramente, comece com um pequeno conjunto de regras. Depois, expanda gradualmente conforme necessário. Portanto, simulação com regras escala bem inicialmente.
Outro bom uso funciona em jogos de estratégia com regras. Simule jogadores virtuais seguindo regras fixas. Da mesma maneira, use em chatbots baseados em decisões estruturadas. Sistemas especialistas popularizaram isso nos anos 80. Hoje, ainda é útil para domínios bem definidos. Portanto, não subestime essa abordagem clássica. Em suma, a versatilidade das regras é notável.
Exemplo prático: sistema de aprovação de crédito
O código abaixo implementa um motor de regras simples. A base de conhecimento contém fatos sobre clientes. Um conjunto de regras avalia cada cliente candidato. As regras são representadas como funções puras. Primeiramente, coletamos todas as condições satisfeitas. Depois, aplicamos as ações correspondentes. Observe como as regras são fáceis de ler e modificar. Nenhum if-else aninhado polui a lógica principal. Além disso, novas regras são adicionadas sem dor. Vamos ao código completo com vários exemplos.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
# ============================================ # SISTEMA DE REGRAS PARA APROVAÇÃO DE CRÉDITO # ============================================ from typing import Dict, List, Callable, Any from dataclasses import dataclass from enum import Enum class Decisao(Enum): APROVADO = "Aprovado" REPROVADO = "Reprovado" REVISAR_MANUAL = "Revisar manualmente" @dataclass class Cliente: nome: str renda_mensal: float divida_total: float score_credito: int tempo_emprego_meses: int idade: int ja_cliente: bool = False quantidade_parcelas_sugerida: int = 0 @dataclass class ResultadoAvaliacao: cliente_nome: str decisao: Decisao razoes: List[str] score_final: int valor_maximo: float parcelas_sugeridas: int # ============================================ # BASE DE REGRAS (DEFINIDAS DECLARATIVAMENTE) # ============================================ # Formato: (condicao, acao, descricao) regras = [] def regra(condicao, acao, descricao): """Decorador para adicionar regras à base.""" regras.append((condicao, acao, descricao)) return acao # Regras de reprovação (motivos bloqueantes) def motivo_reprovacao(cond): return lambda dados: cond(dados) @regra( lambda c: c.score_credito < 300, lambda c: "Score abaixo de 300", "Cliente com score muito baixo é reprovado automaticamente" ) def regra_score_minimo(cliente): return "Score abaixo de 300" @regra( lambda c: c.renda_mensal < 1000, lambda c: "Renda abaixo de R$ 1.000", "Renda mínima necessária é R$ 1.000" ) def regra_renda_minima(cliente): return "Renda abaixo de R$ 1.000" @regra( lambda c: c.idade < 18, lambda c: "Idade mínima não atingida (18 anos)", "Cliente deve ser maior de idade" ) def regra_idade_minima(cliente): return "Idade mínima não atingida" @regra( lambda c: (c.divida_total / c.renda_mensal) > 0.5, lambda c: f"Comprometimento de renda alto: {(c.divida_total/c.renda_mensal)*100:.1f}%", "Dívida não pode exceder 50% da renda mensal" ) def regra_comprometimento(cliente): return f"Comprometimento de renda alto" # Regras de bonificação (aumento de score) @regra( lambda c: c.tempo_emprego_meses > 24, lambda c: 15, "Bônus de +15 pontos por tempo de emprego (>2 anos)" ) def bonus_tempo_emprego(cliente): return 15 @regra( lambda c: c.ja_cliente, lambda c: 10, "Bônus de +10 pontos por ser cliente antigo" ) def bonus_cliente_antigo(cliente): return 10 @regra( lambda c: c.idade >= 25 and c.idade <= 40, lambda c: 5, "Bônus de +5 pontos pela faixa etária ideal" ) def bonus_idade(cliente): return 5 # Regras de decisão final baseadas no score final def calcular_valor_aprovado(score, renda): """Calcula valor máximo de crédito baseado no score.""" if score >= 700: return renda * 0.8 # 80% da renda elif score >= 500: return renda * 0.5 elif score >= 350: return renda * 0.3 else: return 0 def calcular_parcelas(score, renda, valor): """Sugere número de parcelas baseado no score.""" if score >= 700: return min(36, int(valor / (renda * 0.1))) elif score >= 500: return min(24, int(valor / (renda * 0.15))) else: return 12 # ============================================ # MOTOR DE SIMULAÇÃO # ============================================ def simular_cliente(cliente: Cliente) -> ResultadoAvaliacao: """Aplica todas as regras a um cliente e retorna decisão.""" razoes_reprovacao = [] bonus_total = 0 # Verificar regras de reprovação for condicao, acao, descricao in regras: # Se condição parece ser de reprovação (retorna string) if callable(acao) and descricao != "Bônus de ...": try: if condicao(cliente): resultado = acao(cliente) if isinstance(resultado, str): razoes_reprovacao.append(resultado) except: pass # Calcular bônus (regras que retornam números) for condicao, acao, descricao in regras: if "Bônus" in descricao and callable(condicao): if condicao(cliente): if callable(acao): bonus = acao(cliente) if isinstance(bonus, (int, float)): bonus_total += bonus # Score final score_final = cliente.score_credito + bonus_total # Decidir com base nas reprovações e score if razoes_reprovacao: decisao = Decisao.REPROVADO elif score_final >= 500: decisao = Decisao.APROVADO elif score_final >= 350: decisao = Decisao.REVISAR_MANUAL else: decisao = Decisao.REPROVADO # Calcular valor máximo e parcelas if decisao == Decisao.APROVADO: valor_maximo = calcular_valor_aprovado(score_final, cliente.renda_mensal) parcelas = calcular_parcelas(score_final, cliente.renda_mensal, valor_maximo) else: valor_maximo = 0 parcelas = 0 return ResultadoAvaliacao( cliente_nome=cliente.nome, decisao=decisao, razoes=razoes_reprovacao, score_final=score_final, valor_maximo=valor_maximo, parcelas_sugeridas=parcelas ) # ============================================ # SIMULAÇÃO DE MÚLTIPLOS CENÁRIOS # ============================================ def simular_cenarios(clientes: List[Cliente]) -> List[ResultadoAvaliacao]: """Simula vários clientes em lote.""" resultados = [] for cliente in clientes: resultado = simular_cliente(cliente) resultados.append(resultado) return resultados def analisar_sensibilidade(cliente_base: Cliente, variavel: str, valores: List[Any]): """Testa como uma variável impacta a decisão.""" print(f"\n=== Análise de sensibilidade: {variavel} ===") for valor in valores: cliente_mod = Cliente(**cliente_base.__dict__) setattr(cliente_mod, variavel, valor) resultado = simular_cliente(cliente_mod) print(f"{variavel} = {valor}: {resultado.decisao.value} (Score: {resultado.score_final})") # ============================================ # EXECUÇÃO DOS EXEMPLOS # ============================================ if __name__ == "__main__": print("=== SIMULAÇÃO DE REGRAS DE CRÉDITO ===\n") # Cenários de teste clientes_teste = [ Cliente("Ana Silva", 5000, 1000, 720, 36, 30, True), Cliente("Carlos Souza", 800, 200, 550, 12, 25, False), Cliente("Mariana Lima", 3000, 2000, 480, 6, 22, False), Cliente("Roberto Alves", 4500, 0, 650, 48, 45, True), Cliente("Juliana M", 2000, 1200, 320, 3, 19, False), Cliente("Fernando R", 6000, 2500, 590, 18, 35, True), ] # Simular todos resultados = simular_cenarios(clientes_teste) # Exibir resultados for r in resultados: print(f"Cliente: {r.cliente_nome}") print(f" Decisão: {r.decisao.value}") print(f" Score final: {r.score_final}") if r.razoes: for razao in r.razoes: print(f" - {razao}") if r.decisao == Decisao.APROVADO: print(f" Valor máximo: R$ {r.valor_maximo:,.2f}") print(f" Parcelas sugeridas: {r.parcelas_sugeridas}x") print() # Análise de sensibilidade cliente_referencia = Cliente("Referência", 3000, 800, 550, 24, 30, True) analisar_sensibilidade(cliente_referencia, "score_credito", [300, 400, 500, 600, 700]) analisar_sensibilidade(cliente_referencia, "renda_mensal", [1500, 2500, 3500, 5000]) analisar_sensibilidade(cliente_referencia, "divida_total", [500, 1000, 1500, 2000]) # ============================================ # SIMULAÇÃO COM REGRAS BASEADAS EM PYTHON PURO # ============================================ print("\n=== Simulação de Regras com pyDatalog (Opcional) ===") print("Para simulações mais avançadas, instale pyDatalog:") print("pip install pyDatalog") # Exemplo conceitual sem dependência print("\nExemplo de regras declarativas (simuladas):") print(""" Regras para desconto progressivo: - SE valor > 1000 ENTÃO desconto = 10% - SE valor > 5000 ENTÃO desconto = 15% - SE cliente_vip ENTÃO desconto_adicional = 5% - SE primeira_compra ENTÃO desconto_adicional = 0% """) def calcular_desconto(valor, vip, primeira_compra): if valor > 5000: desconto = 0.15 elif valor > 1000: desconto = 0.10 else: desconto = 0.05 if vip: desconto += 0.05 if primeira_compra: desconto = max(0.05, desconto - 0.02) return min(desconto, 0.30) # Cap de 30% testes_desconto = [ (6000, True, False, "VIP com alto valor"), (2000, False, True, "Primeira compra valor médio"), (800, False, False, "Compra pequena normal"), ] for valor, vip, primeira, desc in testes_desconto: desc_calc = calcular_desconto(valor, vip, primeira) print(f" {desc}: Valor R${valor}, VIP={vip}, 1ª compra={primeira} -> Desconto {desc_calc*100:.0f}%") |
No exemplo, as regras de negócio seguem estilo declarativo. Cada regra opera independente e permite testes fáceis. O motor de simulação aplica as regras em qualquer ordem. Primeiramente, avaliamos as regras bloqueantes. Depois, acumulamos os bônus progressivamente. A decisão final combina todas as informações disponíveis. Observe que a lógica principal não possui condicionais. Ela apenas itera sobre as regras registradas. Isso significa que novas regras são simples de adicionar. Portanto, a manutenção fica extremamente facilitada. Além disso, podemos auditar a simulação passo a passo. Cada regra aplicada ganha registro e explicação.
Outra vantagem importante consiste na análise de sensibilidade. Podemos modificar parâmetros e ver o impacto imediato. “E se o score mínimo subir para 400?” torna-se testável rapidamente. “E se aumentarmos o limite de comprometimento?” também. Isso permite decisões baseadas em dados simulados. Os stakeholders de negócio participam desse processo. Eles ajustam regras e observam resultados em tempo real. Portanto, a simulação com regras funciona como ferramenta colaborativa. Para sistemas maiores, use motores especializados como Drools. Contudo, o Python puro já resolve problemas pequenos. Primeiramente, comece com a abordagem mostrada aqui. Depois, escale se necessário. Assim, você evita complexidade prematura.
✅ Separação clara entre lógica e dados
✅ Regras legíveis por não-programadores
✅ Simulação de cenários “e se” rápida
✅ Manutenção simplificada e auditável
✅ Testes isolados por regra individual
Finalmente, documente cada regra com exemplos claros. Use casos de teste para validar o comportamento esperado. Mantenha as regras atômicas e sem efeitos colaterais. Isso facilita a composição e a depuração eficiente. Além disso, versionar regras junto ao código faz diferença. Portanto, utilize Git para rastrear mudanças históricas. Assim, você reverte alterações problemáticas rapidamente. Lembre-se: regras de negócio mudam com frequência. Simular antes de implementar em produção evita surpresas. Portanto, adote essa prática desde o início. Seu projeto se tornará mais robusto e adaptável. Aproveite os exemplos e crie seu próprio sistema de regras.