Olá pessoal. Tudo certo?!
Posts “snippet” vão mostrar apenas trechos curtos de código com algumas questões (dúvidas) relacionadas. A idéia é “parear” mais com vocês.
Considerem:
var topComplexMethods =
(from type in Assembly.GetExecutingAssembly().GetTypes()
from m in type.GetMethods()
where m.IsPublic && !m.IsAbstract
let entry = new {Method = m, Cc = Cc.For(m)}
orderby entry.Cc descending
select entry).Take(10);
O Snippet relaciona os 10 métodos com maior complexidade ciclomática em meu código usando LINQ e FluentCodeMetrics.
Do que eu não gosto?!
Enfim, FluentCodeMetrics está sendo desenvolvida “aos poucos”. Em cada entrega, refino o design. Por isso, me diga:
Era isso.
Let’s design. Let’s code. Let’s rock.
Olá Elemar,
Uma das características que mais gosto no TDD é que o design do SUT é modelado do ponto de vista do usuário (o teste neste caso). Isso normalmente resulta em um design bem limpo.
Partindo desta ideia, eu, como usuário, gostaria de escrever algo assim:
(from t in CurrentAssembly.Types
from m in t.Methods
where m.Cc > 5
orderby m.Cc descending
select m).Take(10);
Agora respondendo aos seus questionamentos:
1) Não gosto do CC.For(). O usuário teria que ler uma documentação para conhecer todas as possíveis métricas de um método, tipo ou assembly. Do modo que se o próprio método tivesse uma propriedade/método para cada métrica, tornaria a utilização do FCM muito mais fácil para quem está começando.
Também não gostei da utilização cláusula let em conjunto com a classe anônima. Acredito que alterando o tipo de dado retornado no IQueryable vai remover a necessidade desta instrução e deixar a utilização mais fluente. Este item complementa o outro ponto que citei acima. Penso em um “wrapper” para o MethodInfo/Type onde haveriam estas propriedades, algo específico para a API de consulta.
2) Com o primeiro eu concordo, afinal foi o que eu comentei acima. Agora com o segundo ponto eu não tenho tanta certeza. Se o filtro padrão fosse ignorar métodos não-públicos e abstratos, ao tentarmos fazer algo como t.Methods.Count estaríamos retornando um valor incorreto. Penso que retornar tudo e deixar o usuário filtrar seja a melhor opção mesmo. Ou talvez definir alguns “shortcuts” como t.PublicMethods.
Concordo com todas as observações.
Pelo que eu notei, você defende a criação de um modelo de objetos alternativo (independente de Reflection e Cecil) para representar as primitivas de trabalho (classes, métodos, namespaces, whatever?!) .. Estava pensando nisso outro dia..
Entendi certo?!
Isso mesmo. Este é a primeira vez que uso o Cecil, mas pelo que eu percebi é o que ele faz com o TypeDefinition, MethodDefinition e AssemblyDefinition.
Com um modelo de objetos próprio é possível construir uma interface limpa sem ter que poluir os tipos padrões com métodos de extensão.
Cecil vai um pouco mais longe. Ele lê/salva IL direto de arquivos .EXE/.DLL
Entendi o que você está indicando e começo a pensar da mesma maneira.