Arquivo

Textos com Etiquetas ‘C#’

[POG] Deveria lançar uma “excessão”

24 de fevereiro de 2012

Não preciso falar nada, o nome do teste diz tudo:

[TestMethod]
public void Deveria_lancar_uma_excessao_ao_obter_para_recusa_com_id_igual_a_zero()
{
    try
    {
        Transacao transacao = this.transacaoBO.ObtemParaRecusa(Guid.NewGuid(), 0);

        Assert.Fail("Deveria ser lançada uma ArgumentException.");
    }
    catch (ArgumentException ex)
    {
        Assert.AreEqual<string>(ex.Message, "ID da conta não pode ser menor ou igual a zero." + Environment.NewLine + "Parameter name: idComprador");
    }
}

Exceção mesmo é escrever código em português. Se fosse em inglês, esse atentado à lingua portuguesa teria sido evitado.

Se você não conhece POG (Programação Orientada a Gambiarras), leia esse artigo para entender melhor.

POG , ,

[POG] SendEmail ou EnviarEmail

19 de junho de 2011


Estou dando manutenção em sistema feito em .NET, corrigindo vários bugs e implementando algumas melhorias. Os autores do código não estão mais envolvidos no projeto.

Em uma página de formulário de contato, um e-mail é enviado para a equipe de atendimento e outro para o próprio cliente que preencheu o formulário de contato. Esses e-mails são enviados através de uma classe chamada Utils, através de dois métodos distintos SendEmail e EnviarEmail.

Vamos dar uma olhada no código C# da classe Utils:

public class Utils
{
  public static void SendEmail(string senderEmail, string senderName, string subject, string body, params string[] destinyEmails)
  {
    MailMessage mailMessage = new MailMessage();
    mailMessage.From = new MailAddress(senderEmail, senderName);
    mailMessage.Subject = subject;
    mailMessage.Body = body
    mailMessage.IsBodyHtml = true;

    foreach (string to in destinyEmails)
    {
      mailMessage.To.Add(to);
    }

    SmtpClient smtpClient = new SmtpClient(ConfigurationSettings.AppSettings["Email.Host"]);

    if (!string.IsNullOrEmpty(ConfigurationSettings.AppSettings["Email.User"]))
      smtpClient.Credentials = new System.Net.NetworkCredential(ConfigurationSettings.AppSettings["Email.User"], ConfigurationSettings.AppSettings["Email.Password"]);
    smtpClient.Send(mailMessage);
  }

  public static void EnviarEmail(string pEmail, string pAssunto, string Corpo)
  {
    try
    {
      string emailFrom = ConfigurationSettings.AppSettings["Email.From"];
      string NomeFrom = ConfigurationSettings.AppSettings["Email.Nome.From"];
      Model.Entities.Utils.SendEmail(emailFrom, NomeFrom, pAssunto, Corpo, new string[] { pEmail });
    }
    catch (Exception ex)
    {
      throw new Exception(ex.Message);
    }
  }

  // Outros métodos
}

O método SendEmail até que passa, mas daria para melhorar. Por exemplo, eu colocaria chaves no if da linha 18 para não confundir com a execução da linha 20.

Já o método EnviarEmail, nas linhas 23 a 35, tem uma lista de POGs:

  • Primeira coisa: por que o Pateta criou o método com esse nome? No mínimo esse método seria uma sobrecarga do método SendEmail.
  • O que é esse “p” como prefixo dos dois primeiros parâmetros? É para dizer que é um parâmetro? Nossa, bem mais eficaz que todo o intelisense do Visual Studio.
  • Legal esse terceiro parâmetro chamar Corpo. Esse nome é bem coerente com a convenção de nomenclatura de parâmetros.
  • Nas linhas 27 e 28 a declaração de duas variáveis locais emailFrom e NomeFrom, uma em camel case e outro em pascal case.
  • Na linha 29 uma chamada do método SendEmail com toda a hierarquia de namespace, sendo que o método chamado é da própria classse Utils.
  • Ainda na linha 29, olha que lindo que foi a passagem de parâmetros para: emailFrom, NomeFrom, pAssunto. Cada variável com uma convenção de nomenclatura diferente. O padrão é não seguir nenhum padrão.
  • Mais ainda na linha 29, no último parâmetro o Pateta criou uma array de um único elemento para passar o e-mail de destino da mensagem. No método SendEmail esse parâmetro está definido com a palavra-chave params, que permite que seja passado nenhum valor, um valor, n valores separados por vírgula ou um array.
  • E para finalizar em grande estilo, nas linhas 31 a 34, uma captura de exceção para colocar dentro de outra exceção e lançá-la de novo. Ou seja, só colocou lixo no stack trace.

Se você não conhece POG (Programação Orientada a Gambiarras), leia esse artigo para entender melhor.

POG ,

[InfoQ] C# 5.0 terá sintax sugar para operações assíncronas

4 de novembro de 2010

O time de desenvolvimento de .NET da Microsoft anunciou nessa última semana que a próxima versão da linguagem C# terá uma nova sintaxe, mais enxuta, para realizar operações assíncronas.

Atualmente, para realizar uma tarefa assíncrona é necessário utlizar callbacks, seja declarando métodos separados ou utilizar métodos anônimos.

No C# 5.0, com a utilização dos novos comandos async e await, essa tarefa ficará muito mais fácil de escrever.

Veja a notícia completa na InfoQ Brasil:
http://www.infoq.com/br/news/2010/11/csharp-5-sintax-sugar

Veja também outras notícias e artigos sobre .NET na InfoQ Brasil:
http://www.infoq.com/br/dotnet

.NET , , , ,

[POG] Mascarando dados sigilosos de cartão de crédito

28 de março de 2010

Se você não sabe o que é POG, veja esse post antes.

Imagine que você tenha uma string formatada como um XML, e nesse XML exista um nó com um dado sigiloso, por exemplo, o número de um cartão de crédito. Então você cria um método que recebe essa string e mais um parâmetro com o nome do nó que contém o dado sigiloso. O método irá retornar a mesma string substituindo o valor sigiloso por asteriscos (*).

Por exemplo, para a representação XML abaixo:

<prodis>
  <some_text>Prodis</some_text>
  <sensitive_data>4010098287290192</sensitive_data>
  <some_value>456</some_value>
</prodis>

Queremos o valor “4010098287290192″ presente no nó sensitive_data seja substituído por “****************”. A utilização desse método em C# seria assim:

string xml  = "<prodis>"
       xml += "  <some_text>Prodis</some_text>"
       xml += "  <sensitive_data>4010098287290192</sensitive_data>"
       xml += "  <some_value>456</some_value>"
       xml += "</prodis>"

xml = Util.MaskXmlData(xml, "sensitive_data");

/*
O valor da variável xml agora é:
<prodis>
  <some_text>Prodis</some_text>
  <sensitive_data>****************</sensitive_data>
  <some_value>456</some_value>
</prodis>
*/

Nem vamos entrar no mérito do porquê esse XML está em uma string. Vamos nos concentrar na resolução do problema em questão.

Veja agora como um Pateta implementou esse método utilizando técnicas POG:

{
  public static string MascaraCartaoXml(string xml, string tagAbertura, string tagFechamento)
  {
    string retorno = xml;

    int posicaoInicio = (xml.IndexOf(tagAbertura)) + (tagAbertura.Length);
    int posicaoFim = (xml.IndexOf(tagFechamento));
    string cartao = xml.Substring(posicaoInicio, posicaoFim - posicaoInicio);
    string cartaoMascarado = cartao;

    for (int i = 0; i < cartao.Length; i++)
    {
      cartaoMascarado = cartaoMascarado.Replace(cartao.Substring(i, 1), "*");
    }

    retorno = xml.Replace(tagAbertura + cartao + tagFechamento, tagAbertura + cartaoMascarado + tagFechamento);

    return retorno;
  }
}

Meus comentários a respeito:

  • Que fique bem claro que esse método é única e exclusivamente para mascarar dados de cartão (de crédito?). Qualquer outro texto que não seja cartão não poderá ser mascarado. Será que serve também para cartão telefônico ou cartão de Natal?
  • Você já viu algum XML bem formatado onde o nome da tag de abertura de um nó é diferente do nome da sua tag de fechamento? Talvez no mundo POG isso seja possível.
  • Preciso dizer alguma coisa sobre as linhas 9 a 14 ou posso somente dar risada?

POG , ,

Desprenda-se de convenções de nomenclatura em nome de testes

21 de novembro de 2009

Eu compartilho da opinião de Jimmy Bogard, que diz que os nomes dos testes precisam descrever o que e o porque, a partir da perspectiva do usuário, onde o desenvolver possa ler o nome do teste e claramente entender o comportamento que é esperado.

Um teste unitário nada mais é que um método em uma classe, e tanto em C# como Java, existem convenções de nomenclatura de métodos.

Em C#, nome de métodos são declarados utilizando Pascal Case:

[TestMethod]
public void ProductShouldHaveAtLeastOneCategory()
{
  //Test implementation.
}

Já em Java, convencionou-se escrever métodos utilizando Camel Case:

@Test
public void productShouldHaveAtLeastOneCategory() {
  //Test implementation.
}

Muitas vezes, o nome desses testes (métodos) ficam um tanto longos, como os exemplos acima. Dessa forma, a legibilidade não é muito boa.

Seguindo um dos conselhos de Neal Ford, em sua apresentação 10 Ways to Improve Your Code, você pode deixar de lado as convenções de nomenclatura da linguagem em favor da legilidade dos nomes dos seus testes. Escreva o nome do teste como se fosse uma frase, nada de letras maiúsculas para cada palavra, e use “_” (underscore) para separar as palavras.

Veja como fica o exemplo acima em C#:

[TestMethod]
public void Product_should_have_at_least_one_category()
{
  //Test implementation.
}

E agora em Java:

@Test
public void product_should_have_at_least_one_category() {
  //Test implementation.
}

Não há nenhum mal em se desprender das convenções de nomenclatura de C# e Java em prol da legibilidade dos nomes dos testes. Afinal, testes são uma documentação executável e nós queremos uma documentação clara para nosso código.

TDD , , , , , , ,

[Tradução] Qual é a diferença entre os operadores “as” e “cast”?

29 de outubro de 2009

Muitas pessoas lhe dirão que a diferença entre “(Alpha) bravo” e “bravo as Alpha” é que o primeiro lança uma exceção se a conversão falhar, enquanto que o segundo retorna null. De qualquer forma isso é correto, e isso é a diferença mais óbvia, mas não é a única diferença. Há armadilhas para se tomar cuidado aqui.

Primeiro, desde que o resultado do operador “as” pode ser null, o tipo do resultado precisa ser um dos que aceitam um valor nulo: um tipo referência ou tipo valor nullable. Você não pode fazer “as int”, isso não faz sentido. Se o argumento não é um int, então qual valor de retorno deveria ser? O tipo da expressão “as” é sempre um tipo nomeado, então ele precisa ser um tipo que pode receber null.

Segundo, o operador cast, como eu discuti antes, é uma besta estranha. Ele significa duas coisas contraditórias: “verifique para ver se o objeto realmente é desse tipo, lance uma exceção se não for” e “esse objeto não é do tipo informado; encontre um valor equivalente que pertença ao tipo informado”. O segundo significado do operador cast não é compartilhado pelo operador “as”. Se você diz

short s = (short)123;
int? i = s as int?;

então você está sem sorte. O operador “as” não fará conversões “representação-substituição” de short para int nullable como o operador cast faria. Similarmente, se você tem uma classe Alpha e uma outra classe não relacionada Bravo, com uma conversão de Bravo para Alpha, então “(Alpha) bravo” será convertido, mas “bravo as Alpha” não. O operador “as” apenas considera conversões de referência, boxing e unboxing.

E finalmente, é claro que o uso dos dois operadores são superficialmente similares, mas semanticamente completamente diferentes. O cast comunica para o leitor “Eu estou certo que esta conversão é legal e eu concordo em receber uma exceção se eu estiver errado”. O operador “as” comunica “Eu não sei se esta conversão é legal ou não; nós vamos tentar e ver o que acontece”.

Esse texto é uma tradução do post original que Eric Lippert, engenheiro de software da Microsoft, publicou no seu blog Fabulous Adventures In Coding. A versão original você pode ler aqui.

Observação: Essa é minha primeira experiência em tradução de artigos técnicos. Seu comentário expressando sua opinião a respeito é muito bem vinda.

.NET , , , , , ,

Cheeseburgers, Decorators e Mocks

29 de julho de 2009

Em São Paulo, eu sempre comi cheeseburgers feitos com pão, hamburguer e queijo. Mas quando eu fui para Itararé, cidade do interior do estado de São Paulo, descobri que eles também colocavam milho no sanduíche.

Para exemplificar, vamos imaginar que o cheeseburger de Ilhéus-BA, venha com molho de pimenta. Só para constar, eu nunca fui para Ilhéus, apesar de ser a cidade natal de meu pai. Então na verdade não tenho a mínima idéia de como seja o cheeseburger de lá.

Imagem original de MarketFare Foods, Inc.

Imagem original de MarketFare Foods, Inc.

Vamos transportar esses três tipos de cheeseburgers para objetos e fazer alguns testes com eles. Usarei como plataforma .NET, linguagem C#, a ferramenta de testes unitários que vem com o Visual Studio 2008 e o Rhino Mocks como framework de criação de mocks.

Leia mais…

.NET, Arquitetura , , , , , , , , , , , , ,