Em 2010 insisti no conceito do Repositório como peça fundamental do andar de domínio.Era a mudança de paradigma mais relevante na época. Este tempo todo depois e parece não ter vingado. As pessoas ainda pensam em termos de DAO. Mas isto me pôs a pensar o que mais falta nos designs de hoje em dia. Além do isolamento da UI que falei outro dia, que é um assunto mais complexo, um ponto importante é a proteção do domínio.
A proteção do domínio significa ter a habilidade de mover as classes do domínio de uma arquitetura para outra, ou em outras palavras reaproveitar a camada de domínio mesmo quando todas as outras mudam. Afinal, é no domínio que estão as regras mais importantes e que queremos preservar entre versões do produto.
Um padrão muito esquecido e mal compreendido é o Service Façade (Serviço de Fachada) ou simplesmente Façade (sim, com cedilha). Ele pode nos ajudar a proteger melhor o domínio.
A ideia do padrão é muito simples. Crie-se um contrato – como em qualquer Service – e deixe o mundo exterior (lei-a-se as camadas superiores) apenas interagirem com esse contrato. Mas em vez de implementarmos os métodos desse contrato na implementação do serviço, vamos usar um pouco de composição. Vamos deixar a implementação apenas coordenar invocações a outros objetos. Em particular vamos orquestrar a chamada de outros serviços. Isto é um pouco como SOA (Service Oriented Architecture). O papel do Service Façade é prover um ponto publico de acesso e orquestrar a distribuição do trabalho.
O contrato publico só mudará se o domínio ganhar funcionalidade enquanto a implementação mudará sempre que o domínio for refatorado, o que acontece com mais frequência.
Sendo que o contrato publico é quase-imutável podemos facilmente – e hoje em dia é realmente simples – publicar este contrato como um web-service ( seja SOAP ou REST, vc escolhe). Ganhamos assim um coração de funcionalidades que isolam todo o problema do estado e das regras e realmente podem ser reutilizados mesmo quando mudamos a camada de UI.
A importância de desenhar os sistemas assim tem um aspecto de diminuição dos riscos e reaproveitamento não apenas do código mas das funcionalidades. Por outro lado leva a um apuramento mais elevado no design do domínio. Muitas vezes as camadas de baixo são quase que desenhadas para responder à camada de UI como se fosse tentáculos dela até ao banco de dados. Isto é extremamente prejudicial se e quando quisermos mudar a UI ou colocar um novo ponto publico de acesso, como um web-service ou um applet – ou , hoje em dia, acesso via smartfone. Ou mesmo quando queremos criar nova funcionalidade aproveitando o que temos.
Por outro lado, o Service Façade nos dá a possibilidade técnica de amarrar todas as considerações de transação em um só ponto o que nos deixa livres para usar outros tipos de objetos mais interessantes na camada de domínio. No tempo do EJB 2.1 tudo eram StatelessBeans e uns se invocavam as outros. Isto causava um complicação tremenda e era um das causas de esforço árduo no EJB 2.1. Contudo mudando para EJB3.x simplificou-se a forma de escrever o bean, mas não se mudou o conceito que apenas StatelessBeans são “autorizados” a serem usados. Muitas vezes criando pontos de conflito entre as configurações de transacionamento entre eles. Já para não falar do controle do contexto de segurança e log. Sendo o contrato do Service Façade publico, nada mais normal que seja ele o candidato a invocações remotas. Isto era patente no EJB 2.1 onde todos os Stateless eram remotos. Os Stateless eram, e ainda são, desenhados para serem apenas Façades e não componentes parrudos do domínio.
Hoje podemos pensar num modelo mais elegante em que o Serviçe Façade atua como um “cut-point” onde todos os aspetos de um aplicação EE podem ser injetados , controlados e todos os contratos da camada de domínio podem ser publicados. Por dentro iremos invocar objetos como Repositório, outros Service (de outros domínios, por exemplo, ou serviços de infra como enviar email) mas também Validator , Strategies , Entidades , States e State Machines e outros que são realmente o que usamos no dia a dia, mas tentamos encaixar na definição de um Stateless Bean. Com a moderna injeção de dependências fica ainda mais fácil criar objetos que contém a lógica de negócio mas não são atrelados ao container nem a coisas chatas como controle de exceptions, rollback e chamadas remotas.
Com objetos de domínio mais simples – POJOs , na realidade – obtemos como bônus domínios mais simples de testar pois tudo está numa camada só e podemos dublar ( fazer dublês , mocks) das camadas de baixo.
Aceitando o papel do Service Façade ha que aceitar menos superfície da camada de domínio ( ou seja, menos métodos públicos) Não cair na tentação de criar um Serviço que busca a entidade A, outro a B e outro a C e sim fazer um serviço que busca qualquer uma ( uma fachada do domain store). Utilizar builders no lado cliente para construir objetos com todas as instruções para um transação e ter apenas um serviço para executar essas instruções em vez de fazer a UI chamar vários serviços diferentes. Ou seja, limpar o máximo possível os serviços de fachada de métodos repetidos e ambíguos, diminuindo a interação publica os métodos mais simples possível.
Proteger o domínio usando o padrão Service Façade pode ajudar muito na simplificação da implementação do domínio, no contrato publico e na separação de responsabilidades. Além que aumenta a portabilidade do domínio para outras versões do software sem ter que o reescrever e inclusive disponibilizá-lo com uma aplicação à parte.
Porque o padrão não é complexo um passo que você pode dar hoje mesmo é refactorar toda a logica de orquestração dos actions e managed beans da sua UI e jogar num Service Façade. Depois limpe a fachada e terá um sistema mais fácil de gerenciar com pouco trabalho e pouco esforço. Experimente e diga-me se não é tão simples…
Muito interessante essa abordagem. Nesse sentido a validação de parâmetros nos métodos do Service Facade? Ou ela somente delega para serviços que já tem essa validação?
O Service Façade é capaz de invocar qualquer coisa na camada de dominio, o que significa que ele pode invocar Validators (no texto eu escrevi “Por dentro iremos invocar objetos como Repositório, outros Service (de outros domínios, por exemplo, ou serviços de infra como enviar email) mas também Validator(…)” ) É o Validator que mantém as regras de validação e não nenhum serviço em particular. Pode acontecer que outro serviço use o mesmo validator. Isto é melhor que delegar a um outro serviço apenas para ele validar e permite encapsular a logica de validação em apenas um lugar. Contudo, na prática é incomum que vc reaproveite os validadores, isto porque um façade recebe parametros minimos e normalmente como tipos primitivos ou sstring. Por exemplo, imagine uma serviço EfetivaPedido que recebe o id do pedido. Internamente o façade vai validar se o ir realmente corresponde a um pedido, vai usar um repositorio para obter o pedido propriamente dito, vai usar um outro serviço para modificar o estoque dos produtos do pedido, vai usar outro serviço para enviar a nota fiscal, etc.. etc.. Cada um destes serviços adicionais vai fazer suas próprias validações porque os parametros que eles recebem são diferentes. Se realmente existir uma validação comum, o validador será usado em mais que um lugar, se não, ele é usado no serviço que precisa da regras. O que interessa é que a regra nunca fica no código do serviço, fica em outro objeto e o façade é livre de chamar esse objeto , tal como seria livre de chamar qualquer outro daquela camada.
Também tenho percebido que são muito utilizados os controllers de algum framework como orquestradores para chamadas de serviços. Só que dessa forma vc perde a capacidade de reaproveitamento da funcionalidade realizada pelo controller caso vc mude de framework. Então acho que esse orquestramento nao deveria estar nesses controller que estão atrelados a um framework específico. O que vc acha?
É isso mesmo Eduardo. O controller é muitas vezes usado como um orquestrador e isso está errado. O certo é transportar esse código para um serviço e depois o controlador só faz uma chamada a esse serviço. Nos tempos do EJB2.1 onde usava muito remote, as pessoas davam mais atenção a isto, porque cada invocação ao serviço pode ser – em potencial – remota, pois como o controlador só vê uma interface nada me impede de lhe dar um proxy remoto em vez do serviço real. Secando a chaamda para uma única invocação a um Façade este problema também é resolvido.
Interessante. De forma tal que o controller somente deveria ter uma chamada para um serviço e o restante do código deveria ser redirecionamentos para páginas específicas ou tarefas de parser no caso de controller de webservice. (parseando xml ou json)