DSLs externas


posted by qmx on 05 July 2010

Um grande benefício trazido pelas idéias do Domain-Driven Design (DDD) é a diminuição da impedância na comunicação entre cliente e desenvolvedores, através de uma linguagem ubíqua. A ideia é que os termos do negócio sejam usados tanto por desenvolvedores, como por clientes.

Mas, que diferença isso faz afinal? Muita!

Os desenvolvedores, que por natureza tem enorme facilidade em adicionar complexidade, sofrem um efeito colateral muito interessante ao serem expostos à uma linguagem ubíqua: são obrigados a simplificar sua forma de pensar. Tarefas consideradas corriqueiras ganham mais atenção, ao passo que cenários onde a complexidade seria predominante, em um momento de inspiração, são reduzidas a pequenos incrementos.

Uma das formas de catalisar o entendimento do negócio do cliente é diminuir ainda mais o ruído durante o desenvolvimento, utilizando DSL’s.

DSL? De novo?

Assunto muito martelado, com aplicações bacanas tanto na teoria como na prática;

Apesar de possuirmos linguagens dinâmicas (ruby), flexíveis (lisp) e poderosas para criação de DSL’s (scala), às vezes se faz necessário criar linguagens totalmente fora do comum: mais declarativas e menos imperativas: as famosas DSL’s externas. Acredito que o exemplo mais popular de DSL externa seja a linguagem do cucumber, chamada gherkin:

Cenário: Adicionar um contato
    Dado que eu estou na página inicial
    E eu sou um usuário autenticado
    Então eu devo ver “adicionar novo usuário”

Muito legal de usar, mas como isso realmente funciona? Como fazer a minha própria DSL?

Esta madrugada, o @rodrigoy me mostrou o kanban_sketch, uma ferramenta interessante pra montar um painel de kanban a partir de uma DSL simples:

selected(A,B,R,T)
development:5
  [acceptance:1(C,Z)]
  [in progress:3(Q,Y,W)]
  [done!()]
deployment:3(E)
in production(F,K,L,M,N)  

isso deve produzir um resultado mais ou menos assim:

kanban_sketch

Interessante!

Por mais que nós desenvolvedores conseguíssemos entender bem um hash de ruby {:selected => [‘A’, ‘B’, ‘R’, ’T’] ......}, acredito que o formato anterior ainda traz maior legibilidade: muitas vezes vale o esforço!

E no quê consiste esse esforço?

Para conseguir transformar o texto solto em código, precisamos inicialmente fazer o “parse” deste texto - transformá-lo em uma estrutura normalizada, e já identificar possíveis erros de sintaxe.

Sintaxe?

Sim, por mais que muita gente já torça o nariz lembrando das aulas de português, o fato é que para que haja uma sintaxe, precisamos construir uma gramática, que diga quais serão as regras que nosso texto deve obedecer. A gramática do kanban_sketch está ficando assim:

grammar KanbanDSL

  rule stage
    (name (':' limit)? (cards / substages) ';')*
  end

  rule substages
    substage*
  end

  rule substage
    '[' name (':' limit)? cards ']'
  end

  rule limit
    [0-9]+ {
      def text_value
        text_value.to_i
          end
    }
  end
  
  rule cards
    '(' ((name [,]?)+)? ')'
  end

  rule name
    [a-zA-Z0-9\s]+
  end

end

Como você pode ver, uma gramática é realmente uma série de regras - literalmente :)

Em segundo lugar, após ter passado pelo parser, vamos obter uma AST, que não é nada além de uma árvore de sintaxe abstrata, que descreve os blocos tratados pelo parser com objetos, prontos para serem manipulados!

Acredito que a ferramenta mais famosa para isso seja o antlr - muito poderoso (podemos usar pra praticamente qualquer tipo de linguagem), e por consequência, extremamente complexo. Uma alternativa bem mais simples é o treetop, que utiliza uma abordagem diferente do antlr, preferindo clareza de código à performance. Esse tradeoff entre performance e complexidade, será abordado em um post futuro, se o tempo me permitir :)

Você encontrará mais detalhes sobre como usar o antlr aqui e o treetop aqui.

Uma vez que os desenvolvedores passam a dominar os termos do negócio, se tornam poderosos instrumentos de mudanças e melhorias, não só no software como também no negócio do cliente!

Agradeço ao @rodrigoy pela #provocaçãogratuita :D