Solucionado (ver solução)
Solucionado
(ver solução)
14
respostas

Diversas dúvidas sobre regras de negócio e padrões de projeto no "modelo".

Sempre que vejo exemplos de código (em livros ou fóruns) utilizando JSF/MVC fico em dúvida sobre a camada do modelo. Será que não esta faltando maiores explicações do que realmente engloba a camada de modelo X boas práticas?

Basicamente: - Geralmente nos códigos que vemos a camada de visualização tem acesso direto ao modelo. Vi em alguns fóruns da Caelum a afirmação de que dar acesso direto ao modelo na visualização não é uma boa prática. - Até então eu não vi exemplos nos cursos onde a camada de modelo "encapsula" as regras de negócio + as entidades, principalmente quando se fala em JSF. Muito pelo contrário, geralmente o que vemos é a camada de visualização acessando (ferindo OO) diretamente as entidades (as quais não possuem regras).

Aí vai as questões: - Se dar acesso ao modelo (a entidade) na visualização não é uma boa prática então como seria a implementação da boa prática?

  • Supondo que a minha base de dados (relacional) não represente um modelo OO, fatalmente teremos que criar classes que englobam tanto as regras de negócio como também o preenchimento dos atributos (setters) das entidades? (Desmontar o brinquedo para armazená-lo).

  • Mesmo que a minha base de dados representasse um modelo OO ainda assim entendo que o LivroBean não poderia de maneira alguma utilizar/manipular o livro(entidade) pois ele pode ferir qualquer regra de negócio. Estou certo? Por exemplo o método this.livro.removeAutor(autor) pode possuir uma regra de negócio que somente permite excluir o autor se X + Y for verdadeiro. Porém ainda posso fazer do jeito antigo/errado que seria this.livro.getAutores().remove(autor). Como tratar esta situação (eu poderia alterar getAutores para private)?

14 respostas
solução!

Oi André, acho que melhor que seguir uma regra é ter bom senso no código. A sua view ter acessa a sua entidade só seria ruim se vc tivesse fazendo código nessa entidade para satisfazer a view. Outra situação é ficar invocando métodos de leitura dos objetos(getters), esses também, em geral, não causam nada muito ruim para a manutenção.

Agora, caso o seu formulário seja diferente da sua entidade, aí vc deve parar e pensar.. Já que talvez não valha a pena fazer código na entidade que não tem a ver com o negócio, e sim só com a view. Nesses casos, vc pode criar uma classe estritatamente ligada ao form, como um ModeloForm e a partir dos dados enviados vc pode criar o objeto de domínio. No Spring eles chamam de ModelAndView.

Em relação a tabela ter uma estrutura diferente da entidade, em geral só acontece se vc começar pelo banco de dados. A JPA prevê que as colunas da tabela estejam mapeadas pelos atributos da entidade, não tem jeito :).

Olá pessoal

Acredito que por mais simples que seja a aplicação permitir o acesso da view direto a entidade é muito perigoso.

Tomando como exemplo o código abaixo:

@ManagedBean
public class EmpregadoBean {

    private Empregado empregado = new Empregado();

    public Empregado getEmpregado() {
        return empregado;
    }

    public void salvar() {

        if (empregado.getCpf().equals("")) {
            throw new RuntimeException("Informe o CPF.");
        }

        new DAO<Empregado>(Empregado.class).adiciona(this.empregado);
    }

}

Neste exemplo problema 1: getEmpregado() O que impede a view de atualizar qualquer atributo da entidade? Ou pior dependo do modelo de dados eu poderia acessar a lista de dependentes e modificar seus atributos ou dar um "Remove". Em resumo dei acesso à base de dados pra view sem qualquer controle.

problema 2: salvar() O método salvar tem uma regra! tem regras no EmpregadoBean. A regra não deveria estar no modelo? Se eu criar um outro salvar e esquecer das regras ... o modelo em si não garante a integridade do negócio.

Em resumo A questão que quero colocar é se o modelo é o domínio, o coração da aplicação com as regras de negócios por que não achamos exemplos de código com tais regras utilizando JSF? Eu tenho muita dúvida de como resolver tais questões, mantendo o encapsulamento e coesão das coisas. Sei que não existe receita de bolo rsrs, mas eu desejo muito ver "um" exemplo de código que realmente faça jus a OO.

Olá,

Existe uma discussão antiga entre DAO e JPA. Com o surgimento do JPA, existem defensores da ideia de que a camada DAO não seria mais necessário. Outros utilizam a camada DAO com o JPA embutido nesse.

Você está enganado, os cursos de JSF utilizam a camada DAO e os Beans é que controlam e quem contém as regras do negócio, a view somente tem acesso àquilo que os Beans deixam passar.

Não é boa prática acessar os dao's diretamente dentro da view, por exemplo: "...action="#{livroDao.salvar(livro)}".

Sim, o modelo é o domínio, o coração da aplicação com as regras de negócios, e se traduzi na utilização dos beans !

E não confunda POO (Programação Orientada a Objetos) com Design Patterns (Padrões de Desenho) !

Atenciosamente.

Oi André, a sua preocupação de alguém da view atualizar algo no modelo é super justa, pensando no cenário extremo, pelo menos para mim, o melhor é só ficar na view objetos com métodos de leitura. A única coisa que eu sempre pontuo é o design ótimo x esforço da solução, por isso que prego o bom senso.

Em relação a operação de salvar um empregado, eu discordo. Não acho que ela deva ficar dentro da classe Empregado.. Acho que ela pode ficar em um DAO e o seu bean chamar, sem problemas. Agora, caso não seja só salvar, tenha mais lógica envolvida aí, sou a favor de isolar numa classe que represente a lógica.

Olá,

Mas o princípio básico de um sistema, do processamento de dados, é receber as entradas, manipulá-las dentro da "caixinha fechada do sistema" e então entregar as saídas.

Então sempre haverá entradas e saídas ! Quer seja no design pattern Model View Controller ou Component Based. A view é utilizada para entrada e saída de dados.

Legal pessoal,

Realmente minha preocupação é de alguém da view atualizar algo no modelo sem passar pelas regras.

Imaginem o seguinte cenário: Tenho uma equipe em que parte das pessoas ficaram mais focadas no modelo e outras na view. As que vão trabalhar no modelo tem que garantir a coesão das informações, para isso temos que estabelecer onde iremos colocar tais regras.

Se tomarmos por base o exemplo do @ManagedBean->EmpregadoBean (que faz a ponte da view com o modelo) eu não poderia ter nenhuma regra nele, visto que além de ser passível de falhas eu posso ter diversas telas (com formatos muito diferentes) que irão atualizar informações no Empregado. Então não dá pra ficar "copiando" as regras.

Com relação à regras ficarem no DAO é uma boa alternativa, no entanto, gostaria de partir do principio que eu tenho muita regra de negócio e também teremos que pensar em escalabilidade (portanto o design ótimo x esforço é pertinente).

Portanto peço que opinem sobre a conclusão que chegamos (o que vocês recomendam?).

Pelo que avaliamos aqui de acordo com as suas respostas talvez o melhor cenário pra este projeto seria:

  1. Ter as entidades somente com as validações "padrões" da JPA.

  2. Ter o EmpregadoRN (regra de negócio) que encapsula todas as validações condicionais (o empregado X não pode ser alterado se alguma coisa, ou ele não pode ser excluído se outra coisa) mais as regras de negócio em si (ao salvar um novo empregado deve ser criado o login automático na aplicação do portal RH).

  3. E por fim temos o @ManagedBean->EmpregadoBean que faria somente a ponte chamando o EmpregadoRN. Sem dar acesso do empregado (entity) a view. Exemplo:

@ManagedBean
public class NovoEmpregadoBean {

    private Empregado empregado = new Empregado();
    private EmpregadoRN empregadoRn = new EmpregadoRN();

   private String nomeEmpregado;
   private String cpfEmpregado;

    public String getNomeEmpregado() {
        return nomeEmpregado;
    }
    public void setNomeEmpregado(String nome) {
        this.nomeEmpregado = nome;
    }

    public String getCpfEmpregado() {
        return CpfEmpregado;
    }
    public void setCpfEmpregado(String Cpf) {
        this.CpfEmpregado = Cpf;
    }

    public void salvar() {
        empregado.nome = nomeEmpregado;
        empregado.cpf = cpfEmpregado;
        empregado.isAtivo = true;
        empregadoRN.salvar(empregado);

}

Neste exemplo a view somente tem acesso ao bean que por sua vez conhece o contexto da entidade e sabe como utilizá-la da melhor maneira. Ou seja ele sabe como dar os setters necessários e também como chamar a ação pra executar a regra.

Olá,

"Com relação à regras ficarem no DAO é uma boa alternativa", não é boa alternativa, é uma péssima decisão.

Você está bastante confuso sobre arquitetura de software e design patterns.

E outra coisa, é uma boa prática a utilização de CDI, assim o bean utilizaria a anotação @Named ao invés de @ManagedBean .

Acho que só as palavras ficaram confusas, já que ele mostrou que queria classes específicas para regras de negócio. De novo, eu não gosto dessa decisão estática, independente da situação.. Acaba com um monte de classe de "regra de negócio" bobocas, que só delegam para o dao e não acrescentam nada de útil.

Pessoal

Com relação ao @ManagedBean não era a questão, somente usei o "mesmo" exemplo do curso, mas valeu.

Já o DAO ter regras ... legal, realmente me confundi (esta claro esta questão).

Agora, falando da decisão estática. Em um mesmo projeto você implementaria as 2 situações, criando uma cara pra alguns e pra outros não?

Olá,

Um exemplo: Java e Domain-Driven Design na prática - Java Magazine 87

Olá,

Outro exemplo: Domain-driven Design with JSF, EJB and CDI

E outo exemplo usando as camadas DAO, Facade e Model: Aplicação Web Completa Tomcat JSF Primefaces JPA Hibernate

Oi André, sim! Óbvio, depende da maturidade do time envolvido no projeto e tudo mais.. Mas para mim, passar essa ideia de bom senso e adaptação para cada situação é muito importante.

Olá,

E também recomendo o livro Introdução à Arquitetura e Design de Software da Casa do Código

Cita, por exemplo, que Repository não é a mesma coisa que DAO.

Pessoal,

Obrigado pelas respostas. Vocês me ajudaram muito. Até a próxima.