Obsessão por tipos primitivos

Esta publicação está disponível em vídeo, ampliada e revisada, no canal da EximiaCo.


Com frequência, em nossas consultorias, encontramos códigos que fazem uso excessivo de tipos primitivos.

public class Employee
{
  public string Id { get; set; }
  public string Name { get; set; }
  public string Cpf { get; set; }
  public decimal Salary { get; set; }
}

No exemplo acima, usou-se string para representar pelo menos três tipos diferentes de dados. Essa abordagem “anêmica” acaba criando dificuldades, por exemplo, para implantação de validações.

public class Employee
{
  public string Id { get; set; }
  public string Name { get; set; }
  
  string _cpf;
  public string Cpf 
  { 
    get
    {
      return _cpf;
    } 
    set
    {
      // .. validation Logic
      _cpf = value;
    } 
  }
  public decimal Salary { get; set; }
}

Uma saída ingênua comum é implantar o código de validação nos Setters das propriedades. O problema, é que essa abordagem leva a duplicação de código e repetição desnecessária de testes.

public class Employee
{
  public string Id { get; set; }
  public string Name { get; set; }
  
  string _cpf;
  public string Cpf 
  { 
    get
    {
      return _cpf;
    } 
    set
    {
      if (Utils.CheckCpf(value))
      {
        throw new ArgumentException(“...”);
      }
      _cpf = value;
    } 
  }
  public decimal Salary { get; set; }
}

Como aprimoramento da solução, muitos times acabam desenvolvendo bibliotecas de uso comum (com nomes criativos como Comum, Utils, …). Entretanto, é importante observar que essas bibliotecas acabam se afastando do paradigma orientado a objetos.

Nossa recomendação é desenvolver um sistema de tipos mais rico que se afaste das primitivas.

public struct Cpf
{
  private readonly string _value; 
  
  private Cpf(string _value) { _value = value; }

  public static Cpf Parse(string value)
  {
    if (TryParse(value, out var result))
    {
      return result;
    }
    throw new ArgumentException(...);
  }

  public static bool TryParse(string value, out Cpf cpf)
  {
    //.. validation Logic 
  }

  public static implicit operator Cpf(string value)
    => Parse(value);
}

Esse tipo, por estar implementado como struct, tem custo mínimo para o runtime. Além disso, torna as implementações que o utilizam mais limpas (por não ter de explicitar a validação) e mais expressivas (pelo tipo do dado).

Observe, também, que o conversor implícito mantem esse tipo compatível com a primitiva mais próxima (no caso, string).

Seus projetos fazem uso obsessivo dos tipos primitivos? O que acha da abordagem que estamos propondo?

Compartilhe este insight:

Comentários

Participe deixando seu comentário sobre este artigo a seguir:

Subscribe
Notify of
guest
5 Comentários
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Ermerson Rafael
Ermerson Rafael
4 anos atrás

Parabéns pelo Post! Conteúdo incrível.

Muitas vezes achamos que sabemos tudo e que não podemos mais nos surpreender.
São pequenos detalhes como esse que fazem muita diferença.

Tiago Crizanto
Tiago Crizanto
4 anos atrás

Achei interessante a abordagem. E como fica a implementação da classe CPF na classe Employee? E se esta classe fosse uma classe de domínio no EF?

Marcos
Marcos
4 anos atrás

Elemar.
Gostei muito da implementação, mas tenho uma duvida. A muito tempo atrás fiz um sistema que necessitava de muita performance e optei por utilizar structs, e por serem “value type” eu tive problemas quando precisa que fosse tratadas como “reference type” (não sei se me entendeu). Num sistema multi thread esse tipo de implementação não dispenderia muito tempo de desenvolvimento pensando no fato que eu teria que tratar a aplicação toda como value type? E o fato de que os métodos são static’s não acarretaria em race condition num sistema multi thread?
Em resumo eu aprecio muito esse tipo te implementação.
Obrigado por compartilhar.

Luiz
Luiz
3 anos atrás

Ótima consideração, Elemar! Gosto da abordagem proposta. Coincidentemente, estou utilizando bastante em meu atual projeto.

Fiquei com uma dúvida, no entanto.

O implicit operator do exemplo lança, ainda que indiretamente, uma exceção.
A documentação afirma que: “Predefined C# implicit conversions always succeed and never throw an exception. User-defined implicit conversions should behave in that way as well.” [https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/user-defined-conversion-operators]
A abordagem estaria de acordo utilizando-se um explicit operator.

Seria muito ruim chamar o método Parse já no construtor?
Sei que também não é muito indicado, mas no caso de um tipo, meu raciocínio é o seguinte: “se essa string _value não representar um CPF válido, nem continuamos a conversa”.

Muito obrigado por compartilhar conteúdo de qualidade e inspirador!

Rafael
Rafael
1 ano atrás
Reply to  Luiz

Nesse caso tu poderia usar uma static factory ao invés do construtor e validar antes de criar o objeto de fato. 🙂

AUTOR

Elemar Júnior
Fundador e CEO da EximiaCo atua como tech trusted advisor ajudando empresas e profissionais a gerar mais resultados através da tecnologia.

NOVOS HORIZONTES PARA O SEU NEGÓCIO

Nosso time está preparado para superar junto com você grandes desafios tecnológicos.

Entre em contato e vamos juntos utilizar a tecnologia do jeito certo para gerar mais resultados.

Insights EximiaCo

Confira os conteúdos de negócios e tecnologia desenvolvidos pelos nossos consultores:

Arquivo

Pós-pandemia, trabalho remoto e a retenção dos profissionais de TI

CTO Consulting e Especialista em Execução em TI
5
0
Queremos saber a sua opinião, deixe seu comentáriox
Oferta de pré-venda!

Mentoria em
Arquitetura de Software

Práticas, padrões & técnicas para Arquitetura de Software, de maneira efetiva, com base em cenários reais para profissionais envolvidos no projeto e implantação de software.

Muito obrigado!

Deu tudo certo com seu envio!
Logo entraremos em contato

Obsessão por tipos primitivos

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

Obsessão por tipos primitivos

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

Condição especial de pré-venda: R$ 14.000,00 - contratando a mentoria até até 31/01/2023 e R$ 15.000,00 - contratando a mentoria a partir de 01/02/2023, em até 12x com taxas.

Tenho interesse nessa capacitação

Para solicitar mais informações sobre essa capacitação para a sua empresa, preencha o formulário a seguir:

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

O seu insight foi excluído com sucesso!

O seu insight foi excluído e não está mais disponível.

O seu insight foi salvo com sucesso!

Ele está na fila de espera, aguardando ser revisado para ter sua publicação programada.

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse nessa solução

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse neste serviço

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

× Precisa de ajuda?