Java com café: 2012

Os sistemas legados

É muito comum hoje em dia o profissional da área de sistemas passar anos na faculdade estudando linguagens modernas e quando entra no mercado de trabalho se vê diante de tecnologias totalmente obsoletas. Muitas empresas ainda mantém sistemas antigos rodando e pode ser difícil encontrar um lugar para trabalhar com tecnologias novas.



É notável a velocidade em que as coisas caminham no mundo da informática. Uma das "leis" na programação de computadores diz que Qualquer dado programa, quando rodando, é obsoleto. Mas mesmo com todas atualizações, novas versões com mais recursos e facilidades, as empresas ainda mantém seus antigos sistemas rodando por vários anos.

Por que as empresas mantém sistemas legados?

Muitas empresas acreditam que não devem trocar o sistema simplesmente porque ele está funcionando, mas na verdade é importante avaliar as desvantagens de mantê-lo como por exemplo a dificuldade na integração. Desvantagem esta que foi observada após a obrigatoriedade de emitir nota fiscal eletrônica, visto que muitos sistemas não possuem recursos para comunicação via web. Ainda nesse aspecto, com o avanço no desenvolvimento de dispositivos móveis e a alta disponibilidade de serviços de internet, esses sistemas não estão preparados para aproveitar tais recursos. Mesmo que apresentem soluções para contornar estes problemas, o resultado final não é dos mais elegantes.
Outro motivo pelo qual as empresas optam por não trocam o sistema é o alto custo despendido com o desenvolvimento de um novo sistema. Sim, existem soluções prontas a todos custos mas é preciso que a empresa veja isso como um investimento e entenda a importância de ter um sistema que realmente atenda suas necessidades.

Compensa trabalhar com uma tecnologia obsoleta?


O importante é ter conhecimento e não ficar fora do mercado, independente da tecnologia. As empresas tem dificuldade de encontrar profissionais para trabalhar com determinados sistemas e geralmente são vagas com uma boa remuneração. 
É necessário se manter atualizado pois muitos sistemas estão sendo construídos e outros sendo migrados, mas acredito que é preciso saber aproveitar as oportunidades e fazer o que tem que ser feito.

Window Function - PostgreSQL

Window function é um recurso muito útil porque nos permite realizar cálculos que antes só poderiam ser feitos com functions ou subquerys, assim podemos escrever menos código e evitar joins. Uma window function consegue particionar as linhas de uma consulta e fazer cálculos dentro destas partições. É como fazemos com funções agregadas, porém sem agrupar e mantendo as linhas separadas. Pra começar, disponibilizo as sentenças para criar e popular uma tabela com dados que vão servir de exemplo:

CREATE TABLE formula1
(
  posicao integer NOT NULL,
  piloto character varying(100),
  equipe character varying(100),
  pontos integer,
  CONSTRAINT pk_formula1 PRIMARY KEY (posicao)
);

INSERT INTO formula1 VALUES (1, 'FERNANDO ALONSO', 'FERRARI', 164);
INSERT INTO formula1 VALUES (2, 'MARK WEBBER', 'RED BULL', 124);
INSERT INTO formula1 VALUES (3, 'SEBASTIAN VETTEL', 'RED BULL', 122);
INSERT INTO formula1 VALUES (4, 'LEWIS HAMILTON', 'MCLAREN', 117);
INSERT INTO formula1 VALUES (5, 'KIMI RAIKKONEN', 'LOTUS', 116);
INSERT INTO formula1 VALUES (6, 'NICO ROSBERG', 'MERCEDES BENZ', 77);
INSERT INTO formula1 VALUES (7, 'JENSON BUTTON', 'MCLAREN', 76);
INSERT INTO formula1 VALUES (8, 'ROMAIN GROSJEAN', 'LOTUS', 76);
INSERT INTO formula1 VALUES (9, 'SERGIO PEREZ', 'SAUBER', 47);
INSERT INTO formula1 VALUES (10, 'KAMUI KOBAYASHI', 'SAUBER', 33);

Fazendo um simples select temos o seguinte resultado:

 posicao |      piloto      |    equipe     | pontos 
---------+------------------+---------------+--------
       1 | FERNANDO ALONSO  | FERRARI       |    164
       2 | MARK WEBBER      | RED BULL      |    124
       3 | SEBASTIAN VETTEL | RED BULL      |    122
       4 | LEWIS HAMILTON   | MCLAREN       |    117
       5 | KIMI RAIKKONEN   | LOTUS         |    116
       6 | NICO ROSBERG     | MERCEDES BENZ |     77
       7 | JENSON BUTTON    | MCLAREN       |     76
       8 | ROMAIN GROSJEAN  | LOTUS         |     76
       9 | SERGIO PEREZ     | SAUBER        |     47
      10 | KAMUI KOBAYASHI  | SAUBER        |     33

Analisando os dados, imagine uma forma de inserir mais uma coluna que mostrará a soma de pontos por equipes. Poderia usar uma subquery:

SELECT *, 
 (SELECT SUM(pontos) FROM formula1 aux
 WHERE formula1.equipe = aux.equipe
 GROUP BY equipe) AS pontos_equipe
FROM formula1
ORDER BY posicao

Poderia usar uma function também, mas fica melhor com uma window function:

SELECT *, SUM(pontos) OVER (PARTITION BY equipe) AS pontos_equipe 
FROM formula1
ORDER BY posicao

 posicao |      piloto      |    equipe     | pontos | pontos_equipe 
---------+------------------+---------------+--------+---------------
       1 | FERNANDO ALONSO  | FERRARI       |    164 |           164
       2 | MARK WEBBER      | RED BULL      |    124 |           246
       3 | SEBASTIAN VETTEL | RED BULL      |    122 |           246
       4 | LEWIS HAMILTON   | MCLAREN       |    117 |           193
       5 | KIMI RAIKKONEN   | LOTUS         |    116 |           192
       6 | NICO ROSBERG     | MERCEDES BENZ |     77 |            77
       7 | JENSON BUTTON    | MCLAREN       |     76 |           193
       8 | ROMAIN GROSJEAN  | LOTUS         |     76 |           192
       9 | SERGIO PEREZ     | SAUBER        |     47 |            80
      10 | KAMUI KOBAYASHI  | SAUBER        |     33 |            80

A chamada da função deve vir acompanhada da cláusula OVER. É isto que determina quais linhas estarão disponíveis para o processamento da função. A outra instrução, PARTITION BY, divide as linhas em grupos para que a função seja aplicada sobre elas. Também podemos definir a ordem que as linhas serão processadas pela função usando ORDER BY. A window function processa as linhas independente da ordem em que estão sendo exibidas, portanto deve-se ter cuidado para que os dados sejam processados na ordem desejada. Suponhamos que queremos saber quem é o piloto número 1 e 2 de cada equipe, sendo o número 1 com a maior quantidade de pontos: 

SELECT *, row_number() OVER (PARTITION BY equipe ORDER BY posicao) AS numero_piloto
FROM formula1
ORDER BY posicao

 posicao |      piloto      |    equipe     | pontos | numero_piloto 
---------+------------------+---------------+--------+---------------
       1 | FERNANDO ALONSO  | FERRARI       |    164 |             1
       2 | MARK WEBBER      | RED BULL      |    124 |             1
       3 | SEBASTIAN VETTEL | RED BULL      |    122 |             2
       4 | LEWIS HAMILTON   | MCLAREN       |    117 |             1
       5 | KIMI RAIKKONEN   | LOTUS         |    116 |             1
       6 | NICO ROSBERG     | MERCEDES BENZ |     77 |             1
       7 | JENSON BUTTON    | MCLAREN       |     76 |             2
       8 | ROMAIN GROSJEAN  | LOTUS         |     76 |             2
       9 | SERGIO PEREZ     | SAUBER        |     47 |             1
      10 | KAMUI KOBAYASHI  | SAUBER        |     33 |             2

A ordenação foi necessária neste caso porque apesar da consulta ser ordenada pela posição, a window function processa os dados de acordo com sua própria ordenação. 
Nesta última query temos o uso da função row_number, que é uma window function embutida. Funções deste tipo devem ser chamadas somente usando a sintaxe da window function (onde a cláusula OVER é obrigatória). 
Tanto as funções embutidas quanto as de agregação podem ser usadas como window functions, mas as de agregação somente se comportam como window functions quando chamadas com a cláusula OVER, caso contrário serão apenas funções de agregação regulares. Outras funções embutidas podem ser encontradas aqui, mas vou apresentar algumas: 
  • lag(coluna, deslocamento) - Usada para retornar valores de linhas anteriores onde o deslocamento determina quantas linhas antes. 
  • lead(coluna, deslocamento) - Parecida com a função anterior, mas para linhas posteriores. 
  • first_value(coluna) - Retorna o valor da primeira linha. 
  • last_value(coluna) - Retorna o valor da última linha. 
E pra finalizar, caso uma query tenha mais de uma window function com o mesmo comportamento, é possível utilizar uma cláusula WINDOW que será referenciada em OVER

SELECT *, row_number() OVER w AS numero_piloto
FROM formula1
WINDOW w AS (PARTITION BY equipe ORDER BY posicao)
ORDER BY posicao

Referência: http://www.postgresql.org/docs/9.1/static/tutorial-window.html

Exemplo de função no PostgreSQL

Esta semana precisei criar uma função no banco de dados PostgreSQL que me retornasse o menor valor dentre outros cotados. Nesta função eu passo dois parâmetros: codigo do material e codigo da cotação (ambos do tipo inteiro).
A função me retorna um tipo NUMERIC(20, 2), que é o tipo no qual venho trabalhando com valores monetários pois segundo a própria documentação do PostgreSQL:
It is especially recommended for storing monetary amounts and other quantities where exactness is required.
Outro detalhe importante que podemos observar é que na query, os valores contidos nos parâmetros são lidos utilizando $1 e $2 respectivamente. Vejamos:

CREATE FUNCTION func_menor_valor(codigo_material INT, codigo_cotacao INT)
RETURNS NUMERIC(20, 2) AS $$ 

 SELECT MIN(valor_total) AS menor_valor FROM view_cotacoes
 WHERE codigo_material = $1 AND codigo_cotacao = $2
 GROUP BY codigo_material;

$$ LANGUAGE SQL;

Enfim, isso é apenas um exemplo básico de função. Mais informações podem ser encontradas na documentação. Também é importante lembrar que a versão do PostgreSQL utilizada foi a 9.1.

JTable - Selecionar todo texto quando editar uma célula

Olá, hoje vou dar início a uma série de postagens rápidas. Normalmente quando abordo um assunto, sempre procuro introduzir os conceitos e explicar detalhadamente cada passo para realizar o procedimento. Mas como não estou tendo tempo pra fazer estas postagens mais elaboradas, resolvi mudar o estilo e tornar esse blog em algo parecido com um depósito de códigos. Assim mantenho o blog ativo e mantenho uma biblioteca com meus códigos pra quem quiser copiar (as vezes eu mesmo preciso de um código que fiz e não acho). 

Então vamos ao que interessa. 
Quando temos uma célula editável numa JTable e clicamos na mesma para fazer a edição, normalmente temos que selecionar e apagar o valor presente na célula para entrar com outro. Para melhorar isto e já selecionar todo conteúdo da célula quando ela entrar em edição, sobrescrevemos o método changeSelection da JTable conforme abaixo:

tbExemplo = new javax.swing.JTable()
{
    // Selecionar o conteúdo da célula quando editar
    public void changeSelection(int row, int column, boolean toggle, boolean extend)
    {
        super.changeSelection(row, column, toggle, extend);

        if (editCellAt(row, column))
        {
            Component editor = getEditorComponent();
            editor.requestFocusInWindow();

            if (editor instanceof JTextComponent){
                ((JTextComponent) editor).selectAll();          
            }
        }
    }
};

P.S.: Todos códigos foram testados por mim e são funcionais. Qualquer dúvida pergunte nos comentários.

Como limitar um JTextField

É muito comum encontrar nos fóruns especializados em Java a seguinte questão: "Como eu faço para limitar o tamanho de um JtextField?". Ocorre um certo desapontamento dos iniciantes na linguagem por não haver um método chamado setMaxLenght(x). Ou ainda com os que trabalham visualmente, procurar a propriedade no componente que limitaria o tamanho máximo de caracteres e não encontrar. Aí programadores que vieram do Delphi por exemplo dizem "O Delphi é muito melhor, blablabla...". Só digo uma coisa: Revejam seus conceitos sobre o que é Java.
A verdade é que o componente JTextField é definido sobre um modelo de documento que por padrão é chamado PlainDocument. Portanto, para para ter o controle sobre o JTextField devemos criar uma sub classe de PlainDocument, sobrescrever alguns métodos dela e trocar o modelo do JTextField para este novo.
Minha intenção não é entrar a fundo neste assunto, mas sim dar uma solução principalmente pra quem está trabalhando visualmente e não quer ficar editanto código a todo momento.
Então vamos lá, primeiramente crie a seguinte classe no seu projeto:

import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

public class JTextFieldLimit extends PlainDocument {

    private int limit;
    // optional uppercase conversion
    private boolean toUppercase = false;
    
    private int maximo = 500;

    public JTextFieldLimit(int limit) {
        super();
        if (limit == 0)
            this.limit = maximo;
        else
            this.limit = limit;
    }

    public JTextFieldLimit(int limit, boolean upper) {
        super();
        if (limit == 0)
            this.limit = maximo;
        else
            this.limit = limit;
        toUppercase = upper;
    }

    @Override
    public void insertString(int offset, String str, AttributeSet attr)
            throws BadLocationException {
        if (str == null) {
            return;
        }

        if ((getLength() + str.length()) <= limit) {
            if (toUppercase) {
                str = str.toUpperCase();
            }
            super.insertString(offset, str, attr);
        }
    }
}

Esta classe não é nenhuma novidade e pode ser encontrada em vários sites pela internet (na verdade fiz algumas mudanças nela). O que ela faz é permitir a limitação de caracteres e opcionalmente fazer a conversão para maiúsculas. Mas o problema é que pra cada JTextField criado, temos que chamar o método setDocument passando essa classe e os parâmetros. Então para resolver este problema, crie o seguinte método na classe onde estão seus campos de texto:

    public void preparaForm() {

        // JTextFields limitados e com maiúsculas
        for (Component c : this.getComponents()) {
            if (c instanceof JTextField) {
                ((JTextField) c).setDocument(new JTextFieldLimit(((JTextField) c).getColumns(), true));
            }
        }
        
    }

Este método deve ser chamado sempre antes de exibir o seu formulário. Ele vai verificar cada componente do formulário e caso este seja do tipo JTextField, será configurado para utilizar o modelo de documento apresentado. Mas onde vou definir o limite de caracteres para cada campo? Observe que o primeiro parâmetro passado para o documento é: ((JTextField) c).getColumns(). Visualmente você poderá definir este número na propriedade column do componente. Mas porque essa propriedade? Isto está parecendo uma bela gambiarra... Fique tranquilo, a propriedade column é apenas um número usado para calcular o tamanho preferido para a largura do campo. Se ele for zero, o tamanho preferido será qualquer um dependendo da implementação do objeto. Isto é, você define a largura visualmente utilizando seu gerenciador de layout preferido e pouco importará o valor definido para a propriedade column.
Enfim, trabalhando desta forma você não precisará ficar escrevendo código para configurar o documento e limite de caracteres para cada campo de texto. Isto não é problema se o projeto é simples, mas se estiver desenvolvendo vários formulários, não é muito produtivo.

Observação: O método só funciona caso esteja trabalhando com JInternalFrames e caso não esteja, pode haver alguma diferença no método que retorna os componentes (this.getComponents). Se for um JDialog por exemplo, ficaria assim:  
this.getRootPane().getContentPane().getComponents().

Por hoje é só! Qualquer dúvida deixe nos comentários.

Editado em 17/12/2012:

Devido a alguns JTextFields estarem dentro de JPanels e JTabbedPanes, desenvolvi um método recursivo que poderá ser chamado dentro do método preparaForm citado anteriormente:
 
    private void preparaJTextFields(Object obj) {

        if (obj instanceof JTextField) {
            ((JTextField) obj).setDocument(new JTextFieldLimit(((JTextField) obj).getColumns(), true));
        }
       
        if (obj instanceof JPanel) {
            for (Component c : ((JPanel) obj).getComponents()) {
                preparaJTextFields(c);
            }
        }

        if (obj instanceof JTabbedPane) {
            for (Component c : ((JTabbedPane) obj).getComponents()) {
                preparaJTextFields(c);
            }
        }

    }   

E a chamada pode ser feita assim:
 
    public void preparaForm() {

        //Centraliza o JInternalFrame
        Dimension d = this.getDesktopPane().getSize();
        this.setLocation((d.width - this.getSize().width) / 2, (d.height - this.getSize().height) / 2);

        //JTextFields limitados
        preparaJTextFields(this.getContentPane());
        
    }

E aproveito ainda para mostrar como não permitir acentuação nos JTextFields, basta trocar a linha super.insertString(offset, str, attr); da classe JTextFieldLimit por:
 
//super.insertString(offset, str, attr);
            
// Sem acentos
String unaccented = Normalizer.normalize(str, Normalizer.Form.NFD);
unaccented = unaccented.replaceAll("[^\\p{ASCII}]", "");
super.insertString(offset, unaccented, attr);

Como listar todos itens de um JMenuBar

Hoje vou ensinar como retornar todos os objetos JMenuItems contidos num JMenuBar. Eventualmente você pode querer retornar também os objetos JMenu, então fica livre para fazer sua implementação do método.
O método que vou apresentar pode ser muito útil para fazer o controle de acesso da aplicação, permitindo que o item de menu seja exibido ou não de acordo com as permissões de cada usuário.
A estrutura de menus em Java é basicamente a seguinte:

JMenubar
   |
   |__ JMenu
   |       |
   |       |__JMenuItem
   |  
   |__JMenu
           |
           |__JMenu
                  |
                  |__JMenuItem

Como podemos observar, temos uma barra de menu e dentro dela temos 2 menus. No primeiro menu temos um item e no segundo temos um sub menu e dentro deste outro item. Então para recuperar todos itens, considerando que podem existir itens dentro de sub menus, devemos utilizar a recursividade.
Resumidamente, um método recursivo é um método que faz chamadas a ele mesmo. Certos problemas, como o apresentado, exigem esta abordagem, pois os elementos estão dispostos numa estrutura do tipo árvore que pode ter várias ramificações. Sendo assim, segue abaixo uma possível implementação do método que resolve este problema.

    /**
     * Retorna todos JMenuItems de um JMenuBar.
     *
     * @param obj Uma variável do tipo JMenuBar.
     * @return void
     */
    public void getMenuItems(Object obj) {

        if (obj instanceof JMenuBar) {

            for (Component c : ((JMenuBar) obj).getComponents()) {
                getMenuItems(c);
            }
        }

        if (obj instanceof JMenu) {

            for (Component c : ((JMenu) obj).getMenuComponents()) {
                getMenuItems(c);
            }
        }

        if (obj.getClass() == JMenuItem.class) {
            System.out.println("JMenuItem: " + ((JMenuItem) obj).getName());
        }

    }

Fiquem a vontade para modificar e utilizar. Até a próxima!

Como vincular dados a um JComboBox

Atualmente estou trabalhando num projeto no qual utilizo o framework JPA. Então a cada dia que passa eu acabo aprendendo algo novo sobre esta API e espero com essa experiência poder ajudar os que estão começando agora.
Hoje vou falar um pouco sobre como vincular dados que se encontram em uma tabela do banco a um componente JComboBox. A vinculação é simples de se fazer, mas a exibição da propriedade desejada é um pouco mais complicada como veremos adiante. Vou apresentar um passo a passo que traduzi do site netbeans.org, mas com algumas correções (o exemplo de código do site na parte "To render the combo box propertly" não funciona).
Vamos ao que interessa:

1. Clique com o botão direito no combo box e escolha Bind > elements (Vincular > elements). 

2. Clique em Import Data to Form (Importar dados para o Formulário...). Selecione a conexão e tabela que voce deseja vincular o combo box. Clique em OK. 

3. No combo From the Binding Source (Origem da vinculação), selecione o item que representa o result list da entidade. Por exemplo, se a entidade se chama Cliente.java, o objeto da lista deve ser gerado como clienteList

4. Deixe o valor em Binding Expression (Expressão de vinculação) como null e clique em OK. 

5. Clique com o botão direito no combo box novamente e escolha Bind > selectedItem (Vincular > selectedItem). Vincule a propriedade que será afetada pela selecão do usuário e clique em OK (normalmente o result list escolhido no passo 3). 

Até aqui já temos os dados vinculados ao combo box, porém se executar o programa verá que o combo mostrará dados da entidade selecionada convertida em String (objeto.toString()) e não uma propriedade específica:


Isto acontece porque, segundo o próprio site do NetBeans, a biblioteca Beans Binding não tem uma classe DetailBinding que permite especificar os valores exibidos no JComboBox.
Uma forma de resolver isto é escrever um código personalizado para mostrar a propriedade que queremos: 

1. Selecione o combo box

2. Na aba Propriedades da Janela de Propriedades, selecione a propriedade render

3. Clique no botão ... 

4. No combo na parte superior do editor de propriedades, selecione Custom Code (Código personalizado). 

5. Na área de texto, entre com um código parecido com o que segue abaixo onde Usuario é o nome da sua entidade e getUsuario é a propriedade que retorna o valor a ser vinculado. 

new DefaultListCellRenderer() {

    @Override
    public Component getListCellRendererComponent(
            JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
        super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
        if (value instanceof Usuario) {
            Usuario usuario = (Usuario) value;
            setText(usuario.getUsuario());
        }
        return this;
    }
}
Feito isso, o valor selecionado deverá aparecer no combo:


Uma outra abordagem mais simples para resolver o problema é sobrescrever o método toString da entidade em questão:

    @Override
    public String toString() {
        return getUsuario();
    } 

Basta fazer com que o método retorne o valor que você deseja mostrar no combo box. É isso aí! Espero que tenham gostado.

Introdução aos Design Patterns

Padrões de projeto são sempre bem vindos quando o assunto é Engenharia de Software. Existe uma variedade deles, mas pra este post teremos apenas uma introdução para entender melhor o que são e pra que servem. Vamos começar com uma definição resumida da Wikipédia:
"Um Padrão de Projeto (Design Pattern) descreve uma solução geral reutilizável para um problema recorrente no desenvolvimento de sistemas orientados a objetos. Não é um código final, é um modelo de como resolver um problema que pode ser usado em muitas situações diferentes. Os Padrões de Projeto definem as relações e interações entre as classes ou objetos, sem especificar os detalhes das classes ou objetos envolvidos, ou seja, estão num nível de generalidade mais alto."
Os conceitos de padrões de projeto vem sendo discutidos ao longo dos anos e se tornou mais popular depois do lançamento do livro Design Patterns: Elements of Reusable Object-Oriented Software em 1995. Então os autores do livro (Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides) ficaram conhecidos como sendo a Gangue dos Quatro (Gang of Four) ou simplesmente GoF.
Outra definição interessante veio de Christopher Alexander cujo seus estudos contribuíram para a utilização de padrões geométricos e matemáticos no urbanismo e arquitetura:
“Cada padrão descreve um problema que ocorre freqüentemente em seu ambiente, e então descreve o núcleo de uma solução para o problema, de maneira que você possa usar esta solução um milhão de vezes, sem fazê-la do mesmo jeito duas vezes.”
Mas o que um cara urbanista e arquiteto está fazendo aqui? Você já deve ter percebido que padrões de projeto não estão ligados apenas a engenharia de software mas também a outras engenharias, como a civil por exemplo. Imagina se você entraria num prédio cujo projeto foi na base do "codifica-conserta"? Você se sentiria seguro? Neste caso é ainda mais crítico porque vidas estariam em risco. De qualquer forma precisamos de boas soluções para nossos projetos e ter padrões já experimentados e aprovados é uma ótima ajuda. Foi com base nos estudos de Alexander que cientistas da computação desenvolveram padrões de projetos usados na engenharia de software.
Dando continuidade ao que interessa, atualmente os padrões são divididos em 3 categorias:
  • Criacionais: Diz respeito a criação de objetos;
  • Comportamentais: Diz respeito a maneira que objetos e classes distribuem suas responsabilidades para realizar uma tarefa
  • Estruturais: Diz respeito a maneira como classes e objetos são organizados estruturalmente
Existem 23 padrões de projetos oficiais que se encaixam nestas categorias. Digo oficiais porque eles são os padrões documentados pela GoF. Existem diversos outros padrões e qualquer pessoa pode criar um, desde que tenha a solução para um problema comum e siga o modelo de documentação. Para documentar um padrão, deve-se definir alguns elementos:
  • Nome e classificação
  • Problema
  • Solução
  • Consequências
  • Casos de uso
Estes são os principais elementos a serem documentados. Pode não parecer importante mas, sem uma forma de documentar os padrões, eles não existiriam ou poderiam até existir mas seriam um monte de diagramas e textos soltos. Foi o próprio Alexander que definiu em seu livro Notes on the Synthesis of Form, The Timeless Way of Building e A Pattern Language, como os padrões devem ser descritos.

Bom pessoal, por hoje é só e espero falar mais sobre alguns padrões em posts futuros.