Também adoto um padrão parecido, onde possuo objetos de selecção ao invés de métodos para diversos critérios.
ex:
class VendaFiltro {
public void filtrarPorProduto(int codigo) {}
public void filtrarPorVendedor(int codigo) {}
}
// codigo cliente
VendaFiltro filtro = new VendaFiltro();
filtro.filtrarPorProduto(1);
List list = VendaRepositorio.listar(filtro);
O uso da transação com autosave é realmente muito bom, mas também acho que é confuso para nossas mentes que trabalham linearmente com o processo onde no fim “as coisas são salvas” e quem manda salvar é alguém. Determinados requisitos necessitam que as coisas sejam salvas no momento determinado pelo usuário. Nesse caso, tenho dúvidas da aplicação do autosave.
Digo isso pelo seguinte: imagine um cliente desconectado (Swing). Obtive do servidor uma lista de clientes para alterar o nome numa grid, mas só deve mudar mesmo quando eu clicar no salvar. Nesse caso, o salvar é explicito. Essa arquitetura resolveria? (essa é uma das razões para a minha preocupação com a transação)
Outra coisa é que não sei ao certo se é uma boa idéia deixar o Domain Model dependente da arquitetura. Será que não pode ocorrer um “downgrade” da arquitetura que pode me dar problemas? (só pensamentos my friend)
Vejo que a aplicação do QueryObject é bem específica para aquelas buscas por diversos parâmetros que podem ser opcionais. Não se aplica a tudo. Se for pensar assim os repositories só teriam uma operação o que semanticamente os deixariam “bem burros”. Eu aplico QueryObject em “buscas com parâmetros diferenciados”. Não sei se existem soluções mais fáceis, mas a implementação do QueryObject também causava náuseas nos programadores quando começava a se falar nos relacionamentos.
Pensando um pouco nos impactos gerados no processo:
Você concordaria comigo que o trabalho do “analista, designer ou o que for” é chegar no Domain Model? A partir dali os “programadores, codificadores ou o que for” poderiam tocar com uma grande parte dos requisitos garantidos? (lógicamente é preciso ter uma arquitetura definida que atenda esse nível de abstração).
Eu não falei que era relativa a regra de negócio (apesar de poder ser). O que eu disse foi:
Um componente, por definição reutilizável, não pode fazer suposições sobre quando transações começam ou terminam, um Caso de Uso pode servir como limite.
Seu exemplo não me permite utilizar a classe Venda em um contexto não-transacional, além de lidar com requisitos não-funcionais misturados com código de negócios.
Mas o código da transação não precisaria estar embutido na lógica de negócios. (para isso temos AOP, etc)
O método efetivar apenas delimita a operação como um todo, ou seja, para efetivar uma venda eu preciso adicionar uma venda e atualizar o meu estoque, no caso do exemplo.
Isso é um dos problemas da implementação desse padrão.
Também me perdi nisso.
Mas você ter um repositorio muito inteligente não dispensaria o uso de um objeto Manager (gerenciador) ?
É essa minha dúvida.
[quote=rodrigoy]O uso da transação com autosave é realmente muito bom, mas também acho que é confuso para nossas mentes que trabalham linearmente com o processo onde no fim “as coisas são salvas” e quem manda salvar é alguém.
[/quote]
Sim, mas isso exige um maior treinamento em OOP, creio.
Eu concordo.
Assumindo que a grid seja um objeto em memória, não há problemas, mas se grid for um daqueles “adoráveis” componentes que trazem uma tabela para um formulário vai depender de quando seu caso de uso termina. De qualquer forma o grid e seus mecanismos possuem um potencial de reutilização baixo e pode fazer algumas suposições sobre como vai ser executado (geralmente componentes de Apresentação e Aplicações têm esta característica).
Arquiteturas são por definição decisões que são difíceis de serem alteradas, mas supondo que o sejam não consigo pensar num modelo masi livre da arquitetura do que este. Veja o domain model proposto, eel não depende em nada de Hibernate, JDO, JDBC, Spring… o que ele precisa são serviços que devem ser supridos por alguém como transações e persistência. Onde você acredita que possa haver dependência?
Eu não sou contra Repositorios com metodos de pesquisa, foi apenas uma sugestão apra que você pudesse ter uma interface única para todos os seus repositórios.
De qualquer forma, ter apenas um método não significa que um objeto é burro. A função do repositório é aplicar a especificação nos seus objetos (que acaba sendo implementado por um DAO aplicando um QueryObject na persistência), ele tem diversas responsabilidades.
Da mesma forma, nada impede que você tenha uma Especificação que se traduz em “SELECT * FROM BLABLA”. O bom de usar especificações é que são conceitos de domínio, ams realmente na maioria das vezes utilizar métodos para busca é mais simples, porém, novamente, foi apenas para deixar seus repositórios gnéricos mais completos
Sim e não, mas isso tem mais a ver com metodologia e processo.
Deixa eu explicar o que estou tentando fazer com meus analistas e programadores (sim, meu projeto atual tem uma diferença enorma -geograficamente falando, inclusive- entre analistas/projetistas e programadores). Eu tenho 6 analistas que vão trabalhar basicamente com o domain model e testes unitários. Basicamente eles fariam isso (se o modelo de fábrica de sofwtare funcionasse, como não funciona eles vão fazer muito mais, mas este é o papel original).
Como eles vão produzir um Domain Model pronto e testado, totalmente baseado em Repository, Specification, Service e tudo mais, cabe aos programadores e a mim como arquiteto a implementação dos serviços que dão suporte ao Domain Model. Assim nós criamos os DAOs segundo a especificação de contrato dos repositórios deles, fazemos os services serem expostos como EJBs e WebServices e por aí afora.
Ter o Domain Model como POJOs de negócio usando padrões de domínio permite testar regras d enegócio o tempo todo.
No caso você quer dizer que um repositório armazena objetos de tipos definidos ex : VendasRepositorio agrupa apenas objetos vendas ?
E um Service (Manager, não sei se posso chamar assim também) pode conter uma operação que possui um fluxo de atividades com objetos colaborativos ?
Pensando melhor na sua dúvida algumas funções de um Service podem ser feitas por Repositories, basicamente as de consulta e isso volta ao papo que eu tava tendo com Rodrigo sobre expôr métodos dos Repositories.
Nada impede que você tenha um repositório Vendas, outro VendasAVista e ouro VendasCanceladas, por exemplo, mesmo que um seja superconjunto do outro. Basta saber se vai agregar algum valor ao seu sistema (e você pode, inclusive, ter um DAO só implementando as interfaces dos múltiplos Repositórios se for o caso…)
[quote=okara]
E um Service (Manager, não sei se posso chamar assim também) pode conter uma operação que possui um fluxo de atividades com objetos colaborativos ?[/quote]
Não entendi, exemplo?
Se for um Service (ou Manager) colaborar com outro, ´há quem não veja problema e há quem diga que deveria haver um Mnagaer de granularidade mais grossa controlando a interação. Eu acho que na maioria dos casos não há problema (um Service não é necessariamente um componente antes que alguém doido por CBD queira minha cabeça) na interação entre dois Services, por exemplo o de usuarios fazendo consultas através ao de grupos para criar um novo objeto.
[quote=[JUZAM]]
Mas como ficaria se fossem mais argumentos, ou seja, o cadastro de cliente tivesse uns 20 campos. Não da para passar String por String…
Qual seria uma forma legal de se fazer isso?
…
:arrow: Começar a criar o obj na action, a parte simples tipo setNome e etc, e passar esse quase obj para o factory method terminar o serviço.
[/quote]
Se sua invariante não depender de muitos destes parâmetros acho que criar o objeto na Factory passando o mínimo para obedece-la e popular o resto diretamente no objeto é a melhor maneira. Em termos de contratos não faz muita diferença se quem popula é o cliente ou a fábrica,d esde que mantida a invariante.
Se o seu objeto depender dos 20 parâmetros apra sua invariante, divida ele em mais objetos porque tem algo errado aí Uma invariante deve ser mínima, eficaz e eficiente.
Não podendo dividir por um motivo X (coisa bem rara, BTW) eu acho que adotaria o Map mesmo. Se checagem em tempo de compilação te fizer falta você pode criar um Prototype(GOF), mas se você já criar um objeto na mão não faz muito sentido usar um Factory, a menos que sua Factory faça coisas como dar ao objeto referêncais apra outros objetos de negócio encapsulados nele ou coloque ele em modo attached, por exemplo.
Ou você pode usar uma Specification um pouco diferente do conceito original. Em vez de dizer: eu quero um objeto já existente com essa característica você poderia dizer: crie um objeto pra mim que passe nesta especificação.
Poder pode, mas eu não faria isso, não criaria Métodos com efeitos colaterais em um repositório.
Se você tem um processo em batch e quer abstrair uma Stored Procedure, por exemplo, pode ter um método no Repositório que aceite e execute um Command (que, em sua implementação, and amais faz que chamar uma SP via DAO) mas este fluxo deve começar no Service.
Fundamentei o exemplo na situação do Domain Object “Cliente” não ter uma operação salvar() pois ele usa o autosave do container. Nesse meu exemplo o que o botão salvar chamaria?
Digamos o seguinte: se eu não colocar as operações “salvar()” nas minhas Domain Classes faço isso porque a minha arquitetura permite o “autoSave”. Correto? Estou partindo da abstração que os objetos se salvam sozinhos quando “mexidos”. E se eu dar um downgrade na minha arquitetura para uma que não permite isso?
(é um casinho meio estúpido, nem precisa responder, mas é só para exemplificar que o Domain Model não é realmente dependente da arquitetura, mas é dependente das facilidades que a arquitetura proporciona). Isso dá margem para escrever “Refactoring Domain Model”, ha ha ha ha…
OK! É precisamos tomar cuidado com essas decisões… Imagine se os seus “analistas/designers” que estão lá longe no seu projeto decidam só usar QueryObject :? (afinal a análise fica mais simples, o programador é que se vire para implementar).
Acho a abordagem de vcs muito acertada. Como eles demonstram a apresentação ou os boundaries (conversa ApAp <-> Domain).
Você critica o funcionamento de fábricas em geral ou particularmente a sua?
Depende. Ele éremoto? Se for chame o método no servidor que atualiza. Ele é local? Então não vejou outra opção além de chamar uma abstração para commit.
Pois é, são os serviços que a arquitetura assume estarem disponíveis, porém não amarrados a uma tecnologia em específico. Mudar isso implica mudar a arquitetura. Uma mudança mais amena poderia utilizar AOP para chamar o save() ou na pior das hipóteses fazer na Camda de Aplicação ou de Apresentação, mantendo ainda o Domain Model limpo dentro do possível.
No caso aqui o maior problema na verdade é lazy loading, esta sim é uma decisão arquitetural difícil de remover.
Por este tipo de coisa que eu não acredito em design separado de implementação para linguagens de alto nível modernas
mas de qualquer forma não consigo pesnar em algo tããão grave que possa ser feito com uma Specification. Além disso, sendo Specification uma abstração não necessariamente ela vai ser um QueryObject. Que tal?
public class ListarUsuariosSpec implements Specification{
private UsuarioDao dao = null//injete aqui seu DAO
public List<Usuario> aplicar(){
return dao.listarusuarios();
}
}
Hm… não entendi, foi uma pergunta?
Em geral. Nunca vi o modelo 9a) funcionar (b) produzir algo de qualidade. O modelo talvez funcione se seguido a risca os princípios de Engenharia de Sofwtare mas eu sou do time que acha que Engenharia de Sofwtare (metodologia do SEI criada na OTAN) só serve, e mesmo assim talvez, apra projetos muito grandes geralmente onde o ahrdware é mais importante que o software e vai ser desenvolvido em apralelo.
Para gestão de informação essas práticas nunca me mostraram resultados reais, eu só vejo 9em projetos que participei ou não) desculpas sobre porque a metodologia não dá certo e promessas que da próxima vez vai ser diferente.
Outro dia tive que ouvir um " a documentação está defasada em relação ao código porque brasileiro não tem cultura de fazer design". Como se desse certo em algum outro país…
[quote=pcalcado]No caso aqui o maior problema na verdade é lazy loading, esta sim é uma decisão arquitetural difícil de remover.
[/quote]
Nem me fale… esses frameworks como o Hibernate resolveram um problemão… implementar Proxies (como exemplo) é uma pentelhação. Realmente no caso de um downgrade tão violento assim daria vontade até de pular fora do projeto… :shock:
É, é uma pergunta. Como os seus designers do projeto passam a ligação entre as boundary classes e o domain? Fazem um SD?
Comentei que a abordagem é acertada pois sempre temos um problema quando o designer entrega o modelo UML diretamente para a codificação. Da forma que vocês estão trabalhando o modelo (que no caso é o próprio código) é testável, coisa que a UML não é (não me venham com diagrama de objetos). Não é uma crítica à UML, mas sim aos designers. Eles devem aplicar a boa prática de continuamente testar o software e não se esconder atrás do modelo.
[quote=pcalcado]
Em geral. Nunca vi o modelo 9a) funcionar (b) produzir algo de qualidade. O modelo talvez funcione se seguido a risca os princípios de Engenharia de Sofwtare mas eu sou do time que acha que Engenharia de Sofwtare (metodologia do SEI criada na OTAN) só serve, e mesmo assim talvez, apra projetos muito grandes geralmente onde o ahrdware é mais importante que o software e vai ser desenvolvido em apralelo.
Para gestão de informação essas práticas nunca me mostraram resultados reais, eu só vejo 9em projetos que participei ou não) desculpas sobre porque a metodologia não dá certo e promessas que da próxima vez vai ser diferente.
Outro dia tive que ouvir um " a documentação está defasada em relação ao código porque brasileiro não tem cultura de fazer design". Como se desse certo em algum outro país… :P[/quote]
Tem que levar em consideração que é difícil achar um gestor que saiba aplicar a metodologia certa no projeto certo (geralmente ele adota o WUP - Waterfall Unified Process). Faço uma crítica muito grande aos gestores de projetos de software em geral.
Documentação é uma palavra que não posso mais ouvir. Já acompanhei duas implantações de CMM. Não ví ganho nenhum na implantação da certificação (fora a churrascada grátis quando pegamos o “selo”), o processo ficou pesadíssimo e Cataratas do Iguaçu. Ví um repositório com 500mb de documentação.
Eu gosto de modelar usando a UML, mas uso a UML como ferramenta de análise. A UML é para descobrir informações. É o que tento explicar para os meus alunos. Não sou “xiita” ao ponto de jogar fora os diagramas (Fowler). Estou para fazer uns testes. Imagino que se o designer se focar em modelar em UML somente o Domain Model suas ligações com as Boundaries os problemas na sincronização do código com o modelo podem ser bem minimizadas, fora que esse designer seria independente de plataforma, arquitetura e etc… (mas é só um teste, acredito que para uma fábrica hibrida JAVA/.NET isso pode ser bom, o designer se encaixa em qualquer projeto sem conhecer as entranhas da arquitetura).