Linguagens vazias ou o que não deve ser modelado

Publicado em: 28 de fevereiro de 2007

Por Jack Greenfield

Nesta página

Quando não usar DSLs
Melhores práticas para MDD
Generalizando problemas
Quando usar DSLs
Use uma curva de maturidade
Como dar suporte a um processo de desenvolvimento
Referências
Sobre o autor

Resumo: A tecnologia da linguagem específica de domínio (DSL) foi introduzida na Microsoft como parte da metodologia de fábricas de software. Embora as DSLs sejam úteis como linguagens independentes, colocá-las no contexto de uma fábrica de software torna-as mais poderosas e ajuda a evitar algumas ciladas comuns na aplicação da tecnologia. Este artigo explica como as DSLs se enquadram na metodologia das fábricas de software e como usá-las para ajudar os desenvolvedores de DSL a evitar algumas ciladas comuns.

Se você esteve envolvido com a comunidade do Visual Studio nos últimos dois anos, conhece o entusiasmo que geram as linguagens específicas de domínio (DSLs) nesse ambiente (vide Referências). As DSLs são visuais, poderosas e fáceis de usar. E o que é mais importante, existem exemplos muito interessantes de DSLs já em uso ou em desenvolvimento, incluindo DSLs para definir tipos de itens de trabalho, mapeamentos de objetos relacionais e contratos de serviço.

Infelizmente, no meio do entusiasmo, observamos pessoas que usam a tecnologia indevidamente. A questão não é que a motivação para uso das DSLs seja mal compreendida. Ao contrário, a comunidade parece entender claramente os benefícios que as linguagens oferecem em relação às linguagens de modelagem de uso geral, como a linguagem de modelagem unificada (UML), o que é gratificante, pois devotamos a esse tema muito espaço em artigos, podcasts, painéis e palestras especiais nos últimos dois anos. Aqui temos uma rápida recapitulação.

Linguagens de modelagem de uso geral são projetadas para serem compatíveis com o desenvolvimento de modelos que servem como documentação, basicamente. Essas linguagens podem descrever qualquer domínio, mas apenas de modo impreciso. A imprecisão é uma conseqüência do uso de abstrações genéricas, como classe, atividade, caso de uso ou estado. O uso dessas abstrações genéricas é o que faz com que a linguagem de modelagem de uso geral seja tão amplamente aplicável. No caso da UML as abstrações genéricas são definidas usando linguagem natural, informal, em lugar do uso das técnicas de definição semântica formal ou semiformal como conversão, execução ou denotação. A combinação de abstrações genéricas e semânticas informais evitam que essa linguagem possa descrever qualquer domínio específico, com precisão.

Ao contrário, uma DSL é projetada para descrever com exatidão um domínio específico como uma tarefa, uma plataforma ou um processo. Em lugar de abstrações genéricas, usa conceitos tirados diretamente do domínio de destino. A exatidão oferecida por essa linguagem é ainda mais aprimorada quando se definem as semânticas usando a conversão ou a execução. Este nível de formalidade é possível porque o designer da linguagem sabe como serão usados os modelos que nela se baseiam para computação. Os exemplos dos tipos de computações executados com modelos baseados em DSL são: geração de código ou de outros artefatos; criação de relações entre os elementos do modelo e o código ou outros artefatos; validação das relações entre os elementos do modelo e o código ou outros artefatos; configuração de componente de tempo de execução, como um servidor Web e modelos de análise e código correlato ou outros artefatos (por exemplo, computar o Impacto de uma determinada alteração).

Bem, no mínimo, esta é a teoria. O problema é que, na prática, as pessoas nem sempre parecem saber quando usar ou não uma DSL, o que modelar e como desenvolver um conjunto de modelos correlatos que possam ser ‘costurados’ juntos para dar suporte a um processo de desenvolvimento. Esses problemas podem ser evitados construindo-se fábricas de software em lugar de linguagens vazias, ou seja, DSLs não definidas no contexto de fábricas de software. Normalmente, uma fábrica de software fornece vários ativos reutilizáveis, inclusive as DSLs, para dar suporte ao desenvolvimento do software. Mais importante ainda, ajuda os desenvolvedores a construírem ativos úteis, colocando-os no contexto de uma arquitetura de produto e de um processo de desenvolvimento para um tipo específico de entrega.

Quando não usar DSLs

Vamos analisar mais detalhadamente as ciladas que ocorrem com mais freqüência na aplicação da tecnologia DSL. Observamos as pessoas usarem DSLs para resolver problemas inadequados à modelagem, como os que podem ser mais facilmente resolvidos com outras ferramentas, ou problemas em domínios mal resolvidos ou de rápida evolução, em que os padrões e as práticas reutilizáveis ainda não emergiram nem se estabilizaram. Por exemplo, temos visto DSLs para mapeamento das relações entre as entidades e para o desenvolvimento de aplicativos de negócio tornarem-se obsoletas durante o seu desenvolvimento, porque a tecnologia da plataforma subjacente ainda estava em evolução.

Além disso, há pessoas que se confundem com o que deve ser modelado. Em geral, esta confusão aparece na definição do escopo dos problemas. Os dois problemas de definição de escopo mais comuns são: usar uma única DSL para capturar informações sobre muitas coisas diferentes ou para capturar muitos tipos de informações sobre a mesma coisa, fatorando os conceitos de modo insatisfatório entre as várias DSLs. Por exemplo, vimos uma DSL ser usada para descrever a decomposição de sistemas em componentes colaborativos baseados em serviço e, também, as mensagens trocadas pelos componentes, as cargas transportadas pelas mensagens, a estrutura das implementações de componentes e, por fim, a configuração dos componentes para implantação.

A experiência do setor com padrões e aspectos demonstrou claramente que, entrelaçar muitas e diferentes preocupações em um único item de código, cria problemas. Este princípio aplica-se aos modelos, assim como ao código.

Por exemplo, talvez eu queira trocar a definição de carga da mensagem de um componente, enquanto outra pessoa altera a estrutura de implementação do componente usando a DSL anteriormente descrita. Teremos de enfrentar um complexo problema de mesclagem ao verificarmos nossas alterações porque duas questões diferentes ficaram entrelaçadas em um único modelo. O problema está em que o modelo é fatorado de modo insatisfatório. Um modelo fatorado de modo insatisfatório é como um código fatorado dessa forma. Falha ao separar questões, dificultando as alterações e tornando-as propensas a erros. Podemos aprimorar modelos fatorados de modo insatisfatório da mesma forma que aprimoramos o código fatorado dessa forma, refazendo a fatoração de acordo com padrões que separam, de modo transparente, itens de código ou conceitos que representam as várias questões. Para saber se dois conceitos de uma linguagem representam questões diferentes basta observar se as alterações ocorrem em diferentes momentos e por diferentes razões.

Quanto a ‘costurar’ modelos juntos para dar suporte a um processo de desenvolvimento, observamos um grande interesse na comunidade do Visual Studio, mas não muitos exemplos de trabalho baseados em DSLs. A análise e o projeto orientado a objeto (OOA&D) popularizaram a idéia de usar um conjunto de modelos interrelacionados para cobrir falhas no processo de desenvolvimento, especialmente a existente entre os requisitos e o projeto (vide Referências). Infelizmente, a expectativa nunca correspondeu, de fato, à promessa pois os modelos envolvidos representavam meramente a documentação baseada em linguagens de modelagem de uso geral que apenas descreveram superficialmente os requisitos ou o projeto.

Além disso, as relações entre os modelos foram definidas apenas de modo informal, com a meta de ajudar os humanos a executar as transformações entre eles, manualmente. Entretanto, talvez o problema mais sério seja que a falha existente entre requisitos e projeto deve ser ultrapassada de várias formas, de acordo com os diferentes tipos de aplicativos. Muitos detalhes importantes ficaram perdidos enquanto as pessoas tentaram aplicar uma única abordagem para todos os casos, usando modelos genéricos para problemas complexos.

Apesar dessas deficiências, a visão permanece poderosa e observamos várias pessoas tentando concretizá-la de várias formas. A maioria o faz manualmente, alguns desenvolveram integrações DSL e outros temtaram a arquitetura orientada a modelo (MDA) do Object Management Group (OMG). Por certo, a expectativa do MDA também nunca correspondeu, de fato, à promessa, conforme explicado em vários podcasts e artigos. Vou recapitular os motivos aqui, sucintamente, para economizar o seu tempo de procurá-los. Depois, poderá consultá-los, se quiser ter um relato mais detalhado (vide Referências).

A MDA enfatiza a independência da plataforma. Na prática, a independência da plataforma não é uma qualidade absoluta de um modelo. É uma qualidade que o modelo pode ter em graus variados. Por exemplo, um modelo de relações entre as entidades não pode depender das características da versão específica de um sistema de gerenciamento de banco de dados, de um fornecedor específico mas, ainda assim, assume a existência de uma plataforma relacional, com determinados recursos.

Ainda estou para ver um modelo que seja verdadeiramente independente de todas as suposições relativas aos recursos da plataforma computacional subjacente.

A MDA pressupõe que o mundo seja inteiramente composto de modelos. Sem dúvida, sabemos que a MDA contém muitos outros tipos de artefatos manipulados por muitas técnicas e tecnologias além da modelagem. Uma metodologia de desenvolvimento orientada a modelo deve incluir as outras técnicas e tecnologias e explicar como é feita a integração dos modelos com os outros tipos de artefatos.

A MDA tem por base uma única linguagem de modelagem de uso geral: UML. Expliquei, anteriormente, a motivação para o uso das DSLs em lugar de uma linguagem de modelagem de uso geral como a UML. Uma metodologia de desenvolvimento orientada a modelo (MDD) deveria usar linguagens de modelagem suficientemente poderosas para suportar o desenvolvimento de aplicativos do mundo real. A MDA pressupõe que apenas os mesmos três tipos de modelos são necessários, independentemente do que está sendo modelado. Um deles denomina-se modelo independente de computação (CIM); o outro, modelo independente de plataforma (PIM) e o terceiro, modelo específico de plataforma (PSM). Esta pressuposição é, na verdade, outra manifestação de uma abordagem genérica. Não faz sentido definir um conjunto específico de modelos para um tipo específico de software se a linguagem de modelagem não for capaz de descrever qual o tipo de software, de nenhuma forma diferente do que descreveria qualquer outro tipo de software. Na prática, são necessários muitos tipos de modelos para descrever um determinado item de software e os tipos de modelos precisam ser diferentes, para diferentes tipos de software.

A MDA se concentra inteiramente na transformação. Com base no modelo independente de plataforma, pressionamos um botão mágico que gera o modelo específico de plataforma. Daí, pressionamos outro, para gerar o código. As ferramentas CASE (Computer Aided Software Engineering) demonstraram no final da década de 80, início dos anos 90, que não havia botões mágicos. A MDA está tentando conseguir algo melhor do que as ferramentas CASE, ao ter como base, duas delas. Na prática, a transformação é, em geral, o último processo computacional a ser efetivamente suportado entre dois modelos ou entre um modelo e um código ou outros artefatos, simplesmente porque exige um nível elevado de conhecimento sobre os dois domínios. Além disso, os desafios de engenharia das mudanças de gerenciamento para um dos artefatos ou ambos, intimidam. Muito antes do suporte para a transformação, outras formas de computação baseada em modelo são possíveis.

Melhores práticas para MDD

Nesta altura, você deve estar perguntando se há melhores práticas definidas que possam ser adotadas para evitar esses problemas. Não apenas existem melhores práticas, como há uma metodologia que incorpora um conjunto de melhores práticas integradas para MDD. Falo sobre a metodologia que denominamos fábricas de software. Se você esteve envolvido com a comunidade do Visual Studio nos últimos dois anos, também conhece o entusiasmo existente à volta das fábricas de software.

Se ainda não está familiarizado com as fábricas de software, a home page do site MSDN é um bom ponto de partida para obter mais informações (vide Referências).

Você também já deve ter percebido que as DSLs e as fábricas de software vêm sempre mencionadas juntas e você pode estar pensando como elas se correlacionam. Vamos analisar a resposta para essa pergunta.

De modo sucinto, fábricas de software representam uma metodologia para a criação de processos de desenvolvimento específicos de domínio e de ambientes de desenvolvimento personalizados de suporte. Muito já se escreveu sobre isso e, portanto, não abordarei todo o tópico aqui. Em lugar disso, vamos nos concentrar apenas em como se relacionam com as DSLs e como abordam os problemas descritos anteriormente.

Vamos iniciar nossa discussão sobre as fábricas de software analisando a principal causa existente por trás das ciladas descritas anteriormente. Todos os problemas se resumem no desejo de uma tecnologia de solução universal que possa ser aplicada a todos os problemas. No caso da tecnologia DSL, este desejo se manifesta na pressuposição de que uma DSL é a melhor solução, independentemente do problema. A "síndrome do martelo", como denomino essa tendência, não é exclusiva das DSLs, lógico. Aflige qualquer técnica ou tecnologia que tenha sido comprovadamente útil na solução de uma classe de problemas, encontrada com freqüência. O que causa a síndrome do martelo?

Michael Jackson oferece o seu diagnóstico (vide Referências): Como não falamos sobre problemas, nós não os analisamos nem classificamos e, assim, caímos na crença infantil de que é possível haver Métodos de Desenvolvimento Universais, adequados à solução de todos os problemas.

Apesar da forte onda publicitária de marketing, sabemos que é impossível existir uma linguagem de modelagem universal que descreva todos os domínios, com precisão suficiente para suportar a computação. Por isso mesmo, devemos estar cientes, também, que as DSLs podem não ser a melhor solução para todos os problemas. Entretanto, considerados o poder e a elegância da tecnologia DSL, corre-se o risco de generalizar todos os problemas.

Se pudéssemos descrever as classes de problemas para os quais as DSLs são uma ótima solução, deveríamos então ter condições de codificar algumas orientações para usá-las adequadamente. Então, por que parar aí? Por que não desenvolver uma forma sistemática para analisar e classificar os problemas? Se pudéssemos descrever as classes de problemas freqüentemente encontrados, deveríamos ter condições de trabalhar em técnicas ou tecnologias de desenvolvimento que fossem boas para solucionar os problemas de cada classe. Esta abordagem representa o pensamento básico que dá suporte aos padrões e às estruturas. Esta também é a filosofia básica existente por trás das fábricas de software, que se apóiam nos mesmos princípios e nas premissas subjacentes como os padrões e as estruturas.

As fábricas descrevem uma ou mais classes de problemas, freqüentemente encontradas na construção de um tipo específico de entrega, como smart clients, clientes móvel, de Web, serviço ou portal Web ou, ainda, sistemas conectados. Esses exemplos são horizontais, ou seja, baseiam-se em tecnologias e estilos arquiteturais específicos. As fábricas de software também podem ter como alvo as entregas verticais como os leilões on-line, os sites de comércio, os portais de instituições bancárias e, até mesmo, os portais dos bancos de varejo. Como veremos, a descrição das classes de problemas encontradas com mais freqüência, criadas por uma fábrica, identifica um ou mais domínios que podem ser candidatos ao uso das DSLs.

Por que ter como alvo um tipo específico de entrega? Por que não usar uma análise genérica do problema e um mecanismo de classificação como uma EAF (Enterprise Architecture Framework)?

Existem várias EAFs bem conhecidas como a Zachmann Framework, a TOGAF (The Open Group Architecture Framework) e a estrutura de padrões da Microsoft Patterns & Practices (vide Referências). Como você já deve ter adivinhado por esses exemplos, as EAFs são quase sempre expressas em grades e linhas, representando diferentes níveis de abstração, e colunas que representam os diferentes aspectos do rocesso de desenvolvimento.

A motivação para usar a fábrica em lugar de uma EAF é a mesma que nos leva a usar uma DSL em lugar de uma linguagem de modelagem de uso geral. Como a linguagem de modelagem de uso de modo impreciso. Ao contrário, fábricas contêm um esquema que descreve um tipo específico de entrega de modo suficientemente preciso para dar suporte a muitas formas úteis de computação.

Obviamente, diferentes classes de problemas são encontradas com freqüência durante a construção dos vários tipos de entregas. Clientes móveis têm problemas diferentes daqueles de um smart client, assim como os problemas do serviço Web são diferentes daqueles de um portal Web. Esses contrastes não significam que deveríamos pensar em construir duas DSLs diferentes, uma para cada tipo de entrega. Precisamos de um horizonte mais amplo do que uma única linguagem ao tratar de problemas tão grandes como a construção de um aplicativo completo, para evitar os tipos de problemas de definição de escopo descritos anteriormente.

Assim, deveríamos pensar em construir duas fábricas diferentes. Essas duas fábricas poderiam, então, conter duas DSLs diferentes. Entretanto, é mais provável que cada fábrica contenha várias DSLs já que estas serão necessárias para dar suporte ao desenvolvimento de toda a entrega. Quantas dessas DSLs aparecerão nas duas fábricas? A resposta exigiria uma análise mais detalhada do que o espaço aqui disponível, mas podemos presumir, seguramente, que haverá DSLs em comum e outras, exclusivas de cada fábrica. Em outras palavras, muito provavelmente haverá diferenças entre as duas fábricas, além das duas DSLs diferentes.

Haverá muitas DSLs diferentes, as quais serão integradas de diferentes formas. As duas fábricas terão esquemas distintos. Além disso, como o esquema de uma fábrica não precisa ser retangular, poderemos definir quantas classes de problemas precisarmos para analisar, com precisão, um determinado tipo de entrega. As relações entre as várias classes de problemas também são mais fáceis de expressar, já que não se baseiam em adjacências entre células arranjadas em linhas e colunas.

Para desenvolver um esquema de fábrica, analisamos as entregas de um determinado tipo para identificar e classificar os problemas que encontramos com freqüência ao construí-las. Iniciamos pela decomposição do problema de construir uma entrega típica em problemas menores e continuamos até que as folhas da árvores se transformem em pequenos problemas, lidando com apenas uma parte da entrega, como contratos de dados, agentes de serviços, fluxos de trabalho ou formulários. Na prática, quase sempre terminamos com vários pequenos problemas, trabalhando com os diferentes aspectos da mesma parte, como a sua estrutura, seu comportamento ou sua diretiva de segurança. Ao decompor o problema, separamos as questões e identificamos problemas diferentes, os quais podem ser trabalhados de modo relativamente independente.

Generalizando problemas

No próximo passo temos a generalização: dos problemas específicos encontrados na construção das diversas entregas típicas, para as classes de problemas que podemos esperar encontrar, de modo razoável, ao construir qualquer entrega do mesmo tipo. Os detalhes específicos serão variados, de acordo com a entrega, óbvio, mas as classes de problemas permanecerão idênticas. Os serviços específicos acessados também sofrerão variações conforme o smart client, por exemplo, mas isso sabemos pois encontramos problemas de acesso ao serviço ao construir qualquer smart client.

Observe mais atentamente o exemplo de smart client para ver os tipos de problemas que podemos definir. Smart clients têm uma interface de usuário composta com várias visões. Cada visão reflete o estado de algum modelo subjacente. O estado da visão e aquele do modelo são sincronizados por um apresentador. As alterações de uma visão podem afetar outra, por meio de eventos. Os apresentadores colaboram publicando e assinando eventos, ativando cenários como mestre/detalhes nos quais o conteúdo de uma visão de detalhe, como um formulário, controla a seleção da visão mestre, como a de uma árvore ou visão de lista.

Modelos, visões, apresentadores e eventos ficam agrupados em módulos que podem ser carregados por demanda. Com freqüência, os smart clients também interagem com os bancos de dados por meio das camadas de acesso a dados ou de serviços remotos usando agentes de serviço. Esses componentes podem colocar em cache os resultados do banco de dados ou as interações de serviço para melhor eficiência ou deixam que um aplicativo continue trabalhando off-line quando o banco de dados ou o serviço fica off-line, sincronizando as alterações na volta ao serviço. A segurança é outra questão-chave, pois os smart clients podem interagir com vários bancos de dados ou serviços remotos utilizando diferentes mecanismos de autorização ou autenticação. Como sugerido pelo exemplo, acompanhar a arquitetura é um bom modo de localizar as classes de problemas encontradas com mais freqüência, para qualquer tipo de entrega. Começamos com os maiores componentes da arquitetura, desdobrando-os em itens menores. A seguir, identificamos os problemas que encontramos nas fases de projeto, implementação, testes, configuração, ou quando alteramos cada componente. O exemplo também ilustra que as diferentes partes de uma entrega apresentam tipos diferentes de problemas, em diferentes fases do ciclo da vida e em diferentes níveis de abstração. A construção de interfaces de serviço apresenta vários tipos de problemas, diferentes da construção de proxies de serviço, e executar os testes das classes de acesso aos dados apresenta outros tipos de problemas, diferentes de projetar a lógica do negócio.

Para colocar esta discussão no vocabulário das DSLs, podemos pensar em cada classe de problemas como um domínio de problema. A construção total de uma entrega representa um domínio de problema de grande porte, com várias questões. Assim, fazemos a decomposição em domínios de problemas menores, até que tudo esteja reduzido a pequenos problemas de domínio, que podem ser trabalhados de modo relativamente independente. Em se tratando de smart clients, esses domínios de problemas independentes podem ser:

  • Projeto de interface do usuário, compreendendo os desenvolvimentos da visão, do modelo, do apresentador e da integração das visões

  • Projeto de serviço, compreendendo o projeto do contrato e a construção da interface de serviço

  • Construção da lógica do negócio, compreendendo o fluxo de trabalho e as classes da lógica do negócio

  • Construção do acesso aos dados, compreendendo a construção do proxy de serviço e as classes de acesso aos dados. Alguns desses domínios podem ser bons candidatos ao uso das DSLs.

Esta conclusão é importante. Agora, podemos responder uma das perguntas feitas anteriormente: Como saber o que deve ser modelado? O primeiro passo dessa resposta é identificar o tipo de entrega que estamos tentando construir. O princípio fundamental da tecnologia DSL é que a linguagem de modelagem deve se concentrar em um domínio específico para oferecer precisão. Não podemos nos concentrar em um domínio específico fora do contexto de um tipo específico de entrega. O segundo passo é decompor o tipo de entrega-alvo em domínios de pequenos problemas que possam ser trabalhados de modo relativamente independente.

O esquema de fábrica captura os resultados dessa análise em um modelo computável que identifica esses domínios de problemas. (Tratase de um modelo baseado em uma DSL fornecida pelo ambiente de criação da fábrica.) Se fizermos um bom trabalho ao definir o esquema de fábrica, as DSLs desenvolvidas para esses domínios de problemas terão o seu escopo definido de forma a separar as questões, efetivamente. Agora, analisaremos com mais detalhes o esquema de fábrica para ver, exatamente, como esses domínios de problemas são descritos, como as DSLs fazem esse mapeamento e como estão organizados no esquema de fábrica para que as DSLs possam ser agrupadas de modo a suportar um processo de desenvolvimento.

Quando usar DSLs

Como anteriormente mencionado, é óbvio que as DSLs não são a única escolha de tecnologia disponível. Os designers baseados em DSL são apenas um tipo de ativo que pode ser fornecido por uma fábrica. Outros tipos de ativos são os modelos do Visual Studio, da criação de texto (conhecidos como modelos T4 das Ferramentas DSL), receitas definidas com o GAT (Guidance Automation Toolkit), code snippets, documentação que descreve padrões e práticas, bibliotecas de classes e estruturas (vide Referências).

Já vimos que diferentes partes de uma entrega podem apresentar diferentes tipos de problemas. A construção desses itens pode, assim, exigir diferentes técnicas ou tecnologias. Por exemplo, podemos usar classes e code snippets do .NET Framework para construir classes de acessos de dados, mas podemos usar um assistente para expandir um modelo que cria um ponto de partida para um agente de serviço e, depois, completar a codificação manualmente usando a orientação fornecida pela documentação. Observe que, neste exemplo, não estamos usando nenhuma DSL. É perfeitamente legítimo construir uma fábrica que forneça apenas ativos inertes como padrões e práticas.

Agora, estamos em condições de analisar outra pergunta feita anteriormente: Como saber quando usar, ou não, uma DSL? Vou refazer a pergunta, com base nesta discussão. Como saber se devemos usar uma DSL em lugar de outro tipo de ativo para solucionar os problemas de um determinado domínio? Para essa resposta, precisamos analisar com mais detalhes o esquema de fábrica. Já dissemos que o esquema de fábrica é um modelo projetado para suportar a computação e que este descreve um ou mais domínios de problemas que representam as classes de problemas freqüentemente encontradas na construção de um tipo específico de entrega. Além disso, falamos sobre decompor domínios de problemas de grande porte em outros, menores, para que possam ser trabalhados de modo relativamente independente. Estamos, então, prontos para juntar essas idéias para explicar como funciona um esquema de fábrica e como isso nos ajuda a determinar quando usar, ou não, uma DSL.

Esquemas de fábrica podem ser representados por uma árvore. Os nós da árvore denominam-se pontos de vista. Cada ponto de vista corresponde a um domínio de problema. O ponto de vista na raiz da árvore corresponde à construção total de uma entrega. Os pontos de vista abaixo da raiz derivam-se por decomposição. Os pontos de vista descrevem seus respectivos domínios de problemas, descrevendo os problemas que podemos encontrar e dizendo-nos como solucioná-los. Descrevem as soluções em termos das atividades que podemos executar, explicando como executar cada atividade e como reconhecer quando a atividade é necessária. As atividades são descritas em termos dos produtos de trabalho que manipulam. Os produtos do trabalho são os artefatos que construímos para produzir uma entrega. Por fim, pontos de vista descrevem um conjunto de ativos fornecidos pela fábrica para nos ajudar a resolver os problemas que podemos encontrar no domínio. Os ativos são projetados para dar suporte às atividades, quase sempre automatizando-as total ou parcialmente.

Observe o ponto de vista do projeto de contrato como exemplo. Os produtos do trabalho são os contratos de dados e de mensagens. As atividades incluem criar e destruir um contrato de dados; adicionar, remover ou modificar elementos de dados de um contrato de dados; criar ou destruir um contrato de mensagens; adicionar, remover ou modificar os métodos de um contrato de mensagens e conectar os contratos de dados de acordo com argumentos de método dos contratos de mensagens.

Os ativos fornecidos pela fábrica para o ponto de vista do projeto de contrato incluem um Designer de Contrato baseado em DSL, com um conjunto de modelos T4 para geração de implementações de contrato, um conjunto de documentos que explicam como construir contratos de dados e de mensagens, uma lista de verificação para validar projetos de contratos, um conjunto de padrões comuns de troca de mensagens e um conjunto de padrões que descrevem os contratos de mensagens e de dados usados por cada padrão de troca de mensagens.

Obviamente, este ponto de vista seria um bom candidato ao uso de uma DSL. Agora, podemos codificar algumas orientações sobre quando usar, ou não, uma DSL: as DSLs devem ser usadas em lugar de algum tipo de ativo, quando forem o melhor mecanismo disponível para dar suporte às atividades de um ponto de vista específico.

Use uma curva de maturidade

Claro, esta resposta pede outra pergunta. Como saber quando uma DSL é o melhor mecanismo disponível?

A melhor forma que conheço para responder essa pergunta é uma curva de maturidade. Começamos fazendo investimentos modestos em ativos simples para um determinado ponto de vista e, depois, gradualmente, aumentamos nosso nível de investimento com o passar do tempo, construindo ativos cada vez mais sofisticados, na medida em que temos compreensão mais profunda do domínio de problema, alvo do ponto de vista, e maior confiança quanto a termos definido corretamente o escopo e o ponto de vista. Depois, nós o colocamos corretamente no contexto dos pontos de vista vizinhos e delimitadores como parte do esquema de fábrica.

No ponto baixo da curva de maturidade estão ativos simples, como diretrizes e outros documentos não estruturados que ajudam o leitor a saber o que fazer e como fazer. Depois de usar e refinar os documentos, podemos decidir sobre a sua formalização em padrões. No decorrer do tempo, podemos decidir implementar os padrões como modelos que podem ser rapidamente instanciados com o uso de assistentes ou de receitas desenvolvidas com o GAT. Em algum momento, poderemos tomar a decisão de substituir os modelos por bibliotecas de classes entregues como exemplo de código ou como conjunto de módulos (assemblies).

As bibliotecas de classes, por sua vez, podem tornar-se estruturas, servidores ou outros componentes de plataforma, na medida em que fazemos as conexões das classes para formar mecanismos que incorporam os padrões subjacentes. Neste ponto, alcançamos o ponto alto da curva de maturidade, onde as DSLs são mais eficientes. Podemos usar as DSLs para ajustar uma estrutura, um servidor ou outros componentes de plataforma. Elas são especialmente eficientes quando os metadados capturados pelo designer podem ser diretamente consumidos por uma estrutura, um servidor ou outros componentes de plataforma ou, ainda, quando são usadas para gerar códigos de configuração e de conclusão. As DSLs são ótimas para resolver estes tipos de problemas:

  • Fornecer editor gráfico para um formato de documento em XML existente

  • Gerar rapidamente uma visão em árvore e interface de usuário baseada em formulário

  • Capturar as informações usadas para acionar a geração de código e outros artefatos

  • Expressar solução em formulário para facilitar o entendimento geral

  • Descrever abstrações que não podem ser facilmente deduzidas pelo código

  • Descrever domínios fáceis de representar diagramaticamente, como fluxos, mapas conceituais ou ligações de componentes. Em geral, as linguagens são ótimas para manipular domínios que contêm volumes moderados de variabilidade. De um lado, usar uma DSL para configurar um runtime com apenas algumas variáveis simples e valores de parâmetros fixos seria exagero. Um formulário contendo poucas opções suspensas, caixas de seleção ou botões de opção seria melhor escolha. Por outro lado, uma DSL pode não ser suficientemente robusta para dar suporte à construção de uma lógica de procedimento complexa. Uma linguagem de programação textual, convencional, seria melhor escolha.

Também é possível usar uma DSL para implementar uma linguagem padrão sem a assistência de uma estrutura, um servidor ou outros componentes de plataforma. Uma situação na qual esta abordagem é sensata está sendo criada dos modelos baseados na DSL para modelos baseados em DSLs menos abstratas. Por exemplo, podemos criar modelos que descrevem contratos de mensagens com base em modelos que descrevam colaborações do negócio.

Outra situação na qual esta abordagem é adequada está sendo criada dos modelos baseados em uma DSL para codificar o que implementa efetivamente uma estrutura, um servidor ou outros componentes de plataforma. Por exemplo, podemos criar uma plataforma independente de dispositivo usada por código de alto nível pela criação de serviços executados em um dispositivo-alvo com base em um modelo que descreva as características do dispositivo.

Como dar suporte a um processo de desenvolvimento

Sem dúvida, às vezes é mais lógico construir uma DSL sem ter de usar a curva de maturidade, como acima descrito. Construir DSLs simples pode ser muito barato e uma pequena equipe poderá ter condições de ajustar, rapidamente, o seu entendimento de um domínio-alvo repetindo varias vezes a definição e a implementação de uma DSL. Entretanto, não recomendaria tentar construir um designer complexo, nem tentar entregar um, por mais simples que fosse, em uma base de usuário de grande porte que exija treinamento significativo, como para uma organização de campo, sem antes estar certo de que o domínio-alvo e suas relações com domínios vizinhos e delimitadores estão bem entendidos.

Algumas fábricas podem consistir em nada mais do que documentos que descrevem padrões e práticas organizados à volta do esquema de fábrica. Outras fábricas podem ter uma DSL para cada ponto de vista. Na prática, tendemos a ver um misto de tipos de ativos na fábrica típica, com um grande número de pontos de vista servidos por ativos orientados a código, como os padrões, modelos e bibliotecas e um número modesto de pontos de vista, geralmente mais estáveis e bem compreendidos, servidos por designers baseados em DSL. Analisamos duas das três perguntas feitas anteriormente. Podemos responder a terceira? Como 'costuramos' as DSLs juntas para dar suporte a um processo de desenvolvimento? De certa forma, já analisamos a maior parte dos fundamentos necessários para responder essa pergunta. Se considerarmos um bom esquema de fábrica que decomponha o problema de construção de um tipo específico de entrega em pontos de vista relativamente independentes, o próximo passo será descobrir as relações entre os pontos de vista.

Começamos por observar como os produtos de trabalho de um ponto de vista relacionam-se com os produtos de trabalho dos outros pontos de vista. Como estamos trabalhando com pontos de vista baseados em DSL, os produtos de trabalho são definidos em termos de elementos de modelo em diagramas. Há muitas formas de interrelacionamento.

A seguir, apenas algumas delas:

  • Produtos de trabalho de um ponto de vista podem fornecer detalhes sobre os produtos de trabalho de outro ponto de vista. Por exemplo, um diagrama de classe pode fornecer detalhes sobre a implementação de um aplicativo descrito em um diagrama de sistema.

  • Produtos de trabalho de um ponto de vista podem usar os produtos de trabalho de outro. Por exemplo, um diagrama colaborativo do negócio pode usar tipos de mensagens definidos em um diagrama de projeto de contrato.

  • Produtos de trabalho de um ponto de vista podem ser total ou parcialmente derivados de produtos de trabalho de outro. Por exemplo, um diagrama colaborativo de negócio pode ser parcialmente derivado de um caso de uso de um diagrama de uso.

  • Dois pontos de vista podem fornecer informações diferentes sobre os mesmos produtos de trabalho. Por exemplo, um diagrama de classe descreve a estrutura de um grupo de classes, enquanto um diagrama de seqüência descreve o comportamento dessas classes quanto às interações.

  • Produtos de trabalho de um ponto de vista podem descrever as relações entre produtos de trabalho em outros pontos de vista. Por exemplo, um diagrama de implantação contém elementos que descrevem a relação entre um elemento de um diagrama lógico de central de dados e um ou mais elementos de um diagrama de sistema.

Já que temos relações entre pontos de vista baseados em produtos de trabalho, o próximo passo é analisar como as atividades nos pontos de vista correlatos se afetam, mutuamente. Por exemplo, veja a relação entre o diagrama lógico de central de dados, o diagrama de implantação e o diagrama de sistema. No ponto de vista do projeto de sistema suportado pelo diagrama de sistema, a principal atividade é a configuração de sistemas, aplicativos e pontos de extremidade. No ponto de vista do projeto lógico da central de dados suportado pelo diagrama lógico da central de dados, a atividade primária trata da descrição dos tipos de host lógicos e suas configurações e definições. No diagrama de implantação, a atividade primária trata do mapeamento dos sistemas em tipos de host lógicos.

As relações entre os pontos de vista dão suporte a uma atividade que combina essas atividades para formar um fluxo de trabalho denominado projeto de implantação, no qual um arquiteto de soluções configura sistemas, mapeia as configurações do sistema em tipos de host lógicos capturados por um arquiteto de infra-estrutura em uma implantação de teste e, em seguida, valida essa implantação de teste para verificar se as configurações do sistema serão implantadas corretamente em uma central de dados.

Agora, poderemos ver como as DSLs se enquadram no macrocenário das fábricas de software. Introduzimos as DSLs na Microsoft para dar suporte à metodologia da fábrica de software, e as tecnologias são extremamente complementares. Um esquema de fábrica quebra um domínio de problema de grande porte em pequenos problemas. Os pontos de vista nas folhas do esquema visam os componentes ou os aspectos relativamente independentes do tipo de entrega-alvo. Alguns dos pontos de vista podem ser candidatos ao uso das DSLs, desde o início. Outros talvez comecem com ativos muito além da curva de maturidade para evoluir gradualmente em direção às DSLs, com o tempo, de acordo com a experiência vivida. Outros, ainda, podem permanecer voláteis e desafiadores, baseando-se em ativos relativamente simples, como documentação, durante toda a vida da fábrica.

As DSLs que visam os pontos de vista da fábrica estarão com o seu escopo bem definido, se a fábrica estiver bem projetada, e terão relações bem definidas com outras DSLs que facilitem agrupá-las para dar suporte aos processos de desenvolvimento. Em um determinado ponto, poderemos oferecer tecnologia que gere código de integração DSL do esquema de fábrica e tecnologia de tempo de execução que suporte as integrações geradas. A próxima vez que alguém solicitar que você construa uma DSL isolada para um domínio amplo como os aplicativos para bancos, pergunte-lhe qual aspecto da instituição financeira deve ser enfocado. Ao ter como resposta um olhar fixo de interrogação, você saberá que essa pessoa, na verdade, precisa de uma fábrica que quebre o domínio em pedacinhos, alguns dos quais talvez sejam suportados por DSLs e, outros, talvez, por outros tipos de ativos e não por uma linguagem vazia.

Referências

MSDN - Enterprise Solution Patterns Using Microsoft .NET - Microsoft Patterns & Practices

MSDN – Microsoft Visual Studio Developer Center - Ferramentas de linguagem específica de domínio

Guidance Automation Extensions e Guidance Automation Toolkit

Blog do Jack Greenfield

Fábricas de software

Object - Oriented Analysis and Design with Applications, 2ª Edição, Grady -Booch (Addison-Wesley Professional 1993)- OMG - OMG Model-Driven Architecture (MDA)

The Open Group Architecture Forum

Problem Frames: Analyzing and Structuring Software Development Problems, Michael Jackson (Addison-Wesley Professional 2000) Software Factories: Assembling Applications with Patterns, Models, Frameworks, and Tools Jack Greenfield, et al. (Wiley 2004) - Wikipedia Enterprise Architecture (Arquitetura Corporativa)

The Zachman Institute for Framework Advancement

Sobre o autor

Jack Greenfield é arquiteto de estruturas e ferramentas corporativas da Microsoft. Anteriormente, atuou como arquitetochefe do Practitioner Desktop Group, na Rational Software Corporation; foi fundador e CTO da InLine Software Corporation. Na NeXT Computer ele desenvolveu a estrutura de objetos corporativos, agora parte dos objetos Web da Apple Computer. Palestrante e escritor bastante conhecido, é co-autor do bestseller e premiadíssimo título Software Factories: Assembling Applications with Patterns, Models, Frameworks and Tools, com Keith Short, Steve Cook e Stuart Kent. Ele também colaborou nos projetos UML, J2EE e nas especificações OMG e JSP correlatas. É bacharel em ciências, cadeira de Física, pela George Mason University.