Rodrigo Allemand

Arquivo de March, 2009

DDD – Blindando o Domínio

por Rodrigo Allemand em Mar.05, 2009, em DDD

Lembram que nesse post eu falei que o domínio deveria ser fechado e bem definido? Então! A melhor maneira de fazer isso é criar uma camada que faça uma “blindagem” no domínio, definindo o acesso a ela e validando contratos para os métodos.

Contrato nada mais é do que vc garantir que o que entra no domínio está valido e o que sai está de acordo com o que o método se propõe a fazer! Retirado do Wiki do Phillip

Se quem chamar me garantir a pré-condição, eu garanto a pós-condição.

Garantir a pré-condição é garantir que todos os parâmetros que vc precisa (e recebe) para efetuar uma ação estejam de acordo com uma especificação mínima. Com isso, a pós-condição – que é a sua resposta do método (retorno) – estará garantida.

O padrão utilizado neste caso – para criar uma camada de comunicação do domínio com o mundo – é o Facade (leia-se “Fasseide”, “conjuncão de Face + ade”), um padrão de projeto citado no livro Design Patterns: Elements of Reusable Object-Oriented Softwares, da Gang of Four [Gof]. Ele cita o seguinte:

Fornece uma interface unificada para um conjunto de interfaces em um subsistema. Façade define uma interface de nivel mais alto que torna o subsistema mais facil de ser usado.

A motivação básica desse padrão é dividir sistemas em subsistemas para reduzir a complexidade do código.

Como eu falei anteriormente, um padrão pode ser desenvolvido de diversas maneiras, mas algumas implementações são tão simples que são frequentemente copiadas ao longo dos projetos. A implementação mais comum de Facade é ter um construtor privado – para impossibilitar a criação de uma instancia da classe -  e colocar os métodos da facade como estáticos. Veja o exemplo:

public class Facade {

    private Facade(){
    }

    public static String sayHello(){
        return "Hello World!";
    }
}

Dentro do seu método, vc pode perfeitamente trabalhar da maneira que melhor imaginar, porem, não convem colocar nenhuma regra de negócio ou validação dentro da facade, já que um método interno do domínio pode referenciar outro método do domínio sem necessariamente passar pela facade.

Existem tambem quem utilize uma classe para fachada, criando outras classes mais especificas para controlar cada ação, dividindo o sistema em sub-dominios, chamados por uma mesma fachada.

Blindar e validar sem ter regra de negócio? Para organizar melhor esta bagunça, Martin Fowler e Erick Evans desenvolveram o padrão Specification.

[...] business logic can be recombined by chaining the business logic together using boolean logic.

OBS.: Aqui está o PDF de Fowler sobre Specification.

Com a Specification, vc pode validar, selecionar e até mesmo construir objetos-modelo para satisfazer a sua regra de negócio. Mais uma vez, nenhum padrão tem uma implamentação fixa, todas podem variar, mas a mais utilizada para Specification em Java é a seguinte:

public interface Specification<T> {
    boolean isSatisfiedBy(T t);
}

No exemplo acima, ela retorna true ou false, caso o objeto passado esteja de acordo com a especificação. Esta especificação ainda pode ser de vários tipos, conforme alguns exemplos descrito abaixo:

public abstract class AndSpecification<T> implements Specification<T>{

    private final Specification<T> one;
    private final Specification<T> other;

    //Retorna true se o objeto passar pelas duas especificações
    public AndSpecification(Specification<T> one, Specification<T> other) {
        this.one = one;
        this.other = other;
    }

    public boolean isSatisfiedBy(T t){
        return one.isSatisfiedBy(t) && other.isSatisfiedBy(t);
    }
}
public abstract class OrSpecification<T> implements Specification<T>{

    private final Specification<T> one;
    private final Specification<T> other;

    //Retorna true se o objeto passar por uma das duas especificações
    public OrSpecification(Specification<T> one, Specification<T> other) {
        this.one = one;
        this.other = other;
    }

    public boolean isSatisfiedBy(T t){
        return one.isSatisfiedBy(t) || other.isSatisfiedBy(t);
    }
}
public interface SelectionSpecification<T> {
    //Filtra uma lista de acordo com uma especificação
    List<T> isSatisfiedBy(List<T> list);
}

Utilizando o nosso exemplo, vamos criar um exemplo para validar o cadastro de um usuário:

public class CadastrarUsuarioSpecification
    implements Specification<Usuario> {

    public boolean isSatisfiedBy(Usuario usuario) {
        if(usuario.getNome().equals("") ||
           usuario.getSenha().equals("") ||
           usuario.getLogin().equals("")){
            return false;
        }
        return true;
    }
}

OBS.: Lembrando que isso é apenas um exemplo didático, a entidade usuário do exemplo tem mais campos para serem validados!

O Dominio deve ter a sua validação independente do que vc utilize fora dele, seja Client-side com JavaScript ou Server-Side no seu servlet, por exemplo. Sempre faça o Design By Contract valer no seu domínio.

A especificação CadastrarUsuarioSpecification deve executar todas as validações necessárias para a inclusão de um usuário na base de dados. Utilizando-a em conjuntio com a Facade, teriamos algo como:

public class Facade {

    private Facade(){
    }

    public static void cadastrar(Usuario usuario){
        CadastrarUsuarioSpecification spec =
            new CadastrarUsuarioSpecification();
        if(spec.isSatisfiedBy(usuario)){
            //Cadastrar usuario
        } else {
            //Levantar erro!
        }
    }
}

Com isso, isolamos o domínio, garantimos o contrato e o seu domínio está vacinado conta possiveis erros vindo de outras camadas!

P.S.: Para o conceito de Specification não ficar vago, ainda existem muitos modelos de se contruir uma especificação, seja ela para acesso a banco, para colecionar critérios, para gerar um SQL, para filtrar uma lista, etc. O que precisamos ter em mente é que sempre que vc quizer implementar uma regra de maneira clara, procure ver antes se ela se encaixa em uma specification.

Até!

comente e Recomende!

11 Comentários :, , , , , , , , mais...

DDD – Entidades e afins

por Rodrigo Allemand em Mar.03, 2009, em DDD, Desenvolvimento

A peça chave do DDD é a Entidade (Entity).

Entidade é um objeto com um significado para o domínio sendo modelado e que possui uma identidade.

Diagrama de Classe extraido do Modelo

Diagrama de Classe extraido do Modelo

No exemplo dado no decorrer da série de post, basicamente, estas seriam as nossas entidades. Repare que todas as classes possuem uma identidade (o campo ID de cada classe). Isso define uma Entidade: a sua identificação única!

Modelo de dados extraido do Diagrama de Classes

Modelo de dados extraido do Diagrama de Classes

Pensando em um modelo relacional, basicamente, cada entidade representa um registro de uma tabela e as suas referências e dependências. Mas preste a atenção: um modelo relacional é diferente de um modelo de entidades, já que existem diferenças em cada mundo. Veja, por exemplo, a tabela Workflow: não existe referencia a ela como uma classe, mas existe uma coleção, dentro da entidade de Status que referencia esta associação.

DTO x TO x VO x Entidade x Pojo x JavaBean

Vc já ouviu falar de DTO (Data Transfer Object), correto?
E de TO (Transfer Object)?
E de VO (Value Object)?
E de POJO (Plain Old Java Object)?
E de Java Bean?

Se vc acha que é tudo a mesma coisa, vc está enganado!

TO foi citado pelo grupo Core J2EE Patterns inicialmente e foi desenhado para ser usado quando aplicações precdisam se comunicar com EJBs, reduzindo a quantidade de métodos a serem chamados.

DTO segue um proncípio parecido, só não cita EJB e foi descrito por Martin Fowler.

Básicamente, TO e DTO são a mesma coisa, um monte de campos com um bando de métodos acessores (Get e Set) para trafegar informação entre dois “extremos”.

Fowler ainda vai adiante e escreve:

Data Transfer Object is one of those objects our mothers told us never to write. It’s often little more than a bunch of fields and the getters and setters for them. The value of this usually hateful beast is that it
result you need to reduce the number of calls, and that means that you need to transfer more data with each d to procall. One way to do this is to use lots of parameters. However, this is often awkwaronly a single value.often impossible with languages such as Java that return The solution Mels How It Works In many ways, amore than a bun
allows you to move several pieces of information over a network in a single call?a trick that’s essential for
tributed systems.

Já o padrão VO é como se fosse um DTO imutável, ou seja um objeto que mantem o seu valor no decorrer da sua vida. O número 5 sempre vai ser 5. Quando vc muda o 5 pra 6, ele deixa de ser o número 5 e vira o numero 6. Número neste caso é um objeto de valor, um é diferente do outro. Em Java, String, Date, todos os Number. Normalmente

Fowler define Value Object como:

A small simple object, like money or a date range, whose equality isn’t based on identity.

VO não tem identidade, tem valor!

Já o POJO, cunhado por Martin Fowler e cia, são objetos simples. São aqueles objetos que não enxtendem ou implementan ninguem. Não dependem de nenhuma atividade externa. São objetos simples que utilizam somente códigos “nativos de Java”.

E Java Bean? Bem, Java Bean é uma especificação! É ela que diz que as classes devem começar com letra maiúscula, os métodos em minúscula, os getX, setX e isX da vida..

Resumindo:

  • Pojo são simples objetos puramente Java;
  • JavaBean é uma especificação;
  • DTO = TO = Objeto pra transferência de informação;
  • VO é um DTO que mantem o seu estado
  • Entidade é um objeto que tem uma identidade em um domínio.

Até!

Comente e Recomende!

2 Comentários :, , , , , , , , , , mais...

Padrões de Projeto e Expressividade de Código

por Rodrigo Allemand em Mar.02, 2009, em Desenvolvimento

Quando eu comecei a vida de desenvolvedor, a minha idéia era que o divisor de águas era quem soubesse escrever “padrões de projeto”. Eu não estava completamente errado. Onde eu errei? Vamos lá…

Christopher Alexander, um renomado arquiteto italiano, uma vez citou:

Cadas padrão descreve um problema no nosso ambiente e o núcleo da sua solução, de tal forma que vc possa utilizar usar esta solução mais de um milhão de vezes, sem nunca faze-lo da mesma maneira.

Christopher Alexander não construia sistemas. Ele construia prédios, casas e cidades. Mas a citação acima se encaixa perfeitamente na definição de padrão de projeto para construção de sistemas! São soluções para um problema conhecido! Não adianta saber “fazer” um padrão de projeto. Vc precisa identificar o problema e achar a melhor solução para este problema, seja ela conforme o criador do padrão de projeto citou ou como você achar melhor. Basta que a definição do padrão seja seguida na sua implementação. Portanto, não grave como a sua classe deve ser para atender um determinado padrão, grave o que o padrão prega, o que ele se propõe a solucionar e os principios de design do padrão.

Outro grande problema encontrado é quanto a nomeção de classes. Quando se nomeia uma classe, deve-se deixar bem claro (porem sem termos um texto como nome) o que a classe faz e como ela foi idealizada. Não só com comentários, mas com os nomes claros, deixando-os entendíveis a primeira vista.

Essa é outra motivação dos padrões. A nomeação é tão importante como a sua implementação. Não adianta vc definir um padrão extremamente bem se uma pessoa que vai desenvolver utilizando essa classe, não conseguir enchergar o que ela realmente faz.

Imagine que vc está entrando em um projeto agora e ao abrir o seu workspace, se depara com uma Classe chamada ConfiguracaoSingleton. Automaticamente vc saberá que se trata de uma instância única da configuração da aplicação.

Ter expressividade no seu código é 80% de um código bem feito! Se alguem entende o que vc se propoz a fazer, as possiveis correções e manutenções (ou até mesmo, usar o seu código como exemplo) fica muito mais facil.

Portanto nomeie bem seu código e saiba o-que-resolve-o-que.

Obs: Vale a pena entender o que é um Anti-pattern tambem!

Para exemplificar melhor, vamos descrever um dos padrões mais conhecidos, mais e mais exemplificados e mais mal-entendidos da história do desenvolvimento orientado a objeto: o Singleton!

O Singleton foi originalmente criado pelo renomado grupo Gang Of Four [GoF], formado por Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides.  Sua definição é:

Garantir que uma classe tenha somente uma instância e fornecer um ponto global de acesso para a mesma.

Resumidamente, a motivação do Singleton é ter um ponto de acesso a uma intancia que seja unica para todo o sistema. As aplicações para este patterns são inúmeras: configuração, tratamento de informação compartilhada, parametrização, manter estado de um objeto, manter instancias de outros objetos que sejam statefull, etc. O qua vai guiar como contruir este objeto é a sua necessidade.

ATENÇÃO: Os códigos utilizados nestes exemplos são meramente ilustrativos.

Vamos ao exemplo mais conhecido de todos:

public class Singleton {

    private static Singleton instance = null;

    private Singleton() {
    }

    public Singleton getInstance(){
        if(instance == null)
            instance = new Singleton();
        return instance;
    }

}

Este sem dúvidas é o código mais conhecido como Singleton. Mas ai começam os problemas…

Se eu tiver em um sistema muito concorrido, pode acontecer de duas instancias serem criadas ao mesmo tempo. Se isso for realmente um problema, refatorando o código poderemos ter algo como:

public class Singleton {

	private static Singleton instance = null;

	private Singleton() {
	}

	public synchronized Singleton getInstance(){
		if(instance == null)
			instance = new Singleton();
		return instance;
	}

}

Sincronizando o método, podemos garantir que apenas uma chamada será processada a cada momento. Mas isso torna o código muito ruim, já que até mesmo depois da criação, todas as chamadas deverão ser sincronizadas e, conforme dito no problema 1, a sua concorrência é grande, o que implica em muitos acessos e uma baixa performance desse método.

Se isso for realmente um problema, para solucionar podemos fazer coisas do tipo:

public class Singleton {

    private static Singleton instance = null;

    private Singleton() {
    }

    public Singleton getInstance(){
        if(instance == null)
            synchronized (Singleton.class) {
                instance = new Singleton();
            }
        return instance;
    }

}

Beleza! com isso conseguimos garantir concorrência e performance, correto? Não, não não… sendo bem purista, ainda há uma possibilidade de haver uma concorrencia na linha 09 do último exemplo. Sim, é possível sim (Calma, são apenas exemplos, rs)! Se isso for um problema, refatorando um pouco mais, podemos ter um código assim:

public class Singleton {

    private static Singleton instance = null;

    private Singleton() {
    }

    public Singleton getInstance(){
        synchronized (Singleton.class) {
            if(instance == null)
                synchronized (Singleton.class) {
                    instance = new Singleton();
                }
        }
        return instance;
    }

}

Pronto! Temos um singleton!!!

Mas ainda temos um probleminha… E se o sistema tiver rolando em Cluster?! Se vc tiver mais de uma JVM, vão existir mais e uma instância do seu singleton, o que deixa de ser singleton!

Bem, perceberam que a ligação entre problema e solução não diz respeito a como codificar. Eu tenho vários exemplos de Singleton acima e até o momento eu não resolvi o meu problema, que é ter uma instância, que suporte concorrência, com performance e em um ambiente distribuido. E eu poderia fazer milhões de implementações diferentes para conseguir chegar ao meu objetivo!

Mas e se eu não me importasse de ter mais de uma instancia no Cluster? E se a minha concorrência fosse muito pequena a ponto de não atrapalhar a minha performance? Isso cabe a você!!! Como eu disse, conhecer o problema e dar a melhor solução possivel!

Existem todos os tipos de pessoas! Existem aqueles que pensam em uma solução, implementam um ou mais padrões sem ao menos conhecer o que está fazendo; como tambem existem aqueles que implementam vários padrões de projeto para um simples Hello World e mesmo assim, a implementação está errada!

Só para termos ideia, vou colocar mais um exemplo de Singleton. Neste eu utilizo o contexto de uma aplicação Web para individualizar a minha instancia.

public class Singleton {

    private static final String KEY = "singleton";

    private Singleton() {
    }

    public Singleton getInstance(ServletContext context){
        Object obj = null;
        obj = context.getAttribute(KEY);
        if(obj == null){
            synchronized (Singleton.class) {
                Singleton singleton = new Singleton();
                context.setAttribute(KEY, singleton);
                return singleton;
            }
        }
        return Singleton.class.cast(obj);
    }

}

Portanto, entender o seu problema, saber qual padrão de projeto aplicar e nomea-lo corretamente é o divisor de aguas.

Até!

Comente e Recomende!

3 Comentários :, , , , mais...

Procurando por algo?

Use o campo abaixo para procurar por todo o site:

Ainda não achou? Deixe um comentário ou me mande um email que eu cuido disso!

Minhas indicações!

Alguns blogs que eu recomendo...