Quando falo em utilizar heurísticas no Merlin, o pessoal fica perguntando: _Como podem ser implementadas essas coisas malucas em um software? Eu digo, simplesmente, que pode. Mas não digo como...
Na verdade, eu nunca me preocupei muito em como isso pode ser feito. Mas, como as perguntas continuam chegando, resolvi publicar a alternativa mais coerente e fácil. E a resposta é simples: _Usando o pattern Chain of Responsability.
Cadeias de responsabilidade
O padrão Chain of Responsability proposto por Gamma e seus amigos é muito bom nesse aspecto. Para quem trabalha com Filtros em Servlets, a coisa é bem semelhante.
Esse padrão diz, em suma, o seguinte: "Dado um problema X, passe esse elea para uma lista de objetos, para que um o resolva". E é bem isso mesmo. Se vocês já conhecem esse pattern, podem continuar. Se não conhecem, dêem uma procurada no Google e depois de ler, retornem para cá...
Heurísticas, Contexto e Histórico
Conforme comento na minha apresentação do Merlin, as heurísticas são regras simples, mas que podem ser conflitantes entre si. São coisas como, "ah, eu acho que assim é melhor (...)" ou "hum, isso é melhor que isso, nesse caso (...)". Mas o problema das heurísticas é justamente esse: podem existir muita gente...achando muita coisa diferente!
Pois bem, então para uma heurística ser boa, ela deve levar em consideração vários aspectos, como o estado do ambiente onde ela ocorre, o objeto a que ela se refere, quem a está utilizando, etc. Chamo isso tudo simplesmente de Contexto.
Mas não é tudo, a variável Tempo também deve ser considerda. Por exemplo, uma heurística que antes era magavilhosa (hic), pode não ser tão boa agora. E pior, ela pode ser péssima daqui a pouco.
Para controlar isso, é interessante contabilizar um Histórico de sucesso ou fracasso no uso das heurísticas. E daí, surge a necessidade das Estimativas.
As Estimativas
A cada uso de uma heurística, o sistema contabiliza se sela foi boa ou ruim. Se ela foi boa, é provável que ela seja interessante numa próxima vez (Hello, meninas: isso é o conceito de proximidade de contexto temporal, muito utilizado em algoritmos de caches). E daí ela ganha um pontinho. Se ela foi ruim, é provável que em um próximo momento, ela seja ruim novamente. E daí ela perde um pontinho.
Essas regras valem, quando os contextos de uso forem semelhantes. Caso contrário, não podemos ser tão simplistas... Mas tudo bem, não quero complicar mais ainda a vida de vocês...
Então, dito isso, vamos aos fatos.
Voltando ao Assado
E como essas heurísticas são implementadas, afinal ? A resposta é: juntamos o pattern de encadeamento, as heurísticas, as estimativas, o contexto e o histórico, num algoritmo assim:
1. O Merlin, que é nosso kernel, que utiliza várias e longas cadeia de responsabilidades para ir montando as telas em tempo de execução.
2. Essas cadeias de responsabilidades nada mais são do que montes de objetos que tratam problemas ao longo do tempo.
3. Cada vez que surge um problema (como por exemplo, escolher o melhor tipo de gui element para um atributo de classe), esse problema é delegado à uma lista de responsabilidades.
4. Esse problema vai navegando (pela própria natureza do pattern Chain) pela lista...
5. Cada heurística é um nodo dessa lista, sendo implementada como um padrão Command ou algo assim (ainda não decidi a melhor forma para isso).
6. Quando o problema X chega à uma heurística que se adeque a ele, a heurística aplica suas regras. Por exemplo, "se o atributo for notnull, então ela adiciona um validador de obrigatoriedade nele".
7. Daí, pela própria natureza do pattern Chain, a heurística acima encarrega-se de passar esse problema X para a próxima heurística da lista...
8. E daí o problema continua navegando, até que todas heurísticas sejam aplicadas.
9. Ao final do processo, todas heurísticas possíveis foram executadas.
Os Melhores em Último!
Obviamente, nesse processo, algumas heurísitcas podem acabar sobreescrevendo coisas de outras, ou seja, as últimas heurísticas da lista podem desfazer coisas feitas lá no começo...
Nesse sentido, quanto mais para o fim da fila uma heurística estiver, mais chances ela tem de suas regras permanecerem sobre o problema. É justamente aí que entram em cena as estimativas.
Durante todo esse processo, o sistema monitora e seleciona boas e más heurísticas, fazendo com que as que mais favoráveis fiquem no fim da fila.
Selecionando os Melhores
Mas como assim o sistema monitora e seleciona as melhores? É ai que entra em cena a figura humana.
Nas primeiras execuções, o Merlin usa suas (ou melhor, as minhas, hehehe) heurísticas, que dizem as regras básicas que devem ser aplicadas. Ou seja, é sua base de conhecimento inicial.
Conforme o cidadão vai utilzando ele no seu ambiente de desenvolvimento, pode ser identificado regras diferentes, como por exemplo "ah, na nossa empresa não usamos comboboxes, mas sim option buttons para valores que são mutuamente exclusivos...". Nesse caso, é criada uma heurística para isso e ela é colocada no fim da fila. Também poderia ser dito que a heurística das comboboxes é tirada da lista...
E como isso é feito? Pelas anotacões! O Merlin provê um conjunto (na verdade, bem simples e pequeno) de anotações na sua API. Assim, o desenvolvedor vai configurando o sistema da melhor forma para o seu contexto.
Conforme o tempo vai passando, o Merlin vai se ajustando ao ambiente onde ele está e as heurísticas vão sendo aplicadas automaticamente, de forma pró-ativa...
E deu-se o ciclo.
Conclusões (Conclusões ?)
Bem, aqui, simplesmente contei como o Merlin resolve essa questão complexa (hic) chamada heurísitca, ou como meu amigo Júlio diz, os Slistaks...
Claro, tem questões relacionadas a desempenho (nessa solução simplista), mas ainda não me preocupo, pois tenho outros algoritmos para evitar trabalhos redundantes ou sobreescritas ao longo da cadeia. Isso poderia ser feito através da simples reordenação da cadeia ou através do descarte de heurísiticas ruins antes mesmo de processá-las...mas não vem ao caso...
Não sei se consegui tirar as dúvidas da população que clama por mais informações sobre o submundo do Merlin. Mas, pelo menos, espero ter dado algumas dicas...
Para quem quer saber mais, acesse o grupo do Merlin.
Até mais.
Na verdade, eu nunca me preocupei muito em como isso pode ser feito. Mas, como as perguntas continuam chegando, resolvi publicar a alternativa mais coerente e fácil. E a resposta é simples: _Usando o pattern Chain of Responsability.
Cadeias de responsabilidade
O padrão Chain of Responsability proposto por Gamma e seus amigos é muito bom nesse aspecto. Para quem trabalha com Filtros em Servlets, a coisa é bem semelhante.
Esse padrão diz, em suma, o seguinte: "Dado um problema X, passe esse elea para uma lista de objetos, para que um o resolva". E é bem isso mesmo. Se vocês já conhecem esse pattern, podem continuar. Se não conhecem, dêem uma procurada no Google e depois de ler, retornem para cá...
Heurísticas, Contexto e Histórico
Conforme comento na minha apresentação do Merlin, as heurísticas são regras simples, mas que podem ser conflitantes entre si. São coisas como, "ah, eu acho que assim é melhor (...)" ou "hum, isso é melhor que isso, nesse caso (...)". Mas o problema das heurísticas é justamente esse: podem existir muita gente...achando muita coisa diferente!
Pois bem, então para uma heurística ser boa, ela deve levar em consideração vários aspectos, como o estado do ambiente onde ela ocorre, o objeto a que ela se refere, quem a está utilizando, etc. Chamo isso tudo simplesmente de Contexto.
Mas não é tudo, a variável Tempo também deve ser considerda. Por exemplo, uma heurística que antes era magavilhosa (hic), pode não ser tão boa agora. E pior, ela pode ser péssima daqui a pouco.
Para controlar isso, é interessante contabilizar um Histórico de sucesso ou fracasso no uso das heurísticas. E daí, surge a necessidade das Estimativas.
As Estimativas
A cada uso de uma heurística, o sistema contabiliza se sela foi boa ou ruim. Se ela foi boa, é provável que ela seja interessante numa próxima vez (Hello, meninas: isso é o conceito de proximidade de contexto temporal, muito utilizado em algoritmos de caches). E daí ela ganha um pontinho. Se ela foi ruim, é provável que em um próximo momento, ela seja ruim novamente. E daí ela perde um pontinho.
Essas regras valem, quando os contextos de uso forem semelhantes. Caso contrário, não podemos ser tão simplistas... Mas tudo bem, não quero complicar mais ainda a vida de vocês...
Então, dito isso, vamos aos fatos.
Voltando ao Assado
E como essas heurísticas são implementadas, afinal ? A resposta é: juntamos o pattern de encadeamento, as heurísticas, as estimativas, o contexto e o histórico, num algoritmo assim:
1. O Merlin, que é nosso kernel, que utiliza várias e longas cadeia de responsabilidades para ir montando as telas em tempo de execução.
2. Essas cadeias de responsabilidades nada mais são do que montes de objetos que tratam problemas ao longo do tempo.
3. Cada vez que surge um problema (como por exemplo, escolher o melhor tipo de gui element para um atributo de classe), esse problema é delegado à uma lista de responsabilidades.
4. Esse problema vai navegando (pela própria natureza do pattern Chain) pela lista...
5. Cada heurística é um nodo dessa lista, sendo implementada como um padrão Command ou algo assim (ainda não decidi a melhor forma para isso).
6. Quando o problema X chega à uma heurística que se adeque a ele, a heurística aplica suas regras. Por exemplo, "se o atributo for notnull, então ela adiciona um validador de obrigatoriedade nele".
7. Daí, pela própria natureza do pattern Chain, a heurística acima encarrega-se de passar esse problema X para a próxima heurística da lista...
8. E daí o problema continua navegando, até que todas heurísticas sejam aplicadas.
9. Ao final do processo, todas heurísticas possíveis foram executadas.
Os Melhores em Último!
Obviamente, nesse processo, algumas heurísitcas podem acabar sobreescrevendo coisas de outras, ou seja, as últimas heurísticas da lista podem desfazer coisas feitas lá no começo...
Nesse sentido, quanto mais para o fim da fila uma heurística estiver, mais chances ela tem de suas regras permanecerem sobre o problema. É justamente aí que entram em cena as estimativas.
Durante todo esse processo, o sistema monitora e seleciona boas e más heurísticas, fazendo com que as que mais favoráveis fiquem no fim da fila.
Selecionando os Melhores
Mas como assim o sistema monitora e seleciona as melhores? É ai que entra em cena a figura humana.
Nas primeiras execuções, o Merlin usa suas (ou melhor, as minhas, hehehe) heurísticas, que dizem as regras básicas que devem ser aplicadas. Ou seja, é sua base de conhecimento inicial.
Conforme o cidadão vai utilzando ele no seu ambiente de desenvolvimento, pode ser identificado regras diferentes, como por exemplo "ah, na nossa empresa não usamos comboboxes, mas sim option buttons para valores que são mutuamente exclusivos...". Nesse caso, é criada uma heurística para isso e ela é colocada no fim da fila. Também poderia ser dito que a heurística das comboboxes é tirada da lista...
E como isso é feito? Pelas anotacões! O Merlin provê um conjunto (na verdade, bem simples e pequeno) de anotações na sua API. Assim, o desenvolvedor vai configurando o sistema da melhor forma para o seu contexto.
Conforme o tempo vai passando, o Merlin vai se ajustando ao ambiente onde ele está e as heurísticas vão sendo aplicadas automaticamente, de forma pró-ativa...
E deu-se o ciclo.
Conclusões (Conclusões ?)
Bem, aqui, simplesmente contei como o Merlin resolve essa questão complexa (hic) chamada heurísitca, ou como meu amigo Júlio diz, os Slistaks...
Claro, tem questões relacionadas a desempenho (nessa solução simplista), mas ainda não me preocupo, pois tenho outros algoritmos para evitar trabalhos redundantes ou sobreescritas ao longo da cadeia. Isso poderia ser feito através da simples reordenação da cadeia ou através do descarte de heurísiticas ruins antes mesmo de processá-las...mas não vem ao caso...
Não sei se consegui tirar as dúvidas da população que clama por mais informações sobre o submundo do Merlin. Mas, pelo menos, espero ter dado algumas dicas...
Para quem quer saber mais, acesse o grupo do Merlin.
Até mais.
0 comentários:
Postar um comentário