Produtividade no Desenvolvimento de Software - DSL Laboratório 2 - Parte 1
Desculpem a demora em atualizar e dar continuidade a esta série de videos-demo do DSL. Estava em férias, e férias quer dizer sem computador :) . Vamos então retomar a nosso exemplo de DSL.
No último "post" terminou-se a construção básica da DSL que representa a máquina de estados, criamos o toolbox. Ou seja, algo muito parecido com a figura apresentada no Laboratório 1 - Parte 3 e nas Figuras 1 e 2 do Laboratório 1 - Parte 2; Entretanto esta DSL na forma em que ela se encontra ainda possue uma série de limitações que requerão um comportamento exemplar de quem quer que venha usá-la. Na prática isto não ocorre, em geral as pessoas tendem a não seguir comportamentos exemplares, existindo sim comportamentos que cobrem os dois extremos. Ou seja pessoas relapsas que construirão diagramas impossíveis e pessoas cuidadosas mas curiosas que por fim conseguiram também gerar diagramas impossíveis. Desta forma temos de complementar a DSL até aqui apresentada para que possamos lidar com estas possibilidades e previnir que os usuários da DSL gerem representações sem sentido. Para tornar mais claro tomemos por exemplo o caso do elemento inicial. No problema proposto desde o início, é de que somente deveria se ter uma única condição inicial, e este não é o caso. Experimente a DSL recem criada, e veremos que é possível de se colocar mais de um estado inicial. E ainda pior, é possível ter condições iniciais que não se conectam a nada.
É neste ponto que vamos apresentar o que Restrições e Validações que irá nos ajudar a evitar erros e limitar a possibilidade de serem criadas construções "impossíveis" com a DSL. De uma forma geral o tema relativos a erros de "linguagem" encerra uma discussão que vai além do escopo destes laboratório. Recomendo aos interessado a recorrem ao capítulo 7 do livro texto Domain-Specific Development with Visual Studio DSL Tools aonde uma discussão mais aprofundada é apresentada.
Esta Laboratório 2 esta relacionado portanto as regras de validação e restrições que vão auxiliar no aprimoramento e "ajuste fino" da linguagem criada. Existem como veremos restrições e validações rígidas (hard) e flexíveis (soft). As rígidas em geral estão associadas a situações que um vez realizadas e imediatemente detectas pela ferramenta de desenho impedirão que o usuário
prossiga. As flexíveis por outro lado permitem que o usuário prossiga com o desenho mas o erro será apenas detectado quando for solicitado para se gerar a linguagem.
No caso do "Issue Tracker" a máquina de estado que o representa possuí um comportamento bastante específico. Que limita, portanto o comportamento da máquina de estado que irá representa-lo. No domínio do nosso problema de rastreamento (Issue Tracker) de "problemas" temos as seguintes condições para a condição inicial (Start Element) e os estados (Issue State) que o representam. Imaginamos inicialmente as seguintes 5 condições, ou restrições:
- Issue State não pode ser repetido, ou seja eu não posso ter estados cujo nome se repete,
- Issue States que estejam soltos ou desconectados (este parece ser uma condição simples mas imagine um desenho complexo que ocupa muito mais que uma tela),
- Apenas um Start Element, ou seja um ponto de entrada, ou condição inicial,
- Issue States não pode estar vazio, ou seja sem um nome,
- E por fim não se pode ter comportamentos ciclomáticos.
As 2 primeiras opções acima são restrições que iremos considerar como flexíveis e as outras 3 últimas são do tipo rígidas.
Vamos começar tratando primeiro caso: Issue State não pode ter nomes repetidos.
O video a seguir mostra como conseguir isto.
Abaixo o código que implementa esta validação.
1: using System;
2: using System.Collections.Generic;
3: using System.Text;
4: using Microsoft.VisualStudio.Modeling.Diagrams;
5: using Microsoft.VisualStudio.Modeling.Validation;
6: using Microsoft.VisualStudio.Modeling;
7: using System.Globalization;
8:
9:
10: // Como requisito da nossa maquina de estado que representa os nossos "Issues"
11: // ela nao pode ter 2 estados com o mesmo nome
12: // Logo o metod abaixo verifica em todo o espaco do dominio da classe (IssueStateModels)
13: // senao existem dois estados com nome iguais.
14: // Caso existam um erro 'e gerado
15: // O erro gerado apenas quando o usu'ario da DSL solicitar uma validacao do modelo
16: // Ou seja um Soft Validation
17:
18: namespace Microsoft.IssueStateModels
19: {
20: [ValidationState(ValidationState.Enabled)]
21: public partial class IssueStateModel
22: {
23: [ValidationMethod(ValidationCategories.Menu)]
24: private void ValidateStateNamesUnique(ValidationContext context)
25: {
26: Dictionary<string, IssueState> stateNames = new Dictionary<string, IssueState>();
27:
28: foreach (StateElement element in this.StateElements)
29: {
30: IssueState state = element as IssueState;
31: if (state != null)
32: {
33: if (stateNames.ContainsKey (state.Name))
34: {
35: string description = String.Format(CultureInfo.CurrentCulture, "State name '{0}' is used more than once.", state.Name);
36: context.LogError(description, "Err 01", state, stateNames[state.Name]);
37: }
38: stateNames[state.Name] = state;
39: }
40: }
41: }
42:
43: }
44: }