Depois de entender o poder da abstração e dos plugins, chegou a hora de subir mais um degrau. E se, em vez de compilar as regras do sistema, você as carregasse de um arquivo JSON? E se as ações fossem apenas nomes ligados a comportamentos, como num mini interpretador?
Bem-vindo à próxima fronteira: sistemas configuráveis por dicionários de ações.
Um mini interpretador
Vamos imaginar que seu sistema precisa executar diferentes tarefas com base em um plano de ações definido por um cliente. Esse plano vem em um JSON como:
[
{ "acao": "EnviarEmail", "para": "cliente@exemplo.com" },
{ "acao": "GerarPDF", "arquivo": "relatorio.pdf" },
{ "acao": "AtualizarStatus", "id": 123, "status": "concluido" }
]
Em vez de codificar essas três ações na lógica principal, você pode registrá-las como comandos:
type
TActionProc = reference to procedure(Params: TJSONObject);
var
ActionMap: TDictionary<string, TActionProc>;
procedure RegisterAction(Name: string; Proc: TActionProc);
begin
ActionMap.AddOrSetValue(Name, Proc);
end;
Registrando as ações
RegisterAction('EnviarEmail',
procedure(Params: TJSONObject)
begin
SendEmail(Params.GetValue('para').Value);
end);
RegisterAction('GerarPDF',
procedure(Params: TJSONObject)
begin
ExportPDF(Params.GetValue('arquivo').Value);
end);
Executando
procedure ExecuteActions(ALista: TJSONArray);
var
Item: TJSONValue;
Acao: string;
Params: TJSONObject;
begin
for Item in ALista do
begin
Params := Item as TJSONObject;
Acao := Params.GetValue('acao').Value;
if ActionMap.ContainsKey(Acao) then
ActionMap[Acao](Params)
else
ShowMessage('Ação desconhecida: ' + Acao);
end;
end;
O que você ganhou com isso?
- Ações podem ser definidas por um cliente, consultor ou outro sistema
- Não há recompilação
- Código desacoplado e dinâmico
- Possibilidade de fallback para ações não reconhecidas
E se a ação não existir?
Você pode criar uma ação "Default":
ActionMap.AddOrSetValue('DEFAULT',
procedure(Params: TJSONObject)
begin
Log('Ação desconhecida: ' + Params.GetValue('acao').Value);
end);
E então mudar o bloco de execução:
if ActionMap.ContainsKey(Acao) then
ActionMap[Acao](Params)
else
ActionMap['DEFAULT'](Params);
Isso é ou não é acoplamento?
Sim. Mas agora você está acoplado a nomes de ações, não a implementações. A fronteira foi movida do código para o JSON. E isso muda tudo.
Possibilidades futuras
- Carregar plugins de DLLs e registrar dinamicamente
- Criar uma linguagem declarativa própria
- Criar filtros e condicionais dentro do JSON
- Validar sequências de execução
Conclusão
A ideia de dicionários de ações transforma o seu código em uma engine.
E uma engine bem feita pode durar décadas, mesmo que as regras mudem todo mês.
A capacidade de interpretar comportamentos, e não apenas codificá-los, é o que separa um sistema comum de uma verdadeira plataforma.
Próximo artigo sugerido: "Condicionais no JSON: tomando decisões fora do código"