C# - Boas Práticas :  Aprendendo com maus exemplos - I


 Neste artigo vou mostrar como aplicar boas práticas de programação usando exemplos de código criados sem preocupação alguma em ter um código robusto, fácil de manter e fácil de entender. Vamos assim aprender a partir de maus exemplos de códigos a usar as boas práticas de programação.

Ao invés de começar teorizando sobre boas práticas e qualidade de código, o que pode levar a uma discussão acirrada, pois as opiniões são muito divergentes quanto à abordagem que se deve dar ao assunto, eu vou tratar o assunto usando um enfoque mais prático partindo de um código mal escrito e implementando boas práticas para que ao final o resultado esteja melhorado.

Assim, vou tratar com exemplos concretos e mostrando que vale apena escrever um código aderente às boas práticas de programação.

Antes de prosseguir com o artigo tenha em mente que eu vou usar a seguinte abordagem :

- Vou mostrar como usar os recursos da linguagem C# e padrões de projeto na prática ;
- Vou usar exemplos simplificados para focar somente no assunto proposto;
- A abordagem não pretende ser vista como a única solução mas tem como objetivo que o código qualidade e seja robusto;
- Para tornar mais simples os exemplos e me ater ao unicamente aos problemas eu não vou me preocupar com tratamento de erros, realizar log de auditorias. etc.;
- Meu objetivo será mostrar soluções comuns e simples para problemas de programação que ocorrem no dia a dia;

Recursos usados:

Nota: Baixe e use a versão Community 2015 do VS ela é grátis e é equivalente a versão Professional.

Criando o projeto no VS Community

Abra o VS Community 2015 e clique em New Project;

Selecione a linguagem Other Project Types -> Visual Studio Solutions;

Selecione o template Blank Solution e informe o nome BoasPraticas_CSharp e clique no botão OK;

Será criada uma solução vazia onde iremos incluir nossos projetos.

Criando o projeto exemplo : uma classe que cheira mal 

Vamos criar um projeto do tipo Class Library em nossa solução e neste projeto definir a nossa classe de partida.

No menu File clique em Add -> New Project ;

Selecione o template Class Library e informe o nome Projeto_BoasPraticas.CodigoRuim e clique em OK;

Pelo nome deu para perceber que neste projeto teremos uma classe com muitos problemas.

Então veja o código da classe abaixo, e, tente entender qual o propósito dessa classe:

    class Class1
    {
        public decimal Calcular(decimal valor, int tipo, int anos)
        {
            decimal resultado = 0;
            decimal desc = (anos > 5) ? (decimal)5 / 100 : (decimal)anos / 100;
            if (tipo == 1)
            {
                resultado = valor;
            }
            else if (tipo == 2)
            {
                resultado = (valor - (0.1m * valor)) - desc * (valor - (0.1m * valor));
            }
            else if (tipo == 3)
            {
                resultado = (0.7m * valor) - desc * (0.7m * valor);
            }
            else if (tipo == 4)
            {
                resultado = (valor - (0.5m * valor)) - desc * (valor - (0.5m * valor));
            }
            return resultado;
        }
    }

Esse é um tipo de código que estraga o dia de qualquer bom desenvolvedor.

A primeira vista não dá para perceber qual o papel dessa classe (é que nome hein... Class1).

Podemos supor que ela realiza alguns cálculos que estão relacionados a descontos e envolvem valores e tipos e anos.

Vamos assumir o risco e supor que o propósito da classe seja gerenciar o desconto de clientes que realizam compras. E é realmente isso que ela faz.

Eu nem precisaria dizer, mas esta classe esta cheirando mal, é ilegível, difícil de manter, difícil de estender e esta usando más práticas e antipadrões.

Vamos perder um tempo para mostrar os problemas encontrados nesta classe...

  Identificando os problemas

1- O problema da nomenclatura (ou falta dela) 

Podemos apenas tentar adivinhar o que o método Calcular faz e o quais as funções dos parâmetros usados no método.

É muito difícil extrair um algoritmo de calculo desta classe.

Se você precisar extrair o detalhes do algoritmo usado neste código vai ter que modificar o código ou vai ficar perdendo tempo tentando entender o que o método Calcular faz.

Se após todo esse esforço não criarmos uma documentação sobre isso, ou se ainda não refatorarmos o código todo esse processo vai se repetir quando outro desenvolvedor se deparar com essa classe. 

Estamos assim perdendo um precioso tempo...

2- O problema dos números mágicos

Analisando o código você sabe o que significa a variável tipo ? E a variável desc ?

Vou ter que dizer porque acho que você nunca vai descobrir...

A variável tipo indica o status da conta do cliente e a variável desc representa o percentual de desconto que deverá ser usado.

Agora perceba que temos uma instrução if-else if que escolhe como calcular o preço do produto aplicando o desconto.

Em cada instrução if temos a variável tipo comparada com números mágicos que significam alguma coisa; mas significam o quê ?

Você faz alguma ideia que tipo de conta seja a conta 1, 2, 3 e 4 ?

Realmente fica difícil descobrir !!!

Esses números estão relacionados com os tipos de clientes que poderemos ter em relação a sua fidelidade : clientes registrados, clientes comuns, clientes especiais, etc.

3- O problema dos bugs ocultos (difíceis de perceber)

Com um código tão sujo e ilegível é muito fácil não perceber problemas que vão causar bugs e que estão ocultos.

Imagine que precisamos adicionar um novo status de conta de cliente ao nosso sistema, algo do tipo : cliente VIP.

Como esse tipo de status de cliente não esta previsto o bloco if-else if vai retornar o valor 0 pois nenhuma condição será satisfeita. Ou seja o cliente esta comprando mas não esta pagando.

Percebeu o bug ?

Como o problema não é facilmente percebido, existe uma grande chance dele se manifestar quando a aplicação estiver em produção, dando assim prejuízo para sua empresa.

É isso que faz um código não documentado e ilegível , você gasta muito tempo para entender o código e corre riscos de cometer erros difíceis de detectar.

4- O problema dos números mágicos novamente

Estamos à volta novamente com os números mágicos.

Você sabe o que significa os números 0.1, 0.7 e 0.5 ?

Vamos imaginar que você tem que alterar a seguinte linha de código :

 resultado = (valor - (0.5m * valor)) - desc * (valor - (0.5m * valor));

Sem saber o que significam os números é um tiro do escuro...

O mesmo problema ocorre no trecho de código a seguir :

 decimal desc = (anos > 5) ? (decimal)5 / 100 : (decimal)anos / 100;

Esta linha de código esta calculando  o desconto percentual com base no tempo de conta do cliente.

Você conseguiria descobrir isso rapidamente sem ajuda ?

Outro detalhe, o que significa o número 5  em (anos > 5) ?  Porque isso esta sendo feito ?

Acredite se quiser mas esse número significa o desconto máximo percentual a qual o cliente pode ter conforme a sua fidelidade.

Fala sério...

5- O problema da duplicação de código (princípio DRY)

Dá para perceber, após algum tempo, que o método Calcular apresenta código repetido em muitos lugares.

O código a seguir :

  resultado = (valor - (0.1m * valor)) - desc * (valor - (0.1m * valor));

possui a mesma lógica que a linha de código :

resultado = (valor - (0.5m * valor)) - desc * (valor - (0.5m * valor));

Podemos parametrizar facilmente o código usado e evitar a sua duplicação.

Código duplicado e espalhado significa maior propensão a erros, e, mais dificuldade de manter o código.

6- O problema das múltiplas responsabilidades do código (princípio SRP)

Podemos identificar pelo menos 3 responsabilidades em nosso método Calcular:

  1. Escolher o algoritmo de cálculo;
  2. Calcular o desconto de acordo com o status da conta;
  3. Calcular o desconto pelo tempo de fidelidade do cliente;

Isso viola o princípio SRP - Single Responsability Principle - ou princípio da responsabilidade única que diz que uma classe deve ter apenas um motivo para mudar.

E qual o problema disso ?

Se precisarmos modificar uma dessas responsabilidades assumidas pelo método as demais serão afetadas e teremos que testar toda a nossa classe novamente.

Pura perda de tempo.

  Tratando de corrigir os problemas

Identificamos os principais problemas descritos acima que se constituem em más práticas e fazem com que o código 'cheire mal' causando problemas e prejuízo.

Vamos agora arregaçar as mangas e corrigir os problemas usando boas práticas para obter um código legível, limpo, fácil de manter e testar.

Faremos isso em etapas para que o entendimento seja facilitado na próxima parte do artigo.

Porque toda a carne é como a erva, e toda a glória do homem como a flor da erva. Secou-se a erva, e caiu a sua flor;
Mas a palavra do Senhor permanece para sempre.E esta é a palavra que entre vós foi evangeliza
da.
1 Pedro 1:24-25

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti