Como revisar o código gerenciado

Microsoft Corporation

Publicado em: 28 de fevereiro de 2007

Por John D'Addamio

Aplica-se ao:

.NET Framework

Nesta página

Introdução
Diretrizes relacionadas recomendadas
Práticas recomendadas
Conclusão

Resumo: este documento discutirá as práticas recomendadas para revisão de código gerenciado. Algumas delas são comuns tanto ao código gerenciado quanto ao não-gerenciado. Outras são exclusivas à revisão do código gerenciado. Embora se presuma que você esteja familiarizado com pelo menos uma linguagem gerenciada, não se pressupõe que você tenha experiência de revisão de código gerenciado. Este artigo também contém links para páginas em inglês. (6 páginas impressas)

Introdução

A revisão de código gerenciado é um pouco diferente da revisão de código não-gerenciado. Sob certo sentido, a revisão de código gerenciado é mais fácil do que a revisão de outros códigos. O compilador verifica os tipos, o que impede a atribuição acidental de dados incompatíveis a um objeto. O compilador também verifica a utilização de variáveis que não foram inicializadas. Essas e outras verificações de compilação evitam uma série de bugs que costumávamos procurar ao realizar revisões de código. Além disso, as verificações em tempo de execução vão detectar outros problemas comuns e poderão conter o dano lançando uma exceção. De outras formas, o código gerenciado acrescenta alguns problemas que não existem em outras linguagens, como os arquivos de recursos e elementos XML no próprio arquivo-fonte.

Este documento vai apresentar as práticas recomendadas para revisão de código gerenciado. Embora se presuma que você esteja familiarizado com pelo menos uma linguagem gerenciada, tais como C# ou VB.NET, não se pressupõe que você tenha experiência de revisão de código gerenciado.

Diretrizes relacionadas recomendadas

Há muitas diretrizes relacionadas no site do MSDN. Embora muitas delas sejam diretrizes de design, elas também podem ser, obviamente, aplicadas a revisões de código. Eis algumas delas:

  1. Diretrizes de design .NET

  2. Diretrizes de nomenclatura

  3. Diretrizes para tipos de transmissão

Práticas recomendadas

Usando o FxCop para reforçar seus padrões de codificação

O FxCop é uma ferramenta de análise de código que verifica os assemblies de código gerenciado .NET quanto à conformidade com as Diretrizes de Design .NET mencionadas anteriormente. O FxCop fornece regras padronizadas de análise de código e lhe permite personalizar as regras para seu projeto. A supressão de advertências do FxCop também é permitida no código-fonte. Para obter mais informações ou baixar o FxCop e a documentação, sem custo algum, visite a Página da Equipe do FxCop.

Execute o FxCop no código que está sendo revisado

Defina uma configuração padrão de compilação que execute a análise de código FxCop que cada projeto deve implementar. Como parte da revisão de código, verifique se o projeto implementou corretamente sua configuração padrão de compilação do FxCop e se o código que está sendo revisado passa pela avaliação do FxCop compilando a configuração do FxCop.

Verificando a supressão dos erros do FxCop no código-fonte

Pesquise o código que está sendo revisado para ver se há supressão das mensagens do FxCop. Você pode usar Ctrl+F para pesquisar "CodeAnalysis" no projeto atual. Se você encontrar qualquer supressão do FxCop, verifique se ela é legitimamente necessária e se o motivo para a supressão está claramente explicado nos comentários. De vez em quando, você pode descobrir que a supressão não é necessária, mas que a pessoa que escreveu o código não sabia corrigir o erro. Por exemplo, a seguinte supressão não é necessária.

// FxCop doesn't like the "\n\n" so we're suppressing the error message 
here.
[System.Diagnostics.CodeAnalysis.SuppressMessage
("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = 
"System.Windows.Forms.TextBoxBase.AppendText(System.String)")]
this.resultsTextBox.AppendText ("\n\n" + Strings.contextErrorMessage);
			

Uma mudança simples no código, como mostrado aqui, impede o erro do FxCop.

this.resultsTextBox.AppendText( Environment.NewLine + 
Environment.NewLine + Strings.contextErrorMessage);
			

Revisando a lógica

Naturalmente, os principais pontos da revisão do código são buscar falhas na lógica (bugs) e reforçar os padrões de codificação da equipe. A utilização do FxCop para reforçar seus padrões de codificação lhe permitirá dedicar mais tempo à revisão da lógica do código.

O .NET Framework tem muitas classes e cada classe tem muitos métodos, o que pode ser desanimador. Ninguém é obrigado a conhecer todas as classes ou métodos. Uso livremente as descrições do tipo IntelliSense das classes ou métodos.

Se não conseguir entender o que o código faz a partir dos comentários existentes e das descrições do tipo IntelliSense, é porque o código não tem comentários suficientes. Se você achar que a lógica não faz o que o autor tem em mente, a lógica tem falhas ou o código não tem comentários suficientes para deixá-lo claro.

Compilando

É uma boa prática compilar o código em todas as configurações do projeto. Talvez o autor tenha esquecido de compilá-lo em todas as configurações. Se o código não compilar em todas as configurações, você deve exigir que o autor corrija os erros antes de enviar o código.

Por exemplo, é comum definir a configuração de liberação para excluir os testes de unidade. Se forem feitas mudanças na assinatura de um método, mas os testes de unidade não forem atualizados, o código será compilado com perfeição na configuração de liberação, mas não na configuração de depuração.

Procurando os testes da unidade

Ao revisar o novo código, planeje-se para que os testes da unidade sejam apresentados ao mesmo tempo em que o código funcional. É muito fácil deixar para última hora!

Ao revisar as mudanças no código, podem ser necessários testes da unidade novos ou revisados. Execute os testes atuais de unidade e qualquer outro que seja enviado com a revisão do código. Se os testes de unidade falharem, solicite que o autor atualize o código funcional e/ou os testes de unidade, de forma que sejam bem-sucedidos.

Buscando a validação de parâmetro

É uma boa prática para um método validar seus parâmetros de entrada. Se um parâmetro for inválido, o método deve adotar uma ação apropriada. Por exemplo, deve-se verificar um parâmetro da cadeia de caracteres que seja um objeto null ou igual a String.Empty. Uma ação apropriada em uma situação em que String.IsNullOrEmpty retorna true pode ser lançar uma exceção (por exemplo, uma ArgumentException ou uma ArgumentNullException), mas, em outra situação, o método pode simplesmente retornar ao chamador sem realizar nenhuma ação.

Ao revisar o código, busque os valores de parâmetro que podem causar algum comportamento indesejável. Os valores "bad" podem ser tão óbvios quanto no exemplo da cadeia de caracteres mostrado, mas podem ser menos explícitos. Por exemplo, pense em uma cadeia de caracteres que deve representar alguns dados numéricos entre 0.0 e 100.0. Talvez o código precise fazer alguma validação além da verificação null, como remover espaços vazios e espaços duplos, converter a cadeia de caracteres para o formato numérico e confirmar que o valor encontra-se no intervalo esperado.

Comentários

Elementos XML necessários

Cada definição de classe e todos os membros públicos devem ter marcas summary de XML para descrever a classe ou o membro. Isso permite que os usuários da classe vejam a descrição ao editar o código. A marca parameter de XML também é necessária, quando pertinente. No Visual Studio 2005, os editores de código em C# e VB vão inserir automaticamente as marcas summary e parameter, se você digitar /// e ''' (respectivamente) em uma linha em branco acima da definição de classe ou método. Isso é extremamente útil, pois você não precisa digitar as definições de marca XML corretamente. Só é necessário digitar as descrições!

Se a sua equipe usa cabeçalhos XML mais elaborados para as definições de classe ou membro (por exemplo, algumas equipes exigem cabeçalhos XML que descrevem o histórico de mudanças, incluindo descrição das informações de alteração, autor e data), verifique se os cabeçalhos estão presentes e se os dados apropriados foram inseridos.

Valide todos os elementos XML

Certifique-se de que todos os elementos XML estão bem-formados. Isso é importante porque as ferramentas que tratam dos comentários de XML no código-fonte exigem XML bem-formados para funcionar corretamente.

Retire todos os elementos XML gerados automaticamente que estejam vazios, caso sua equipe não necessite deles. Por exemplo, o VB gera automaticamente elementos returns e remarks que, em muitos casos, poderiam ser excluídos.

Comentários adicionais

Verifique se o código tem comentários adicionais suficientes para descrever a utilização, a lógica ou o comportamento dos elementos de código.

Qualidade dos comentários

Os comentários devem ser claros e descrever com precisão o código associado. Há várias situações em que os comentários não correspondem ao código. Cuidado com elas! Por exemplo, algumas vezes o código é alterado em um módulo e as pessoas se esquecem de atualizar os comentários. Ou, se uma seção de código de outro aplicativo for adaptada para um objetivo atual, os comentários do código original talvez não sejam mais apropriados ou precisos.

Constantes da cadeia de caracteres

Arquivos de recursos da cadeia de caracteres

Os literais da cadeia de caracteres devem ser empacotados em um arquivo de recursos da cadeia. Isso reúne as cadeias de caracteres em um local, o que facilita as mudanças no texto da mesmas. A utilização de arquivos de recursos da cadeia de caracteres também permite a localização e a globalização. Fazer e usar arquivos de recursos da cadeia são tarefas que costumavam ser um tanto quanto incômodas. No entanto, a Resource Refactoring Tool pode ajudar nessa questão, pelo menos para os projetos em C# e VB. Por exemplo, os literais da cadeia de caracteres na seguinte declaração:

private static string snippetSchemaPathBegin = 
Path.Combine(Environment.ExpandEnvironmentVariables("%ProgramFiles%"), 
@"\Microsoft Visual Studio 8\Xml\Schemas");

			

podem ser rapidamente alterados, com a utilização da Resource Refactoring Tool, para o seguinte:

private static string snippetSchemaPathBegin = 
Path.Combine(Environment.ExpandEnvironmentVariables( 
Strings.ProgramFiles), Strings.MicrosoftVisualStudio8XmlSchemas);

			

Nomes e caminhos de arquivos

Ao revisar um código, procure literais da cadeia de caracteres ou referências ao arquivo de recursos da cadeia que contenham caminhos de arquivo embutidos no código. Use sempre variáveis de ambiente e .NET APIs que fornecem um nome de caminho (por exemplo, System.Windows.Forms.Application.ExecutablePath, que retorna o caminho para o executável que iniciou o aplicativo), ou uma entrada do arquivo de configuração para os caminhos de referência. Em geral, as pessoas instalam coisas em outras unidades que não a C e de vez em quando personalizam o local de instalação de outras formas!

Da mesma maneira, os nomes de arquivo do aplicativo não devem ser definidos em um literal da cadeia de caracteres ou em uma referência do arquivo de recursos da cadeia. As alternativas aceitáveis são um arquivo de configuração, variáveis de ambiente ou entrada do usuário, tais como um parâmetro para um aplicativo de console ou uma caixa de diálogo de um arquivo em um aplicativo WinForms. Qualquer uma dessas alternativas permite ao usuário mais flexibilidade para usar o aplicativo.

O exemplo a seguir mostra várias práticas incorretas, incluindo um caminho embutido no código e uma variável pública.

			public static readonly string SnippetSchemaPathBegin = 
@"C:\Program Files\Microsoft Visual Studio 8\Xml\Schemas\";

			

A declaração poderia ser reescrita usando-se uma propriedade pública e uma variável de ambiente SystemDrive, como mostrado aqui.

			public string SnippetSchemaPathBegin { get { return 
snippetSchemaPathBegin; } }
        private static string snippetSchemaPathBegin = 
Environment.ExpandEnvironmentVariables("%SystemDrive%" + @"\Program 
Files\Microsoft Visual Studio 8\Xml\Schemas");

			

Da mesma forma, seria possível usar a variável de ambiente ProgramFiles, como mostrado aqui.

			private static string snippetSchemaPathBegin = 
Path.Combine(Environment.GetEnvironmentVariable("ProgramFiles"), 
@"Microsoft Visual Studio 8\Xml\Schemas");

			

Convenções de nomenclatura

Nomes

Em geral, os nomes devem ser legíveis e devem descrever claramente o item. Portanto, ao revisar os códigos, procure abreviaturas, nomes curtos ou nomes não-descritivos. É uma boa prática iniciar os nomes de função e método com um verbo, para representar a ação que realizam em seus objetos. Da mesma forma, os nomes de variável e propriedade devem ser substantivos, pois são objetos. Por exemplo, se você estivesse escrevendo uma classe para objetos geométricos planos, como um círculo, você poderia definir as propriedades como PontoCentral e Raio. Os nomes de função para essa classe poderiam ser CalcularCircunferencia e CalcularArea.

Uso de maiúsculas/minúsculas nos nomes

Verifique se o código-fonte segue as convenções de maiúsculas/minúsculas recomendadas na seção Estilos de Capitalização da documentação de Diretrizes de Nomenclatura que foi recomendada anteriormente. Em outras palavras, use camelCasing (a primeira letra do nome é minúscula e a primeira letra de cada palavra subseqüente no nome é maiúscula) para parâmetros, variáveis locais e variáveis privadas ou protegidas de uma classe. Use PascalCasing (a primeira letra de cada palavra no nome é maiúscula) para praticamente todo o resto, incluindo nomes de classe, métodos, propriedades, declarações de tipo e valores de enumeração.

Não aceite notação húngara

A notação húngara não é recomendada para código gerenciado. É difícil usar e ler corretamente esse tipo de notação. A dificuldade de leitura também pode prejudicar o entendimento da lógica. Algumas pessoas usam o húngaro por hábito, aprendido na codificação em C ou C++. Procure isso nas revisões de código.

Exceções

Lançando exceções

Caso o código lance uma exceção, certifique-se de que o tipo de exceção seja apropriado e que a mensagem identifique claramente o problema que fez com que o código lançasse a exceção. Coloque o máximo possível de informações de depuração na mensagem de exceção. Isso ajudará ao fazer o diagnóstico do problema, seja de um rastreamento de pilha ou de um arquivo de log.

Capturando exceções

Se o código que você está revisando chamar um método que provavelmente lançará uma exceção, verifique se o código tratará da exceção de forma razoável. Por exemplo, File.Open lança várias exceções comuns, incluindo FileNotFoundException e UnauthorizedAccessException. Seria razoável capturar essas exceções e apresentar uma mensagem de erro ao usuário.

Definindo exceções

Se o código para um assembly definir exceções, defina os tipos comumente utilizados em uma classe global de exceções para o assembly. Defina as exceções que são exclusivas para uma classe na própria classe.

Formatação

Use as regiões para organizar o código

Ao revisar o código, procure uma boa utilização das regiões para melhorar a legibilidade do código. As regiões são geralmente pouco utilizadas, mas às vezes há uma utilização excessiva.

As regiões ajudam a organizar logicamente o código e a melhorar a legibilidade dos arquivos grandes, pois você pode encolher as regiões desnecessárias e ver apenas a parte do código de que necessita atualmente. Encolher regiões também facilita a rolagem em arquivos grandes, quando desejamos encontrar uma região de interesse. No entanto, tenha cuidado com a forma como as regiões aninhadas são usadas. O encolhimento de uma região externa poderia ocultar as regiões internas e poderia, na verdade, fazer com que ficasse mais difícil encontrar uma região de interesse.

Entre os locais comuns para usar as regiões estão ao redor de dados privados de classe, construtores, propriedades públicas, métodos privados e métodos públicos. Em um projeto de teste, as regiões são geralmente usadas para agrupar os testes. Por exemplo, uma região poderia agrupar os testes de unidade para um dos métodos de classe.

Use linhas em branco para separar definições

A utilização de linhas em branco entre as definições do mesmo nível melhora a legibilidade. No entanto, não use mais do que duas linhas em branco consecutivas.

Diversos

Sem variáveis públicas

Verifique se as variáveis de dados de uma classe são declaradas como privadas. Se você preferir permitir o acesso aos dados, defina uma propriedade pública ou protegida para fornecer acesso ao usuário.

Valores de retorno

Os métodos que retornam um valor devem usar a declaração de retorno, em vez de atribuir um valor ao nome do método.

Sem declarações GoTo

As declarações GoTo são desnecessárias. De vez em quando, pode-se usá-las em circunstâncias especiais, mas é sempre bom ficar atento a elas durante as revisões de código.

Constantes numéricas

Por padrão, quase todas as ferramentas de depuração vão exibir constantes numéricas em hexadecimal. Portanto, defina as constantes numéricas em hexadecimal para identificações de janela, identificações de controle e assim por diante. Dessa forma, você não precisa convertê-los de decimal para hexadecimal durante a depuração.

Conclusão

Este documento discutiu as práticas recomendadas para revisão de código gerenciado. Algumas delas são comuns tanto ao código gerenciado quanto ao não-gerenciado. Outras são exclusivas para revisão do código gerenciado.