O que é Clean Code? Confira as melhores dicas!

Yuri Corredor

O Clean Code (código limpo) é um método de desenvolvimento de softwares que tem como proposta a criação de códigos de forma mais simples e objetiva. Com algumas boas práticas, a ideia é deixar o código mais acessível e com manutenção facilitada. Considerando que as mudanças na tecnologia, no mercado e a demanda dos usuários são constantes, é essencial entender maneiras distintas de criar códigos de uma forma mais eficiente. Para entender mais sobre estas boas práticas de desenvolvimento e como elas podem te ajudar, acompanhe nosso artigo de hoje.

Conteúdo

Clean Code é uma forma de desenvolvimento de sistemas com a aplicação de práticas voltadas a facilitar a escrita e a leitura de um código para ser o mais limpo e compreensível possível. Quando se aplica esta filosofia na criação de códigos, fica muito mais fácil realizar testes, correções e manutenção do código-fonte, prolongando a vida do software

Vale ressaltar que a expressão do código limpo ganhou popularidade em 2008 com a publicação do livro “Clean Code: A Handbook of Agile Software Craftsmanship” de Robert Cecil Martin ou Uncle Bob como também é conhecido.  

Presente no cenário de desenvolvimento desde 1970, Uncle Bob notou que a dificuldade em fazer a manutenção de códigos é um dos principais desafios na área de programação. Isso porque à medida que surgem novas demandas de atualizações ou funções, lidar com código mal elaborado torna este processo cada vez mais complexo.

O que é considerado um Bad Code (Código Sujo)?

Bad Code ou Código Sujo são códigos de programação considerados difíceis de entender, expandir ou fazer manutenção. Escritos de maneira desorganizada, não seguem boas práticas de desenvolvimento e engenharia de software, resultando em um código de baixa qualidade.]

Dificilmente um programador não se deparou com um Bad Code e com a dor de cabeça que eles podem gerar, uma vez que códigos desorganizados criam um efeito dominó, onde pequenas alterações podem desencadear problemas em todo o sistema, transformando tarefas simples em problemas significativos.

Quando um código é mal estruturado, surgem desafios como dificuldade para corrigir erros, necessidade de refatorações extensas e aumento do tempo de desenvolvimento. Por isso, é essencial adotar práticas de Clean Code como nomes descritivos, funções com responsabilidades únicas e modularidade. 

Um código bem organizado não só facilita a manutenção, mas também acelera o progresso e reduz riscos. Investir em boas práticas desde o início é a melhor forma de garantir que o sistema evolua de maneira eficiente e sustentável.

Para que serve o Clean Code?

É uma prática essencial no desenvolvimento de software que visa simplificar a criação e a manutenção de códigos. Considerando que atualizações e novas funcionalidades são inevitáveis, ter um código bem estruturado e organizado é fundamental para garantir a eficiência e a longevidade de um sistema.

No entanto, muitos programadores negligenciam a importância do Clean Code, acreditando que se o código está funcionando, não há motivos para preocupação. Isso pode levar a problemas futuros, já que a manutenção e a revisão de códigos são etapas indispensáveis no ciclo de vida de qualquer projeto. 

Outra questão, é que qualquer código pode se tornar ultrapassado e cair em desuso. Um código desatualizado ou que precise de algum remendo fica difícil de manter, tornando mais fácil começar um novo sistema do que continuar a operar uma versão ruim. 

Adotando as boas práticas do Clean Code evitam-se problemas, promovendo a clareza, a legibilidade e a organização do código. Isso não só facilita a implementação de novas funcionalidades, mas também reduz custos e tempo de desenvolvimento, já que um código bem escrito é mais fácil de entender e modificar.

Por que o Clean Code é importante?

O Clean Code propõe o desenvolvimento de uma codificação legível e de fácil manutenção, a fim de qualquer pessoa que precise ler o código, compreenda com tranquilidade e faça alterações e correções com praticidade. 

Afinal de contas, é impossível não haver a necessidade de mudanças em um sistema. Seja por modificações nos objetivos de negócio da empresa, como por novas necessidades dos usuários, é essencial ter um software que se adequa facilmente a novos cenários. 

Quais são os 7 princípios do Clean Code?

Os princípios do Clean Code são baseados nas ideias de Robert C. Martin (Uncle Bob). Eles incluem boa nomenclatura, escrita simples, aplicação de funções mais curtas e diretas, cuidado com inserção excessiva de comentários durante a codificação, tratamento dos erros e a realização de testes

Vejamos mais detalhes seguir. 

1. Nomes fáceis e significativos

Um código deve ser fácil de ler e entender. Transmitir a ideia com objetividade e clareza, faz toda diferença na hora de interpretar o código. 

Portanto, use nomes significativos para variáveis, funções e classes, evitando abreviações obscuras ou nomes genéricos. 

2. Código Simples

Ao programar deixe o código o mais limpo e simples possível para ficar o mais acessível para futuros programadores. Agora, quando for o caso onde você está continuando uma programação que não foi você que iniciou, faça como os escoteiros e “deixe o lugar mais limpo do que quando você o encontrou.” 

3. Funções simples e curtas 

Classes e funções devem ser objetivas e bem definidas. Isso porque os códigos funcionam de maneira narrativa, então é preciso que os programadores, como autores do desenvolvimento, se atentem para o modo como a história será contada. 

4. DRY (Don’t Repeat Yourself)

Para manter uma boa legibilidade do software, se apegue ao princípio do “não repita a si mesmo” descrito no livro The Pragmatic Programmer, evitando o uso de diversos “ifs” em sequência, aplicando uma representação única em cada parte do conhecimento. 

Evite a repetição de códigos extraindo funcionalidades duplicadas em funções ou módulos reutilizáveis. 

5. Cuidado com comentários

À medida que a programação do código é alterada, os comentários passam a não condizer com a realidade, ficando por vezes esquecidos. 

Assim, tenha cuidado com a inserção excessiva de comentários. Certifique-se em fazê-los apenas quando forem realmente necessários. 

6. Tratamento de erros

Erros podem interromper o bom funcionamento de um software e afetar diretamente a rotina de uma empresa.  É importante realizar o tratamento de erros, realizando a correção dos códigos para impedir este tipo de situação. 

7. Testes limpos

A cada nova funcionalidade ou alteração, é essencial realizar testes para garantir o correto funcionamento do sistema. Até porque, testar o sistema é uma etapa importante e contínua no desenvolvimento de software.

Um teste bem feito, ou limpo, deve ser:

  • Rápido: Devido sua execução repetitiva, é fundamental que os testes tenham um processamento ágil para não atrasar o ciclo de desenvolvimento;
  • Independente: Cada teste deve ser autossuficiente e não depender de outros testes para não impactar o sistema como um todo, evitando efeitos em cascata.
  • Repetível: Repetir testes faz parte do desenvolvimento, por isso os códigos devem permitir a repetição de testes várias vezes em ambientes distintos; 
  • Passível de validação: Um teste eficaz deve fornecer resultados claros e objetivos, retornando respostas booleanas (true ou false) para indicar sucesso ou falha;
  • Pontual: Os testes devem ser escritos de forma precisa. Isso ajuda a evitar complexidades desnecessárias e garante que o código atenda aos requisitos desde o início.

Como fazer um código limpo?

Escrever um código limpo exige a adoção de boa filosofia de desenvolvimento. Entre elas estão algumas regras gerais e específicas ligadas aos comentários, estruturação do código, nomes, funções e métodos. 

Confira a seguir algumas dicas de regras e boas práticas para fazer um clean code.

Regras gerais

As regras gerais para o desenvolvimento de código limpo abordam direcionamentos como: seguir convenções, manter o código simples e estar atento às origens dos problemas. Confira as regras com mais detalhes a seguir.

Siga as convenções

Quando se entra em um novo projeto com convenções estabelecidas, procure segui-las à risca. Por exemplo, se são utilizadas constantes em letras maiúsculas ou enumeradores com prefixo “O”, não importa qual é a regra, o importante é aderir aos padrões previamente definidos. 

Mantenha o código simples (KISS)

Siga o princípio KISS: Keep It Stupid Simple (Mantenha isso estupidamente simples)!

Não complique as coisas, mantenha tudo o mais simples possível para que as resoluções sejam feitas de forma prática. 

Procure a causa raiz do problema

Não se atenha a superficialidades. Procure se aprofundar nos problemas para realmente corrigi-los e evitar retrabalhos.

Regras de design

Quando pensamos no design do código é importante manter os dados de configuração em alto nível, utilizar processamentos em threads separados e se atentar para algumas indicações. Confira.

Mantenha dados de configuração em alto nível

Toda aplicação possui configurações, como as famosas ConnectionStrings. É importante manter essas configurações ou o processo de interpretação delas no nível mais alto que conseguir. 

Evite:

public class MeuServico

{

    public void Conectar()

    {

        string conexao = “Server=meuServidor;Database=minhaBase;User Id=usuario;Password=senha;”;

        var banco = new Banco(conexao);

    }

}

Recomendado:

public class Configuracao

{

    public string ConnectionString { get; set; }

}

public class MeuServico

{

    private readonly Configuracao _config;

    public MeuServico(Configuracao config)

    {

        _config = config;

    }

    public void Conectar()

    {

        var banco = new Banco(_config.ConnectionString);

    }

}

Isso permite que a configuração seja gerenciada centralmente e facilmente alterada sem precisar modificar o código principal.

Mult-thread

Utilize processamento em threads separados sempre que possível. O C# oferece suporte a multi-threads e paralelismo há algum tempo, e recursos como Async/Await facilitam essa implementação. Por exemplo:

Sem async/await:

[HttpGet(“produtos”)]

public IActionResult ListarProdutos([FromServices] IProdutoRepository repository)

{

    ViewBag.Produtos = repository.GetProdutos();

    return View();

}

Com async/await:

[HttpGet(“produtos”)]

public async Task<IActionResult> ListarProdutos([FromServices] IProdutoRepository repository)

{

    ViewBag.Produtos = await repository.GetProdutosAsync();

    return View();

}

Neste exemplo, a operação de “buscar produtos” foi transformada em assíncrona, utilizando async/await para melhorar a eficiência e a responsividade da aplicação.

Separe os códigos mult-thread

Uma das bases para um código limpo é manter o que é assíncrono separado do que é síncrono para que um trecho do código não force o outro. Utilizando o mesmo exemplo do tópico anterior fica assim:

Método síncrono:

[HttpGet(“produtos”)]

public IActionResult ListarProdutos([FromServices] IProdutoRepository repository)

{

    ViewBag.Produtos = repository.GetProdutos();

    return View();

}


Método assíncrono:

[HttpGet(“produtos/async”)]

public async Task<IActionResult> ListarProdutosAsync([FromServices] IProdutoRepository repository)

{

    ViewBag.Produtos = await repository.GetProdutosAsync();

    return View(“ListarProdutos”); // Reutiliza a mesma view do método síncrono

}

Dessa forma, o método síncrono “ListarProdutos” e o método assíncrono “ListarProdutosAsync” são mantidos separados, permitindo que cada um seja utilizado conforme a necessidade, sem forçar a sincronicidade ou assincronicidade em toda a cadeia de chamadas. Isso também facilita a manutenção e a clareza do código.

Utilize Async como sufixo

Sempre utilize o sufixo async para identificar um método assíncrono. Por exemplo:

public async Task<IEnumerable<Produto>> BuscarProdutosAsync(int categoriaId)

{

    // Simula uma operação assíncrona, como uma consulta ao banco de dados

    return await _produtoRepository.BuscarPorCategoriaAsync(categoriaId);

Evite configurações desnecessárias

Procure não deixar configurações que ainda não tiverem seus objetivos determinados por alguém. Lembre-se sempre de deixar o código o mais limpo possível e descomplicado. 

Evite:

public class Servico

{

    private string _parametro = “”;

    public Servico()

    {

        _parametro = “ValorPadrao”; // Definição sem necessidade

    }

}

Recomendado:

public class Servico

{

    private readonly string _parametro;

    public Servico(string parametro)

    {

        _parametro = parametro ?? throw new ArgumentNullException(nameof(parametro));

    }

}

Utilize injeção de dependência

Para deixar o código mais limpo e desamarrado, use injeção de dependência na programação. 

Evite:

public class UsuarioService

{

    private UsuarioRepository _repository;

    public UsuarioService()

    {

        _repository = new UsuarioRepository(); // Alto acoplamento

    }

}

Recomendado:

public class UsuarioService

{

    private readonly IUsuarioRepository _repository;

    public UsuarioService(IUsuarioRepository repository)

    {

        _repository = repository;

    }

}

Lei de Demeter

A Lei de Demeter (LoD), também conhecida como Princípio do Menor Conhecimento, estabelece diretrizes para promover um design de software mais modular e desacoplado. Seus principais pontos são:

  • Cada componente deve ter conhecimento apenas sobre unidades diretamente relacionadas a ele;
  • Um componente deve interagir apenas com seus “amigos” próximos, ou seja, objetos com os quais ele tem uma relação direta;
  • Não se deve interagir com “estranhos” (objetos indiretos ou distantes). A comunicação deve ocorrer apenas com amigos imediatos.

Vejamos um exemplo:

Classes básicas:

public class Pedido

{

    public Pagamento Pagamento { get; set; }

}

public class Pagamento

{

    public decimal Valor { get; set; }

    public void Processar() 

    { 

        // Lógica para processar o pagamento

    }

}

Mau exemplo (violando a Lei de Demeter):

public class ProcessadorPedido

{

    public void FinalizarPedido()

    {

        var pedido = new Pedido();

        pedido.Pagamento.Processar(); // <– Acesso direto a um objeto distante

    }

}

Bom exemplo (respeitando a Lei de Demeter):

public class Pedido

{

    public Pagamento Pagamento { get; set; }

    public void Finalizar()

    {

        Pagamento?.Processar(); // Encapsula a lógica dentro da classe Pedido

    }

}

public class ProcessadorPedido

{

    public void FinalizarPedido()

    {

        var pedido = new Pedido();

        pedido.Finalizar(); // Interage apenas com o objeto imediato (Pedido)

    }

Regras sobre entendimento de código

Entender os códigos é essencial para manter a programação bem escrita e com fácil manutenção. Ser consistente, utilizar variáveis concisas, evitar dependências lógicas, entre outras regras vão te ajudar nisso. Veja abaixo.

Seja consistente

A consistência na aplicação do código é fundamental. Caso queira seguir um padrão, mantenha-o em todo o projeto. Isso facilita a leitura e a manutenção do código.

Evite:

int dias;  // Nome genérico

int quantidadeDiasNoAno = 365;

Recomendado:

int diasNoAno = 365;

int diasNoMes = 30;

Utilize variáveis concisas

Variáveis devem ser autoexplicativas, evitando a necessidade de comentários adicionais. Escolha nomes que descrevam claramente o propósito da variável. Por exemplo:

// Total do que?

decimal total = 0;

// Total do carrinho de compras

decimal shoppingCartTotal = 0;

Obsessão primitiva

Não foque apenas em tipos primitivos (Built-in). Utilize objetos de valor (Value Objects) para representar conceitos mais complexos e melhorar a clareza do código.

Evite:

public class Pedido

{

    public string EnderecoEntrega { get; set; }

}

Recomendado:

public class Endereco

{

    public string Rua { get; set; }

    public string Cidade { get; set; }

    public string Estado { get; set; }

}

public class Pedido

{

    public Endereco EnderecoEntrega { get; set; }

}

Evite dependências lógicas

Métodos não devem depender de condições específicas de sua classe para funcionar corretamente. Isso pode levar a comportamentos inesperados e dificultar a manutenção.

Evite:

public class Usuario

{

    public bool Logado;

    public void AcessarSistema()

    {

        if (Logado)

        {

            Console.WriteLine(“Acesso permitido”);

        }

    }

}

Recomendado:

public class Usuario

{

    public bool Logado { get; private set; }

    public void Login()

    {

        Logado = true;

    }

}

Evite condicionais negativas

Condicionais negativas podem dificultar a leitura do código. Prefira condições positivas para melhorar a clareza. 

Evite:

if(!IsSubscriber) { … }

Utilize: 

if(IsSubscriber) { … }

Regras de nomes

Escolha nomes descritivos e significativos para garantir a clareza e a manutenção do código. Nomes bem escolhidos reduzem a necessidade de explicações adicionais e facilitam a compreensão do que o código faz. 

Confira algumas dicas para esta que é uma das práticas mais importantes.

Escolha nomes descritivos

Nomes de classes, variáveis e métodos devem ser claros e expressivos. Se você precisa explicar o que um nome representa, significa que você pode melhorá-lo.

Evite:

var y = 100;

// Altura do que? Em qual unidade?

int height = 10;

// Muito mais expressivo

int heightInCentimeters = 10;

Faça distinções significantes

Nomes devem ser distintos o suficiente para que seu significado seja claro e não se confunda com outros nomes no código.

Evite:

var valor = 1500M;

// Tem um significado maior

var valorEmDolares = 1500M;

Utilize nomes com fácil busca e pronúncia

Evite nomes com pronúncia difícil ou criar convenções que não sejam intuitivas. Nomes claros e fáceis de buscar ajudam na manutenção do código.

Evite:

var xptoVar = “valor”;

Recomendado:

var nomeCliente = “João”;

Evite o excesso de strings

O uso repetido de strings pode levar a erros difíceis de detectar. Utilize constantes para não se deparar com problemas de comparação e não desperdiçar tempo buscando um bug.

Evite:

if (status == “ATIVO”) { … }

Recomendado:

public class Status

{

    public const string Ativo = “ATIVO”;

}

if (status == Status.Ativo) { … }

Não use prefixo ou caracteres especiais

Evite prefixos que indicam o tipo da variável, método ou classe. Além disso, nunca utilize espaços ou caracteres especiais em nomes.

Evite:

public class clsCustomer { … }

Evite:

string strNome = “José”;

Evite:

var situação – “Pendente”;

Regras para funções ou métodos

Regras como expressividade, coerência e códigos não comentados, são importantes para garantir que suas funções sejam eficientes e fáceis de entender.

Pequenas e com objetivo único

Métodos devem ser pequenos e focados em uma única tarefa. Isso facilita a reutilização e a compreensão do código.

Evite:

public void ProcessarPedido()

{

    ValidarCliente();

    CalcularFrete();

    GerarFatura();

}

Recomendado:

public void ValidarCliente() { … }

public void CalcularFrete() { … }

public void GerarFatura() { … }

Utilize nomes descritivos

Nomes de métodos devem ser claros e descritivos, refletindo exatamente o que o método faz, sem usar caracteres especiais.

Evite:

// O que esse método faz?

public void Calcular() { … }

Utilize:

// Calcula o valor do frete

public void CalcularFrete() { … }

Utilize poucos parâmetros

Tente não exigir muitas coisas de um mesmo objeto. Utilize objetos ou parâmetros opcionais para simplificar a assinatura do método como o Optional Parameters do C#.

Evite:

public void CriarPedido(string produto, int quantidade, double preco, string cliente)

Recomendado:

public void CriarPedido(Pedido pedido)

Tenha cuidado com efeitos colaterais

Se uma função alterar valores de outra classe sem ser a dela, isto vai gerar um efeito colateral.

Evite:

public void AplicarDesconto(Pedido pedido)

{

    pedido.Valor -= 10;

}

Recomendado:

public class Pedido

{

    public decimal Valor { get; private set; }

    public void AplicarDesconto(decimal desconto)

    {

        Valor -= desconto;

    }

}

Não tome decisões desnecessárias

Evite o uso de “flags” para tomar decisões dentro de métodos. Divida a lógica em métodos separados ou outras classes.

Evite:

public void Processar(bool isPagamentoCredito)

{

    if (isPagamentoCredito)

        ProcessarCartao();

    else

        ProcessarBoleto();

}

Recomendado:

public void ProcessarCartao() { … }

public void ProcessarBoleto() { … }

Regras de comentários

Comentários podem ser úteis, mas seu uso deve ser criterioso para evitar redundâncias e poluição no código. Não ser redundante, não fechar comentários, colocar intenção e esclarecimento, são parte das regras que guiam o uso adequado de comentários. Veja a seguir.

Um código bom é expressivo

Em teoria, quando é preciso comentar uma parte do código, é porque ele não está claro o suficiente. 

// Função que inicia o sistema

public void IniciarSistema() { … }

Não seja redundante

Se um comentário não faz sentido para o contexto ou cenário, evite colocá-lo.

// Verifica se o usuário está logado

if (usuario.Logado) { … }

Não feche os comentários

Fechar comentários com barras ou outros caracteres é desnecessário e polui o código.

// Este é um comentário // <- Fechamento desnecessário

public void ProcessarDados() { … }

Evite códigos comentados

Códigos comentados podem ser confusos e dificultam a leitura, para deixar o código limpo e organizado, remova estes trechos. Caso você precise recuperar códigos antigos, utilize versionadores de código.

Intenção

Comentários podem ser úteis para explicar a intenção por trás de um método, classe ou variáveis.

// Retorna os usuários inativos para o processo de limpeza mensal

public IList<Usuario> ObterUsuariosInativos() 

    …

}

Esclarecimento

Outro bom uso de comentários é para fornecer esclarecimentos sobre decisões específicas no código.

public void FinalizarCompra() 

    // Verifica se o estoque foi atualizado antes de finalizar

    if (estoque.Atualizado)

    {

        ConcluirPedido();

    }

}

Consequências

Comentários podem servir como aviso sobre possíveis consequências de trechos de código, especialmente em operações críticas. Nesses casos, é recomendado o uso de comentários em XML.

/// <summary>

/// ATENÇÃO: Este método remove o usuário e todos os dados associados

/// </summary>

public void RemoverUsuario() 

    …

}

Estrutura do código

Entre as práticas recomendadas para estruturar um código estão: a separação de conceitos de forma vertical, agrupar funcionalidades similares, declarar funções de cima para baixo, manter poucas linhas, entre outros. Veja abaixo.

Separe conceitos verticalmente

Uma estrutura de pastas bem organizada ajuda a separar contextos e funcionalidades, evitando confusão e facilitando a navegação no projeto.

Exemplo:

/Controllers

/Services

/Repositories

/Models

Declare variáveis próximas de seu uso

Declare variáveis próximas de onde serão utilizadas, evitando criar variáveis no início de uma classe ou método. 

Evite:

var total = 0;

public void CriarCliente() { … }

public void CriarPedido() { … }

public void AtualizarCliente() { … }

public void CalcularTotal() 

    total = 500; // <- Só é utilizada aqui

}

Exemplo recomendado:

public void CriarCliente() { … }

public void CriarPedido() { … }

public void AtualizarCliente() { … }

var total = 0;

public void CalcularTotal() 

    total = 500;

}

Agrupe funcionalidades semelhantes

Funções que pertencem ao mesmo grupo ou contexto devem ser mantidas próximas umas das outras.

Evite:

public void CriarCliente() { … } 

public void VerificarEstoque() { … }

public void CriarPedido() { … }

public void AtualizarCliente() { … }

public void CalcularTotal() { … }

Exemplo recomendado:

public void CriarCliente() { … } 

public void AtualizarCliente() { … }

public void VerificarEstoque() { … }

public void CriarPedido() { … }

public void CalcularTotal() { … }

Declare funções de cima para baixo

Organize as funções em uma ordem lógica, preferencialmente de cima para baixo, seguindo uma hierarquia de complexidade ou uso. Por exemplo:

public void CriarCliente(string nome) { … } 

public void CriarCliente(string nome, int idade) { … } 

public void CriarCliente(string nome, int idade, Endereco endereco) { … } 

public void CriarCliente(string nome, int idade, Endereco endereco, bool ativo) { … } 

Mantenha poucas e curtas linhas

Funções com muitas linhas ou linhas muito longas são difíceis de ler e manter. Priorize funções curtas e objetivas. 

public void CriarCliente(string nome) 

    var cliente = new Cliente(nome);

    _repositorio.Clientes.Add(cliente);

    _repositorio.SaveChanges();

}

Não use alinhamento horizontal

Alinhar variáveis, constantes ou propriedades horizontalmente não é necessário e pode dificultar a leitura.

private   Long            tempoLimiteProcessamento;

protected Pedido          pedido;

private   Contexto         contexto;

this.contexto =            contexto;

entrada =                  stream.getInputStream()

tempoLimiteProcessamento = 1000;

Use os espaços em branco corretamente

Utilize espaços em branco para separar ou agrupar itens relacionados, melhorando a legibilidade do código.

Exemplo recomendado:

private void MeuMetodo(string parametro) {

  variavel++;

  int outraVariavel = algumArray.Length();

  total += algumMetodo();

  outraClasse.OutroMetodo(variavel, total);

  outroMetodo(total);

}

Não quebre a identação

A identação é fundamental para a legibilidade do código. Um código sem identação adequada não deve ser enviado para o projeto.

Evite:

public class MinhaClasse{

var valor=12;

Console.WriteLine(valor);

}

Recomendado:

public class MinhaClasse 

{

    var valor = 12;

    Console.WriteLine(valor);

}

Objetos e estruturas

As práticas recomendadas para o desenvolvimento de objetos e estruturas incluem o uso de estrutura de dados, esconder estruturas internas e não utilizar dados e objetos juntos. Confira.

Esconda estruturas internas

Manter a estrutura interna de um objeto oculta é uma boa prática para garantir o encapsulamento e evitar que dados sejam manipulados de forma inadequada. Isso pode ser feito tornando propriedades privadas e expondo apenas métodos para manipulação.

Evite:

public class Usuario

{

    public string Senha;

}

Recomendado:

public class Usuario

{

    private string _senha;

    public void DefinirSenha(string senha)

    {

        _senha = Criptografar(senha);

    }

}

Opte por estrutura de dados

A estrutura de dados diz respeito a como os dados são organizados, variando entre classes e structs.

Geralmente os structs são mais leves e adequados para dados simples, enquanto classes oferecem mais recursos como herança, polimorfismo, entre outros.

Exemplo com struct:

public struct PhoneNumber 

{

    public PhoneNumber(string number) 

    { 

        // Validação do número

    }

    public string Number { get; private set; }

}

public class Customer

{

    public PhoneNumber ContactNumber { get; private set; }

}

Exemplo com classe:

public class PhoneNumber 

{

    public PhoneNumber(string number) 

    { 

        // Validação do número

    }

    public string Number { get; private set; }

}

public class InternationalPhoneNumber : PhoneNumber

{

    public InternationalPhoneNumber(string number) 

        : base(number)

    { 

        // Validação adicional para números internacionais

    }        

}

public class Customer

{

    public PhoneNumber ContactNumber { get; private set; }

Instanciar poucas variáveis

Evite criar variáveis desnecessárias dentro de métodos ou objetos. Priorize o uso de propriedades para reduzir a complexidade.

Evite:

public void Processar()

{

    int resultado;

    resultado = Calcular();

}

Recomendado:

public void Processar()

{

    int resultado = Calcular();

}

Classe base não deve saber sobre suas derivadas

Uma classe base não deve ter conhecimento sobre suas classes derivadas. Isso viola o princípio de encapsulamento e pode levar a um acoplamento desnecessário.

Exemplo:

// N/A (Não há cenário válido para uma classe base saber sobre suas derivadas)

Mais métodos, menos tomadas de decisão

Prefira criar mais métodos do que aumentar a quantidade de tomadas de decisão dentro do código. Por exemplo:

Evite:

public class Order

{

    public void ProcessPayment(PaymentMethod method)

    {

        if(method == PaymentMethod.CreditCard)

            // Processar cartão de crédito

        else

            // Processar boleto

    }

}

Exemplo recomendado:

public class Order

{

    public void ProcessCreditCardPayment() 

    {

        // Processar cartão de crédito

    }

    public void ProcessBankSlipPayment() 

    {

        // Processar boleto

    }

}

Evite métodos estáticos

Métodos e classes estáticos podem ser difíceis de gerenciar e testar, além de serem compartilhados entre a aplicação integralmente. Prefira instâncias de classes para manter o controle sobre o estado.

Evite:

public static class Logger

{

    public static void Log(string message) 

    {

        // Registrar mensagem

    }

}

Exemplo recomendado:

public class Logger

{

    public void Log(string message) 

    {

        // Registrar mensagem

    }

}

Dicas para testes

Confira agora algumas dicas práticas para escrever testes eficientes e de fácil manutenção.

Um assert por teste

É recomendável utilizar apenas um assert por teste. Ter mais de um assert pode causar confusão e dificultar a escrita do teste.

Evite:

[TestMethod]

public void ShouldReturnTrue 

{

    Assert.AreEqual(true);

    Assert.AreEqual(1);

}

Exemplo recomendado:

[TestMethod]

public void ShouldReturnTrue 

{

    Assert.AreEqual(true);

}

Legível

Os testes devem ser tratados como parte fundamental do código, e não como algo secundário. Eles precisam ser organizados e bem escritos, assim como o restante do software.

Rápido

Um dos principais objetivos de um teste é cobrir uma pequena parte do código. No entanto, é comum estender essa ideia para a maior parte do código possível, resultando em uma grande quantidade de testes de unidade.

Esses testes são executados antes da publicação das aplicações, garantindo que nada com bugs seja enviado para produção. Em cenários críticos, o tempo de deploy é crucial, e testes lentos podem impactar negativamente esse processo.

Independentes

Os testes não devem depender de entidades externas ou de outros testes. O uso de Injeção de Dependência (DI) e Princípio da Inversão de Dependência (DIP) é fundamental para garantir essa autonomia.

Repetível

Devemos ser capazes de repetir o mesmo teste com parâmetros diferentes, garantindo que ele funcione em diversos cenários.

Dicas sobre Code Smells

Quando o Clean Code não é bem aplicado, alguns indicativos aparecem sugerindo problemas na qualidade do código. Conhecido como Code Smells, estes indícios são:

  • Rigidez: Quando o software é difícil de modificar, qualquer alteração, mesmo que pequena, desencadeia uma série de outras mudanças;
  • Fragilidade: Mesmo uma pequena mudança quebra o software em diversos locais;
  • Imobilidade: Dificuldade em reutilizar partes do código em outros projetos por estar acoplado;
  • Complexidade desnecessária: Uso excessivo de padrões e arquiteturas que tornam o código mais burocrático do que funcional.
  • Repetição desnecessária: O mesmo código é repetido em vários lugares, indicando falta de modularização;
  • Opacidade: O código é difícil de entender, prejudicando a manutenção e a clareza.

Simplifique sua gestão de documentos fiscais com a Focus NFe

Somos um ecossistema de soluções para a emissão e gestão de documentos fiscais. Nossos recursos permitem que empresas dos mais diversos portes e segmentos ganhem mais tempo para focar no que importa.

Sua empresa possui desenvolvedores, sistema interno e quer otimizar a emissão de notas? Teste gratuitamente e conheça nosso conjunto de APIs para emissão de documentos fiscais!

Ou converse já com a nossa equipe e saiba como podemos ajudar o seu negócio!

Inscreva-se em nossa newsletter​

Receba nossos conteúdos exclusivos em primeira mão.

Explore outros conteúdos:

nfce
Documentos fiscais
Egon Hilgenstieler

NFC-e: o que é, como funciona, vantagens e como emitir?

A Nota Fiscal do Consumidor Eletrônica (NFC-e) é um documento que precisa ser emitido por praticamente qualquer empresa que comercializa produtos e serviços, com exceções como os Microempreendedores Individuais (MEIs). Porém, as regras de obrigatoriedade de emissão deste documento não são as mesmas nos estados brasileiros, gerando diversas dúvidas para quem trabalha com varejo.

Por isso, no texto a seguir, explicamos tudo sobre o documento que tem o propósito de substituir um modelo impresso por um digital, as vantagens que ele oferece e regras para a emissão.

Porém, as regras de obrigatoriedade de emissão deste documento não são as mesmas nos estados brasileiros, acarretando diversas dúvidas por parte das pessoas varejistas.

Por isso, no texto a seguir, explicamos tudo sobre o documento que tem o propósito de substituir um modelo impresso por um digital, as vantagens que ele oferece e regras para a emissão.

Leia mais »
API para SAT: o que é, para que serve e como consultar?
Tecnologia e API
Cesar Nocrato

API para SAT: o que é, para que serve e como consultar?

A API para SAT foi desenvolvida para facilitar a comunicação entre sistemas de gestão e o Sistema Autenticador e Transmissor de Cupons Fiscais eletrônicos (CF-e SAT) em São Paulo. Essa interface permite a emissão, autenticação e envio de cupons fiscais de forma automatizada, garantindo conformidade com a legislação tributária vigente.

Com a descontinuação do SAT a partir de 2026, entender como se adaptar às novas regras é essencial para empresas que ainda utilizam esse modelo. Hoje vamos falar mais sobre esta API, assim como as informações essenciais para fazer uma boa transição.

Acompanhe!

Leia mais »
Entenda o que é NCM e o que significa cada número do código. Aprenda também a consultar e definir o NCM de seus produtos!
Contabilidade
Jaciara Santana

O que é NCM? Confira como consultar e tabela atualizada!

Saber o que é NCM é essencial para as empresas envolvidas em transações comerciais internacionais, tanto para importação quanto exportação. Isso porque a utilização da NCM é obrigatória em notas fiscais eletrônicas, tornando-se indispensável para documentos comerciais.

Este sistema de codificação, adotado em janeiro de 1995 pelos países membros do Mercosul, segue critérios internacionais de classificação de mercadorias. Acompanhe o artigo de hoje e saiba o que é NCM, sua função, como determiná-lo e qual é a sua importância.

Este sistema de codificação, adotado em janeiro de 1995 pelos países membros do Mercosul, segue critérios internacionais de classificação de mercadorias.

Acompanhe o artigo de hoje e saiba o que é NCM, sua função, como determiná-lo e qual é a sua importância.

Leia mais »