DSLs não são para gerentes

Por Fabio Kung em 30/12/08

Já vi e ouvi de muitas pessoas e em muitos lugares que Domain Specific Languages são uma ótima ferramenta para deixar o código tão simples de escrever, tão legível e tão parecido com uma linguagem natural (português, inglês), que serve para que não programadores possam escrever parte do código.

A idéia é que o próprio gerente, cliente, analista-não-programador, ou alguém com este tipo de perfil não técnico escreva as regras de negócio em uma linguagem muito parecida com a linguagem natural, eliminando a necessidade de programadores e reduzindo os custos.

Este pode até ser um uso possível e interessante para DSLs, mas infelizmente, DSLs não tem a mínima pretenção de serem linguagens naturais. Isso seria muito ambicioso para o escopo de uma línguagem específica para um domínio. DSLs não foram criadas para ensinar inglês ou português aos computadores.

Existe uma outra forma interessante de usar DSLs, pela qual tenho preferência declarada e felizmente, parece haver uma convergência para esse meio de aplicá-las. O objetivo é fazer com que o código fonte do programa fique mais próximo do problema sendo resolvido. DSLs como forma de aumentar a expressividade do código. Dave Thomas e Andy Hunt tratam desse assunto no famoso livro The Pragmatic Programmer, sob o nome de Program Close to the Problem Domain.

Em seu livro Domain Driven Design, Eric Evans fala muito sobre a importância de todos os envolvidos no desenvolvimento do sistema usarem a mesma linguagem, que ele chama de linguagem ubíqua (Ubiquitous Language). Desta forma, conseguimos diminuir o abismo que existe entre programadores e especialistas no negócio, facilitando comunicação e diminuindo os clássicos problemas do “telefone sem fio”.

problemas de comunicação

problemas de comunicação

DSLs são uma ferramenta para o desenvolvedor. Uma das formas de inserir os termos da linguagem ubíqua no código fonte, de fazer o código refletir o problema que está sendo resolvido. Desta forma, programadores podem fazer com que o código fique auto explicativo e auto documentado. O próprio código se explica; é a documentação de si próprio.

Ando tão “viciado” nessa forma de escrever código, perseguindo expressividade, fazendo com que o próprio código se explique, que em muitos casos a DSL surge naturalmente depois de algumas refatorações. Aqui, Behavior Driven Development (e principalmente o ciclo red-green-refactor) tem ajudado muito, mas esse assunto fica para um próximo post.

Uma técnica simples para aumentar a expressividade é evitar escrever comentários no meio do código. O tradicional “comentário é mal cheiro no código” (code smell).

Ao invés de escrever o comentário, simplesmente extraia o código que estaria sendo comentado em um novo método. O nome deste novo método deve ser exatamente o mesmo que iria ser escrito no comentário.

“You’ve written the code, now you have to write about the code. In a perfect world, you’d never have to write comments for this purpose: the code will be expressive enough that someone who reads it will understand it. Two things help achieve this result: expressive, readable languages and the composed method pattern.” — Neal Ford

Neal Ford diz que linguagens expressivas e legíveis ajudam a eliminar a necessidade de explicar o código. Geralmente, linguagens mais modernas são mais expressivas do que as mais antigas como Assembly. Mesmo usando linguagens mais modernas, ainda podemos usar nossa ferramenta de programadores preferida: DSLs para criar a linguagem com a expressividade adequada para resolver o problema!

Essa técnica tem o seu preço, claro. É sempre uma troca, uma questão de vantagens e desvantagens; clássico trade-off. Projetar uma DSL pode dar mais trabalho no início, já que precisamos pensar em como desejamos escrever o código (Language Oriented Programming) e pode exigir alguns ciclos extras de refatoração até o código chegar num nível bom de expressividade.

O que tenho percebido é que esse possível esforço extra no desenvolvimento (nem está comprovado cientificamente que ele existe [1]), costuma compensar mais para a frente, dada a facilidade de ler e entender o código, associado ao fato dos programadores estarem naturalmente o tempo todo usando a linguagem ubíqua.

Além disso, diminui bastante a necessidade da famosa pilha de documentação extra que precisa ser escrita em muitos projetos. Na maior parte deles isso tudo é até escrito quando o software já está pronto! Não estou querendo dizer que manuais não devam ser escritos, mas boa parte desse esforço extra de documentação pode ser reduzido. Principalmente o esforço relacionado a documentação que tem como alvo outros desenvolvedores e pessoas que possivelmente darão manutenção no código.

Assim como os testes durante o desenvolvimento, podemos encarar o uso de DSLs como um investimento, e não tempo extra no desenvolvimento.

Feliz ano novo a todos!


1. eu até acho que fico mais produtivo escrevendo código desse jeito.

Java Annotations: directing, enabling?

Por Fabio Kung em 22/09/08

Há algum tempo, quando trabalhava na Alemanha, costumava ter diversas conversas e discussões extremamente produtivas com um grande amigo e desenvolvedor, Tiago Silveira. Como não poderia deixar de ser, desenvolvimento de software era o preferido entre diversos assuntos interessantes.

Em uma de nossas conversas, falávamos sobre o uso de anotações em Java. A discussão foi tão produtiva, que chegamos a concordar que o uso de anotações pode ser encarado como atitude com relação ao desenvolvimento de software!

Foi o próprio Tiago que começou a falar sobre enabling vs directing e começamos a fazer algumas comparações com o uso de anotações em projetos famosos.

Anotações são apenas metadados (ou DecorativeData, como alguns podem preferir); informações extras sobre o código que está escrito. Eu costumo sempre fazer analogia com um post-it pendurado no meio do seu código fonte: anotações não executam código.

Na minha opinião, o bom uso de anotações segue o estilo “Enabling”. Não te direcionam para nenhum caminho, não indicam a execução de nenhum código. Pelo contrário, como metadados, apenas possibilitam diversos usos desta informação extra. Um bom exemplo seria a anotação @Entity, da Java Persistence API:

@Entity
public class Carro {
  // …
}

Diversos frameworks e até outras partes do seu sistema podem usar esta informação extra como bem entenderem. O próprio hibernate usa esta informação para saber que se trata de uma classe persistente, que deve ter representação no banco relacional, um validador poderia usar esta informação para decidir que objetos desta classe devem ser validados, um framework de aspectos poderia decidir aplicar um aspecto nesta classe baseado nesta informação extra, entre diversas outras possibilidades. Um outro exemplo interessante poderia ser a anotação @Transient, da própria especificação JPA:

public class Bicicleta {
  @Transient
  private double velocity;
}

Você poderia usar esta informação para decidir não mostrar este campo na interface gráfica (web ou desktop). Pode usar esta informação extra até para decidir que este campo não será enviado em emails, nem incluso em logs. Frameworks de ORM como o hibernate aproveitam esta informação para ignorar o atributo e não incluí-lo em nenhuma tarefa de persistência.

Poderia dar mais inúmeros exemplos de bons usos de anotações. O mais importante é a idéia de que a anotação possibilita diversos usos e não direciona - não força - nenhum caminho. A anotação não está associada a nenhuma execução de código. Funciona mesmo como um simples post-it.

A atitude alternativa seria o pensamento “Directing”. Neste caso, a anotação está diretamente relacionada a execução de algum código e serve apenas para este fim. Exemplo:

public class Sistema {

  @EnviaEmail(Emails.CONFIRMACAO)
  public void cadastra(Usuario usuario) {
    //…
  }

}

Neste caso não há outro uso para esta anotação. Perceba que ela já pressupõe a execução do código de envio de emails. Te limita a um pensamento particular, para um uso específico. Talvez seja um caso exagerado, mas não há diferença alguma com a chamada direta do método que envia o email:

public class Sistema {
 
  public void cadastra(Usuario usuario) {
    mensageiro.enviaEmail(Emails.CONFIRMACAO, usuario);
    // …
  }
 
}

Em alguns casos pode ser bastante difícil, ou até subjetivo demais, decidir se o uso de uma anotação é directing ou enabling. Não acho que devemos tomar nada como verdade absoluta; o importante é ter consciência dos diversos pontos de vista diferentes. Assim podemos tomar as nossas decisões, sempre pesando vantagens e desvantagens.

E você, consegue lembrar de algum outro uso interessante de anotações? Enabling ou Directing?