Domain Specific Languages: Considerações Finais

January 11th, 2008 § 0 comments

Este é o quinto artigo em uma série sobre DSL, ou Linguagens Específicas de Domínio. O primeiro artigo introduziu o assunto explicando o que é uma DSL e como elas podem melhorar e simplificar o código de uma aplicação. O segundo artigo mostrou o processo de transformação de um problema usual em um problema resolvido por uma DSL. O terceiro artigo mostrava a implementação de uma DSL simples, usando as características básicas de meta-programação do Ruby. Por fim, o quarto artigo mostrava uma implementação mais complexa ilustrando outras técnicas úteis.

Neste último artigo, é explorar rapidamente alguns temas relacionados e mostrar o que está vindo por aí. Com a popularidade do Ruby e outras linguagens dinâmicas e funcionais, o assunto está se tornando cada vez mais estudado e vale a pena acompanhar o que está acontecendo.

Quando usar uma DSL

Muitos programadores, em seu primeiro contato com o tema, decidem que todo e qualquer problema podem ser resolvidos com uma DSL. Com o ditado diz, se você tem um martelo tudo se parece com um prego. O resultado são programas povoados de pequenas linguagens que precisam de uma grande quantidade de código para conversarem em si.

Embora seja possível–e em alguns casos interessante–coordenar interfaces entre uma DSL e outra, isso reduz consideravelmente os benefícios de isolar um problema, reduzir o seu foco e isolar a complexidade do código relacionado. Quando se começa a pensar na interface que uma DSL vai prover para outra DSL, a questão pode ficar complicada.

Para que está começando, o uso de DSL vai ser mais interessante em duas áreas: envolver código legado em interfaces mais acessíveis e refatorar seqüências complexas em algo mais gerenciável. Não é que uma DSL só sirva para essas duas tarefas. Mas, na minha experiência, é onde estão os maiores ganhos para quem está começando.

A partir daí, progredir para a elaboração de ferramentas internas mais complexas e finalmente chegar ao uso de ferramentas externas é um caminho mais tranqüilo.

Interfaces fluentes

Um termo que recentemente está sendo associado ao uso de DSL é interfaces fluentes. Como Martin Fowler–um dos criadores do termo–menciona nesse artigo, o termo é basicamente intercambiável com DSL e representa uma forma de concatenar chamadas em algo mais fluido e legível.

Um exemplo bem simples disso são os manipuladores de data no Rails:

(4.months + 5.years).from_now

Esse código pode ser lido naturalmente e seu intento é evidente de imediato. O objetivo de uma interface fluente é justamente realizar essa transição–o código imperativo e fixo é convertido em algo flexível e de fácil leitura.

Para linguagens que não possui capacidade específica de meta-programação, interfaces fluentes podem ser a maneira mais fácil de implementar uma DSL. Em C# 2.0, por exemplo, seria fácil dizer algo do tipo:

broker.ProcessFile(fileName).Using(MyService).
  MapColumn("A1").ToField("Name").FormattedAs(typeof(String)).
  MapColumn("A2").ToField("Date").FormattedAs(typeof(DateTime)).
    WithOptions("Year").As(DateTime.Today).
  MapColumn("A3").ToField("OrderId").FormattedAs(typeof(Integer)).
    WithOptions("Unique").As(True).
    WithOptions("EagerLoading").As(False)

O código é necessariamente mais verboso do que seria se a meta-programação fosse mais evidente na linguagem mas ainda é mais legível do que se estivesse quebrado em múltiplas classes e implementações.

Se você precisa usar uma linguagem que não é tão flexível, buscar linguagens fluentes pode ser uma estratégia bem interessante para a implementação de uma DSL.

Testando

Como a implementação de uma DSL geralmente envolve muita mágica, por assim dizer, testar a mesma pode se tornar algo complicado quando o escopo de execução dos blocos está sendo modificado ou é dinâmico–principalmente em linguagens onde os próprios mecanismos de teste implementam uma DSL com toda a dinâmica adjacente.

Nesses casos, a melhor estratégia não é estar a própria DSL, mas testar o que ele está gerando. Pode parecer que isso não dá um cobertura interessante, mas há um equivalência óbvia entre as duas coisas. Escolher os exemplos apropriados não é difícil e é possível exercitar todos os aspectos da geração simples observando o que ela está fazendo.

Quando a DSL possui um produto bem específico e final, a situação se torna ainda mais simples e o teste desse produto é uma validação automática.

Finalmente, o código que usa a DSL pode estar testado naturalmente já que o contexto encapsulado da DSL é isolado nesse caso.

O futuro próximo

Vários assuntos e tecnologias estão surgindo em torno do potencial de linguagens específicas. Entres eles estão geradores baseados em DSL com modificações two-way, language workbenches e programação orientada a linguagens.

Geradores de código estão entre as ferramentas mais vilipendiadas na história da programação, embora a sua utilidade seja inquestionável. De fato, usuários de linguagens cujo afinidade com DSL é patente, como Smalltalk, sempre utilizaram geradores de código em profusão e sem efeitos detrimentais para o código.

O maior problema com geração de código, entretanto, é que poucas vezes a geração é reversível. Isto, modificações no código gerado não são refletidas para o template usado. Uma DSL pode resolver isso servindo tanto de modelo como de código final, permitindo que haja uma correspondência direta entre as duas esferas. Esse é o tipo de problema que será mais e mais resolvido por linguagens específicas.

Language Workbench, por sua vez, é um novo termo cunhado por Martin Fowler para representar uma nova classe de ferramentas que permitem manipular uma DSL de maneira mais formal e persistente. De certa forma, eles estão para DSL como ferramentas de modelagem estão para UML diferindo, é claro, pela extrema flexibilidade. O uso de language Workbenches permite desenhar, testar e documentar uma DSL de uma maneira similar à criação de código.

Obviamente esse tipo de ferramenta ainda está em sua infância mas é algo que também será mais e mais utilizado nos próximos anos. O artigo de Fowler é uma fonte primária de informações e vale a pena se lido inteiramente–até porque fornece uma boa visão dos temas relacionados.

Finalmente, programação orientada a linguagem é outro assunto que está ganhando proeminência nos últimos meses. Originalmente, o termo se referia à mesma classe de soluções representada por linguagens específicas de domínio mas atualmente está se tornando um sinônimo para linguagens sintática e semanticamente flexíveis.

Isso e algo que linguagens como Lisp e Scheme vem fazendo há décadas mas que agora está sendo também traduzido para linguagens mais em voga como JavaScript e Ruby. Um bom exemplo disse é OMeta, uma sub-linguagem (no sentido de estar incorporada a outra) para extensões gramaticais.

Fechando o ciclo

Terminamos aqui a nossa série sobre DSL e esperamos que o tempo que você empregou lendo os textos tenha sido proveitoso, ajudando a completar o seu conhecimento. Quaisquer dúvidas, sugestões e correções podem ser deixadas nos comentários associados às entradas e os mesmos serão incorporados ao texto de acordo com as possibilidades.

Leave a Reply

Your email address will not be published. Required fields are marked *

What's this?

You are currently reading Domain Specific Languages: Considerações Finais at Superfície Reflexiva.

meta