PRINCIPLE DISCUSSION Respect for difference
C. Why is the Convention important?
A criação de entidades no Framework PON original se dava pela simples instanciação de uma classe do tipo desejado. Entretanto, com o surgimento de diferentes estruturas de dados no Framework PON otimizado (cf. descrito na Subseção 3.1.2), as entidades PON passaram a ser criadas com o auxílio de uma fábrica de entidades. Neste âmbito, o Algoritmo 16 exemplifica a criação de entidades PON com o auxilio da fábrica de entidades.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 SingletonFactory::changeStructure(SingletonFactory::NOPVECTOR); Premise* prPacmanHasNoMoreLives = SingletonFactory::createPremise( game->score->atNumLives, 0, Premise::EQUAL); prPacmanHasNoMoreLives->setName("prPacmanHasNoMoreLives"); Method* mtChangeGameStateToGameOver = SingletonFactory::createMethod(
game->atState, Game::GAME_OVER, Attribute::STANDARD);
mtChangeGameStateToGameOver->setName("mtChangeGameStateToGameOver"); RulePlus* rlCheckGameOverAndFinish = SingletonFactory::createRulePlus("rlCheckGameOverAndFinish", scheduler, Condition::CONJUNCTION); rlCheckGameOverAndFinish->addPremise(prPacmanHasNoMoreLives); rlCheckGameOverAndFinish->addInstigation(mtChangeGameStateToGameOver); Algoritmo 16 – Exemplo de criação de entidades PON
Conforme ilustrado no Algoritmo 16, a criação de entidades PON se dá por meio da utilização de uma instância única (Singleton) da fábrica de entidades. A estrutura de dados para cada entidade pode ser definida em tempo de criação, pela chamada do método changeStructure (cf. linha 1).
Ademais, observa-se a utilização da fábrica para criação de uma Premise (linhas 4 e 5), de um Method (linhas 9 e 10) e de uma Rule (linhas 14 e 15). Ainda, de modo a facilitar a depuração do código, tais entidades são nomeadas com o próprio nome do ponteiro definido no código do programa, respectivamente nas linhas 6, 11 e 14.
Apesar dessas facilidades, é possível observar que as instruções utilizadas para tais criações não simplificam essa atividade (i.e. instruções longas e repetitivas). Outrossim, a própria nomeação de entidades é passível de erros, uma vez que dependeria do desenvolvedor adequar o nome do ponteiro do código com a nomenclatura da entidade em questão.
Neste sentido, de modo a proporcionar de certa forma um padrão de implementação específico para o PON, este trabalho propõe a utilização de pseudônimos (i.e. instruções define do C/C++) para simplificar a criação de entidades, bem como garantir sua integridade. Pseudônimos além de simplificar a utilização de uma instrução, possuem a capacidade de realizar um conjunto dessas com apenas uma única chamada. Basicamente, tais pseudônimos foram criados para abstrair chamadas para um ou mais métodos responsáveis pela criação de entidades PON, bem como para a definição de suas particularidades.
A título de exemplo, o Algoritmo 17 apresenta as definições dos pseudônimos para os tipos de Attributes PON. No código ilustrado são apresentados apenas os tipos Boolean e Integer, porém tal recurso é aplicado igualmente a todos os demais tipos de Attributes.
1 2 3 4 5 6 7 8 9 10 11
#define BOOLEAN(fbe, attribute, value) attribute =
SingletonFactory::getInstance()->createBoolean(fbe, value); attribute->setName(#attribute)
. . .
#define INTEGER(fbe, attribute, value) attribute =
SingletonFactory::getInstance()->createInteger(fbe, value); attribute->setName(#attribute)
Conforme apresenta o Algoritmo 17, a definição dos tipos de Attributes PON criam as entidades a partir de métodos presentes na fábrica de entidades instanciada (linhas 3 e 10) e posteriormente definem o nome de tal Attribute baseando-se no conjunto de caracteres utilizado para representar o ponteiro desse no código-fonte (linhas 4 e 11).
Igualmente a criação de entidades Attribute, as entidades Method também apresentam pseudônimos para suas respectivas criações e subsequentes definições. O Algoritmo 18 apresenta as definições dos pseudônimos para os tipos de Methods PON. No código ilustrado são apresentados três definições distintas, onde cada uma dessas possui uma instrução para criação de uma instância de um
Method PON e outra instrução para definição de seu respectivo nome.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#define METHOD(fbe, method, attribute, value, flag) method =
SingletonFactory::getInstance()->createMethod( fbe, attribute, value, flag);
method->setName(#method)
#define METHOD_PLUS(fbe, method, attribute, value, operation, flag) method =
SingletonFactory::getInstance()->createMethod( fbe, attribute, value, operation, flag); method->setName(#method)
#define METHOD_OPERATION(fbe, method, attribute, operation, flag) method =
SingletonFactory::getInstance()->createMethod( fbe, attribute, operation, flag);
method->setName(#method)
Algoritmo 18 – Definições de pseudônimos para os tipos de Methods PON
Outrossim, as diferenças entre os pseudônimos apresentados no Algoritmo 18 estão presentes em seus respectivos parâmetros de criação. A entidade Method criada no primeiro pseudônimo (linha 1) possui a função de apenas atribuir um dado valor (value) à um dado Attribute. A entidade Method criada no segundo pseudônimo (linha 7), por sua vez, possui a função de realizar uma operação (operation) aritmética simples (i.e. adição, subtração, multiplicação ou divisão) entre o Attribute e o valor (value), atribuindo o resultado de tal operação no respectivo attribute. Por fim, a entidade Method criada no terceiro pseudônimo (linha 13) possui a função de realizar uma expressão aritmética composta (i.e. funcionalidade Operation apresentada na Subseção 3.2.3), atribuindo o resultado dessa no Attribute definido na chamada desse pseudônimo.
Outrossim, as demais entidades PON (i.e. Premise, Condition, Rule, Action e
Instigation) também apresentam pseudônimos, porém suas composições são
similares as demais definições apresentadas. O Algoritmo 19 apresenta o mesmo exemplo de código demonstrado no Algoritmo 16, utilizando as simplificações proporcionadas pelos pseudônimos.
1 2 3 4 5 6 7 8 9 10 11 CHANGE_STRUCTURE(SingletonFactory::NOPVECTOR); PREMISE(prPacmanHasNoMoreLives, game->score->atNumLives, Premise::EQUAL); METHOD(mtChangeGameStateToGameOver,
game->atState, Game::GAME_OVER, Attribute::STANDARD);
RULE(rlCheckGameOverAndFinish, scheduler, Condition::CONJUNCTION); rlCheckGameOverAndFinish->addPremise(prPacmanHasNoMoreLives);
rlCheckGameOverAndFinish->addInstigation(mtChangeGameStateToGameOver); Algoritmo 19 – Exemplo de criação de entidades PON utilizando os pseudônimos
É possível observar que a aplicação dos pseudônimos na criação de entidades PON simplifica suas composições, evita redundâncias nas chamadas de código e evita problemas com a integridade das mesmas (i.e. nomes e ponteiros com conjunto de caracteres divergentes).
Outrossim, é importante ressaltar que o uso de pseudônimos apresenta um custo adicional na ‘montagem’ de uma aplicação PON, uma vez que realiza algumas chamadas de métodos adicionais. Entretanto, esse custo de processamento é relativamente baixo, sendo praticamente imperceptível na composição da maioria dos domínios de aplicações. Na verdade, na execução de uma aplicação propriamente dita, esse recurso não representa nenhum impacto no desempenho, uma vez que durante a execução de uma aplicação, caso nenhuma entidade adicional seja criada, tal recurso não é utilizado.
3.4 CONCLUSÃO
Esse capítulo apresentou a essência do PON e de seu novo framework, bem como as particularidades desses sob uma nova perspectiva de leitura do PON, sob o viés de padrões de projeto. Tal perspectiva inicia pelo vislumbre da essência do paradigma e de seu framework sob a luz do padrão de projeto Observer.
De acordo com Simão et al. (2012), a solução de inferência do PON, responsável por determinar o fluxo de execução de uma aplicação desenvolvida sob os princípios desse, não se trata apenas de uma aplicação do conhecido padrão de projeto Observer. Tal solução é dita como uma extrapolação desse padrão, aplicada no âmbito do cálculo lógico-causal desse paradigma, através de notificações pontuais a pequenas entidades reativas.
Quanto ao Framework PON, de maneira geral, a sua estrutura apresentava em sua materialização original, os padrões Iterator e Command, além do padrão
Observer. Tais padrões apesar de não estarem detalhados de forma explícita nos
documentos referenciados neste trabalho, mantinham breves citações aos mesmos. Neste presente trabalho, entretanto o framework recebeu melhorias significativas na aplicação de tais padrões, além de adicionar outros padrões de projeto em sua estrutura. Os padrões aplicados na estrutura do novo Framework PON tiveram como foco principal a simplificação do desenvolvimento de aplicações PON, proporcionada pela flexibilidade advinda da implementação desses. Dentre eles destacam-se o padrão Abstract Factory, Singleton e Strategy.
Ainda, nesse capítulo foram apresentados novos conceitos específicos para o PON, materializados na versão atual do framework em questão. Os conceitos de impertinência de Attributes e dependência entre Rules se adequám ao paradigma, visto que tratam de melhorias pontuais em sua estrutura, independentes de sua materialização.
Ademais, o conceito de operações aritméticas abstraídas em uma espécie de Method PON representa um conceito pontual para o Framework PON, não se encaixando explicitamente no estado da arte do paradigma. Tal conceito representa um módulo que elimina a necessidade do desenvolvedor criar métodos do POO para vincular em suas aplicações, tornando a implementação de aplicações PON, com operações aritméticas, mais “pura”. Ainda, outros recursos de programação como persistência em arquivos ou banco de dados poderiam ser implementados seguindo a mesma estrutura apresentada. Assim, os desenvolvedores focariam apenas no desenvolvimento de suas aplicações PON “puras”, relacionando as execuções de suas aplicações aos recursos preestabelecidos pelo framework.
Outrossim, a nova estrutura do framework apresenta novas funcionalidades que visam principalmente simplificar a composição e depuração de aplicações PON. Tais funcionalidades atuaram pontualmente no problema de acompanhar o fluxo de
execução não tradicional de aplicações PON por meio de depuradores tradicionais específicos para a Programação Imperativa.
Neste sentido, além de tais contribuições para a estrutura do Framework PON, vislumbra-se a possibilidade de explorar novos padrões de desenvolvimento específicos para o PON, analisando a influência que esses podem causar às aplicações, tanto no impacto em seus desempenhos, quanto em questões de praticidade de desenvolvimento.
Para melhores detalhes quanto à implementação adequada e eficiente de aplicações PON, o Capítulo 4 demonstra o uso efetivo da maioria das funcionalidades/recursos (antigas e novas) nos casos de estudo simulador de jogo
4 BOAS PRÁTICAS E PADRÕES DE DESENVOLVIMENTO PARA O PON
Os conceitos do chamado Paradigma Orientado a Notificações (PON) foram primeiramente utilizados no âmbito de aplicações de controle discreto para uma a composição de sistemas de manufatura simulados [SIMÃO, 2001; 2005; SIMÃO e STADZISZ, 2002; 2008; 2009a; 2009b; SIMÃO, STADZISZ e KÜNZLE, 2003; SIMÃO, STADZISZ e TACLA, 2009; SIMÃO et al., 2010]. Em um dado período de tempo, a solução evoluiu de uma teoria de controle e inferência para um paradigma de programação [SIMÃO e STADZISZ, 2008; 2009a; SIMÃO et al., 2012a]. No domínio da concepção de software nesse paradigma, as raízes do âmago da programação baseada na versão prototipal do framework e suas posteriores evoluções levaram a possibilidade de conceber software de várias naturezas sob os princípios desse paradigma.
Ainda, recentemente surgiu um método de desenvolvimento para o PON denominado Desenvolvimento Orientado a Notificações (DON) o qual permite elaborar artefatos de projeto voltados particularmente para a Programação Orientada a Notificações segundo um processo que se utiliza do conhecido Projeto Unificado, do ferramental da Unified Modeling Language (UML) e das pertinentes Redes de Petri [WIECHETECK, 2011; WIECHETECK et al., 2011].
Entretanto, os trabalhos relativos ao DON e ao PON em geral não consideraram efetivamente questões de padrões de desenvolvimento de software. Além disso, a falta de um conjunto efetivo de programas exemplo, especialmente com escopos consideráveis, não contribuía efetivamente para um aprendizado orientado a exemplos.
De maneira geral, a implementação de aplicações PON apresenta certas complicações (i.e. fluxo de execução não convencional e dificuldades para depuração de código) que, em um primeiro momento, podem tornar sua concepção dificultosa. Neste sentido, este capítulo apresenta boas práticas e técnicas de implementação específicas para o PON, as quais são aqui entendidas como Padrões de Desenvolvimento para o PON. A proposta de tais padrões no atual estado da técnica do Framework PON se mostra bastante pertinente, uma vez que esses auxiliam os desenvolvedores a alcançar maior entendimento na programação baseada no PON como um todo.
Neste sentido, esta seção busca aliar as qualidades existentes no PON a um estilo de programação eficiente, dotado de boas práticas e padrões de desenvolvimento de software. Isso se dá especialmente na apresentação e implementação de programas de natureza mais realista (e.g. aplicações comerciais e simuladores), norteando o desenvolvimento de futuras novas aplicações. Outrossim, tal abordagem visa principalmente minimizar a curva de aprendizado desse novo estilo de programação. Ademais, tal estilo contribuiria para a elaboração de aplicações PON mais eficientes, melhor estruturados, modulares (com unidade coesa e desacopladas) e que possam ser estendidos e reutilizados com certa facilidade.
Outrossim, neste capítulo são apresentados alguns experimentos comparativos em termos de desempenho. Todas as execuções desses experimentos foram realizadas em um notebook com processador AMD Turion X2 de 2.0 Ghz, com 3 GB de memória RAM. De maneira a evitar resultados imprecisos com sistemas operacionais que apresentam maior número de preempções, os testes foram executados em um sistema operacional Linux (distribuição Debian6). Ademais, o ambiente Linux oferece medidas de tempo mais precisas e, portanto, a unidade de medida apresentada nos resultados é representada em milissegundos. Outrossim, os resultados representam a média de execução de 100 repetições para cada experimento.
Para isso, este capítulo está organizado da seguinte maneira: A Seção 4.1 descreve detalhadamente os procedimentos para a criação de uma aplicação PON. Ainda, quando pertinente, sugere o uso de boas práticas e padrões de desenvolvimento elencados para a concepção de aplicações PON. Ademais, tal seção apresenta algumas considerações de implementação, comparando diferentes formas de implementação para problemas similares, considerando questões como desempenho, facilidade de composição de programas e purismo no estilo de programação (i.e. adotar uma implementação puramente baseada no PON, minimizando o uso de conceitos de outros paradigmas). A Seção 4.2, por sua vez,
6
A distribuição Debian apresenta uma versão composta apenas pelos pacotes essenciais para a execução do sistema operacional, possuindo poucas aplicações que executam concorrentemente [DEBIAN, 2012]. Neste sentido, as aplicações tendem a executar sem muitas interferências externas (i.e. preempções) geradas por outras aplicações. Tal fato reforça a confiabilidade dos resultados obtidos em testes de desempenho.
demonstra a utilização pontual das boas práticas e padrões de desenvolvimento propostos em um caso de estudo específico. Mais precisamente, tal caso de estudo consiste em uma nova implementação do sistema de pedido de vendas apresentado na Subseção 2.4.2, objetivando justamente uma abordagem purista para com o uso dos conceitos do PON. Por fim, a Seção 4.3 apresenta as conclusões deste capítulo.