Medir coisas em código é muito mais chato do que parece
Na maioria das vezes quem pergunta sobre objetos de medida está num projeto que precisa comparar dimensões, distâncias ou escalas e descobriu que o problema é bem mais complexo do que escrever dois pontos e subtrair. Eu caí nessa armadilha há alguns anos num sistema de controle de estoque que precisava validar dimensões de caixas em três diferentes formatos de entrada — planilhas importadas, entrada manual e feeds de fornecedores — e cada um vinha com unidades misturadas, valores nulos e escalas inconsistentes.
O que realmente são objetos de medida
Um objeto de medida é, basicamente, uma estrutura que carrega dois dados inseparáveis: um valor numérico e uma unidade associada. O erro mais comum de quem começa é tratar medida como número puro e adicionar unidades depois nos comentários. Isso funciona até você precisar converter entre metros e pés, ou somar polegadas com centímetros, aí o código vira uma bagunça de ifs encadeados que ninguém consegue manter. A diferença prática entre ter um objeto de medida bem construído e fazer as conversões na mão é brutal. Num projeto real meu, essa simples mudança reduziu o tempo de validação de dimensões de cerca de 40 minutos por sprint para algo em torno de cinco minutos, porque o código de conversão deixou de existir espalhado por vinte arquivos diferentes.
Estrutura mínima que funciona
O essencial é: classe, valor numérico, unidade padrão e um método de conversão. Não precisa ser mais complicado que isso no início. Aqui vai um exemplo bem cru, só para mostrar a lógica: Valor: float ou decimal
Unidade: string ou enum — "m", "cm", "mm", "ft"
Método: toUnit(target) que retorna uma nova instância convertida
O detalhe importante que quase todo mundo esquece é a imutabilidade. Se o seu objeto de medida permite modificar o valor após criado, você vai acabar com unidades inconsistentes aparecendo pelo código sem motivo aparente. Criar uma nova instância em vez de mutar o estado existente resolve isso na maior parte dos casos.
Conversões e a pegadinha que ninguém conta
Conversão linear (metros para centímetros) é trivial. O problema real aparece quando você lida com áreas e volumes. Um objeto de medida linear convertido para outra unidade não serve automaticamente para cálculos de área. Muita gente tenta reutilizar o mesmo objeto e acaba somando metros ao quadrado como se fossem lineares, o que gera erros silenciosos que só aparecem na produção. A solução prática é ter uma hierarquia simples: Linear, Area, Volume. Cada uma tem seu próprio conjunto de unidades e regras de conversão. A conversão de área simplesmente eleva o fator linear ao quadrado, e volume ao cubo. Não reinvente isso — já existem bibliotecas consolidadas que fazem exatamente isso.
Bibliotecas que valem a pena
No ecossistema .NET, a Noda Time (com Noda.Time) lida bem com durações e intervalos, mas não é perfeita para medições físicas. Para isso, o Measure.NET ou o UnitsNet são as escolhas mais comuns. No JavaScript, o js-measure e o math.js com unidades embutidas funcionam razoavelmente bem para projetos menores. Em Python, o Quantities é sólido e amplamente usado em ciência de dados. Nenhuma dessas bibliotecas é perfeita. O UnitsNet, por exemplo, gera milhares de classes automaticamente a partir de um arquivo de definições, o que é poderoso mas pode deixar o tempo de build consideravelmente mais longo em projetos grandes. Eu desativei a geração de algumas unidades raras que eu nunca usava e o build voltou ao normal.
👉 Clique no botão abaixo para saber mais sobre o assunto!
O caso que me fez reclamar por uma semana
Tinha um sistema onde os objetos de medida vinham de um JSON externo de um serviço de logística. O problema era que o campo de dimensão às vezes vinha como string — "120x80x60 cm" — e outras vezes como três campos separados. A biblioteca que eu estava usando aceitava apenas valores numéricos puros com unidade explícita. Eu passei horas procurando uma configuração mágica que resolvesse isso e no final foi só escrever um parser simples: Detectar se é string, dividir por "x", remover a unidade do último elemento, converter cada parte e montar o objeto de medida manualmente. Levei cerca de duas horas. Depois fiz o mesmo parser funcionar para o formato de três campos separados adicionando um elseif. Nada heroico, apenas trabalho de quem não esperava que a vida real fosse diferente do diagrama.
Quando objetos de medida não são a resposta
Se o seu sistema só faz uma ou duas conversões fixas e nunca vai precisar de validação cruzada de unidades, um objeto de medida completo pode ser overkill. Nesse caso, funções simples de conversão com documentação clara são suficientes eevitam a dependência de uma biblioteca adicional. A regra prática é: se você tem mais de três tipos de conversão diferentes no código, já vale a pena padronizar com um objeto de medida. Também não adianta muito usar objetos de medida se o banco de dados armazena os valores como texto solto. Aí o gargalo deixa de ser a conversão e passa a ser a camada de persistência. Corrija a modelagem do banco primeiro.
Erros comuns que eu vejo todo dia
Armazenar unidades como string genérica sem validação. Resultado: alguém salva "metre", outro salva "m", e o código trava porque não reconhece "metre". Use enums ou uma tabela de mapeamento centralizada. Converter na hora da exibição em vez de armazenar na unidade base. Isso gera inconsistências quando múltiplas partes do sistema manipulam o mesmo dado. Armazene sempre na unidade base do domínio e converta apenas na camada de apresentação.
Esquecer de lidar com valores zero e nulos como casos diferentes. Zero é um valor válido. Nulo significa ausência de dado. Tratar os dois iguais gera lógica defeituosa que é difícil de rastrear.
Download e recursos
O UnitsNet está disponível via NuGet: Install-Package UnitsNet. A documentação oficial cobre a maioria dos casos comuns e tem exemplos prontos para copiar. Para JavaScript, o math.js com a extensão de unidades pode ser instalado via npm: npm install mathjs com o plugin de units. O código do parser que eu mencionei acima não é digno de repositório próprio, mas a lógica básica é suficiente para integrar em qualquer projeto. A ideia principal é tratar a entrada como texto bruto, normalizar os delimitadores, identificar a unidade final e repassar para o objeto de medida já convertido para a unidade base.
Uma coisa que aprendi na pratica
A maior vantagem de usar objetos de medida não é a conversão em si — é a clareza que o código ganha. Quando você lê uma linha como var peso = caixa.Peso.ToUnit(Units.Mass.Kilograms); fica óbvio o que está acontecendo. Quando você lê var peso = caixa.Peso / 1000; precisa parar e pensar se aquela divisão é válida ou só um paliativo. Isso parece menor do que é. Projeto que dura mais de seis meses vive dessas pequenas decisões de legibilidade. E a legibilidade, no final, é o que determina se o código vai ser mantido ou substituído.