quinta-feira, 15 de abril de 2010

Plugin do Visual Studio 2010 para exibir o código fonte na margem

Há algum tempo sugeri o plugin RockScroll, que exibe o código fonte na barra de rolagem, destacando alguns elementos.

Agora, acabei de ver a dica do Scott Hanselman no twitter de um plugin para o Visual Studio 2010 que tem funções parecidas com o RockScroll.

Bem, não adianta eu falar muito a respeito desse plugin, o mais fácil é instalar e ver pessoalmente. Você pode fazer o download do plugin nesse link.

Rolagem no Visual Studio 2010
À primeira vista achei um pouco poluído demais, mas ele tem várias funções que podem ser desabilitadas se necessário, e o melhor, tem o código fonte disponível.

quarta-feira, 14 de abril de 2010

Usando reflection para simplificar nossa vida

Em um projeto que estou trabalhando (o mesmo que citei aqui), existe a necessidade de se comunicar com programas COBOL. A comunicação é feita de uma forma um tanto arcaica. Temos que passar um string contendo os diversos campos, cada um com o tamanho exato.

Digamos que precisamos passar as informações de uma nota fiscal, teríamos essa definição:
  • Data de expedição – 10 caracteres;
  • Nome do Cliente – 15 caracteres;
  • Número da nota – 5 dígitos;
  • Valor – 5 dígitos.
Ao gerar a string contendo o seguintes valores:
  • Data: 01/01/2010;
  • Nome: ALGUM NOME;
  • Número: 123;
  • Valor: 15.
Temos isso como resultado: “2010-01-01ALGUM NOME     00012300015”.

A SOLUÇÃO ANTIGA

A solução que existia para facilitar isso era gerar uma classe de acordo com a definição dos campos, que retorna a string formatada. A classe gerada ficaria assim:
class NotaFiscal 
{ 
  private string dataExpedicao; 
  private string nomeCliente; 
  private string numero; 
  private string valor; 

  public string DataExpedicao 
  { 
    get{return dataExpedicao;} 
    set{dataExpedicao = Utils.FormataCaracteres(value, 10);} 
  } 

  public string NomeCliente 
  { 
    get{return nomeCliente;} 
    set{nomeCliente = Utils.FormataCaracteres(value, 15);} 
  } 

  public string Numero 
  { 
    get{return numero;} 
    set{numero = Utils.FormataDigitos(value, 5);} 
  }

  public string Valor 
  { 
    get{return valor;} 
    set{valor = Utils.FormataDigitos(value, 5);} 
  }
 
  public string ObtemString() 
  { 
    return dataExpedicao + nomeCliente + numero + valor; 
  } 
}
Essa classe tem alguns problemas:
  • todos os dados são strings, não é usada a tipagem da linguagem (int, string, DateTime);
  • a definição de tipo e tamanho dos campos fica espalhada pelo código;
  • a ordem dos campos precisa ser verificada dentro da função ObtemString;
  • caso alguma modificação seja feita nos campos, fica ruim de dar manutenção nesse código.

A Nova solução

A solução que procurei desenvolver tinha alguns pré-requisitos, entre eles:
  • a classe não deveria ter informações relacionadas aos campos que seriam montados na string (definição de tipo, tamanho, etc);
  • poder utilizar os tipos da linguagem (int, DateTime, Enum);
  • a definição de mapeamento da classe para a string a ser gerada deveria ser clara e facilmente editável;
O caminho natural foi desenvolver algo semelhante a um Mapeamento Objeto-Relacional. Eu batizei-o de Mapeamento Objeto-Cobolar. ;)

Com isso temos uma classe de modelo, contendo os dados devidamente tipados e um mapeamento que define quais campos serão transportados para a string, o formato e a posição. Todas essas informações conseguimos obter usando reflection e o mapeamento definido.
class NotaFiscal 
{ 
  public DateTime DataExpedicao { get; set; } 
  public string NomeCliente { get; set; } 
  public int Numero { get; set; } 
  public int Valor { get; set; } 
}

<mapping class=”NotaFiscal”> 
  <field name=”DataExpedicao” Length=”10” /> 
  <field name=”NomeCliente” Length=”15” /> 
  <field name=”Numero” Length=”5” /> 
  <field name=”Valor” Length=”5” /> 
</mapping>

Como você pode ver, não é necessário definir o tipo do campo pois ele é inferido à partir do tipo utilizado no modelo. Ou seja, sabemos que um DateTime deverá ser convertido para o formato yyyy-MM-dd, um inteiro deve ser preenchidos com zeros a esquerda e uma string com espaços a direita.

Para obter a string à partir de um modelo, o que precisa ser feito é chamar um método assim:
conversor.GetString(meuModelo);

Implementando a solução

A implementação não tem muito segredo é apenas uma questão de obter cada valor do nosso modelo seguindo a definição do XML.

O ponto mais importante é a conversão do valor tipado para a string. Como cada tipo tem um formato específico, criei um conversor para cada um. Por exemplo:
class IntConverter : ITypeConverter 
{ 
  public string GetString(Field field, object value) 
  { 
       int valorInteiro = Convert.ToInt32(value); 
       return valorInteiro.ToString().PadLeft(‘0’, field.Length); 
  } 
}

Conclusão

Muitas vezes vale a pena perder um pouco de tempo desenvolvendo uma infra-estrutura que facilite o desenvolvimento. Alguns minutos perdidos no início do projeto podem salvar muitos minutos mais adiante, e, o mais importante, evitar muita dor de cabeça.

segunda-feira, 12 de abril de 2010

Validando bindings usando Reflection

Em um projeto que estou trabalhando percebi a facilidade de criar problemas de binding. Basicamente, ao renomear uma simples propriedade do modelo os bindings ligados a ela param de funcionar. O pior disso é que, para saber que há um problema neles, só mesmo executando as telas uma a uma. Nenhum erro de compilação é gerado.

Pra resolver esse problema, resolvi criar um teste que seja executado automaticamente no build e verifique qualquer problema nos bindings.

Relacionando o componente ao modelo

Fazer a validação do binding a princípio é bastante simples, basta buscar cada propriedade do componente que está ligada ao modelo e verificar se o modelo contém a propriedade com o nome definido no componente. Por exemplo, em um ComboBox, pegamos o nome definido no DisplayMember e buscamos no modelo se existe uma propriedade com o nome correspondente.
Porém, há um pequeno problema, no componente não há nenhuma informação dizendo qual o modelo ao qual ele está relacionado. Sem essa informação, não tem como fazer a validação.

Nesse ponto procurei criar uma forma de descobrir qual modelo está relacionado ao componente.

A convenção

O projeto está sendo desenvolvido em WinForms e adotamos o padrão MVP, mais especificamente o Passive View. Como você já deve saber, no MVP temos a camada de View (exibição) separada do Presenter (lógica da tela). A view apenas recebe os dados a serem exibidos.

Olhando a view pude ver um padrão na atribuição de valores utilizados no binding:
class View 
{ 
  public IEnumerable<Usuario> Usuarios 
  { 
    set{ algumGrid.DataSource = value; }
  } 
}

Fica claro que, ao fazer um binding temos:
  • uma propriedade do tipo IEnumerable<T>;
  • a propriedade permite escrita (contém um set);
  • dentro da propriedade atribuímos o valor ao DataSource do componente.
Com essas informações já temos uma base de como podemos verificar o binding.

Buscando o modelo correspondente ao componente

Com essa convenção, é possível descobrir quais componentes fazem binding e qual o modelo correspondente. Para isso temos de fazer duas coisas:
  1. buscar todas as propriedades das telas que sejam do tipo IEnumerable<T> e que contenham um set;
  2. para cada propriedade, obter o componente para o qual está sendo atribuído o valor.
O primeiro passo é bastante simples, via reflection conseguimos ter essa informação:
private IEnumerable<PropertyInfo> GetProperties(Type type)
{
  return type.GetProperties()
      .Where(x => x.CanWrite && EhLista(x))
}

private bool EhLista(PropertyInfo propertyInfo)
{
  return TipoEhEnumerable(propertyInfo.PropertyType) ||
    propertyInfo.PropertyType.GetInterfaces().Any(x => TipoEhEnumerable(x));
}

private bool TipoEhEnumerable(Type type)
{
  return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>);
}

O segundo passo é um pouco mais complicado. Precisamos analisar o código executado, buscando o componente ao qual é atribuído o valor. Via reflection não temos acesso fácil ao código que está sendo executado, para isso foi necessário uma biblioteca externa. Basicamente, foi necessário analisar o MSIL à procura do componente.

Finalmente, Validando os bindings

Agora que já temos todas as informações necessárias, fazer a validação dos bindings é simples. Basta pegar cada propriedade do componente que faz o binding e verificar se o campo existe no modelo. Essa verificação varia conforme o componente, por exemplo, em um ComboBox simplesmente verificamos o DisplayMember e o ValueMember. Em um grid, por sua vez, é necessário verificar essas propriedades para cada uma das colunas.

Tendo a validação pronta, bastou criar um teste que busca os problemas de binding e reporta cada erro encontrado.

Código fonte de exemplo

Pra entender melhor isso, o mais fácil é olhar o código fonte.  Disponibilizei o código no GitHub, nesse repositório.

Caso você ainda não conheça o Git, recomendo a leitura desse artigo.