O Que São Propriedades - O Que São Propriedades Químicas - GITEDU
O Que São Propriedades Químicas - GITEDU

Entendendo propriedades em programação prática

Muita gente confunde propriedades com variáveis normais quando começa a programar em orientação a objetos. O resultado costuma ser código bagunçado que quebra quando alguém tenta estender uma classe que parecia simples no começo. A diferença real entre os dois é que uma propriedade permite executar lógica toda vez que um valor é lido ou modificado, enquanto uma variável exposta faz exatamente o quê você vê — nada a mais, nada a menos.

O que são propriedades e como funcionam de verdade

Uma propriedade é um membro de classe que encapsula um campo privado por trás de dois métodos: getter e setter. Quando você acessa algo como objeto.idade, na verdade está chamando o getter. Quando faz objeto.idade = 25, o setter entra em ação. Isso parece óbvio na teoria, mas a parte que ninguém conta nos tutoriais é que o uso indiscriminado de propriedades com lógica pesada dentro do getter pode transformar seu código em uma mina terrestre de efeitos colaterais inesperados. No C#, a sintaxe moderna ficou bem limpa com auto-properties: public int Id { get; set; }. O compilador gera o backing field automaticamente. Mas assim que você precisa adicionar validação no setter ou computar um valor no getter, precisa voltar ao formato completo com campo privado. Isso acontece o tempo todo em projetos reais. Eu já passei por isso num sistema de estoque onde a propriedade PrecoUnitario deveria aplicar um desconto baseado no volume, mas o desconto só fazia sentido se o produto estivesse em promoção ativa. O problema era que o setter precisava acessar outra propriedade da mesma classe, o que criava um ciclo de dependência se eu não estruturasse direito.

A solução que eu encontrei foi separar a responsabilidade. Criei um método CalcularPrecoComDesconto() que o getter consultava, e esse método só era chamado quando o contexto de promoção estava definido. O setter continuava simples, apenas atribuindo o valor bruto ao campo privado. Dessa forma, a validação e o cálculo ficam isolados e você evita efeitos colaterais. No JavaScript, a coisa é diferente. As propriedades clássicas são apenas pares chave-valor em objetos. A funcionalidade de getter e setter foi introduzida com a sintaxe get e set no ECMAScript 2015. Funciona assim:

var pessoa = {
  _nome: "João",
  get nome() { return this._nome; },
  set nome(value) { this._nome = value.toUpperCase(); }
}; O detalhe importante aqui é que o underscore no campo privado é apenas uma convenção. O JavaScript não impõe privacidade real nessas propriedades. Se alguém fizer pessoa._nome = "teste", o setter nem é acionado. Isso mata a validação que você pensava estar implementando.

👉 Clique no botão abaixo para saber mais sobre o assunto!

Uma armadilha comum em JavaScript é esquecer que getters e setters são invocados automaticamente em operações como Object.getOwnPropertyDescriptor() e loop com for...in. Eu perdi umas três horas num debugging session porque um getter estava sendo invocado durante uma iteração de objeto e lançando exceção silenciosamente. A exceção não aparecia no stack trace original porque vinha de dentro do loop. No Python, a abordagem é ainda mais flexível com o decorador @property. Você define um método normal e o decora, e ele vira uma propriedade. O grande poder disso é que você pode ter o mesmo nome para getter, setter e deleter, o que mantém a API limpa. Mas o custo é que qualquer pessoa que herda sua classe e sobrescreve essa propriedade precisa lembrar de usar os três decorators, senão o setter simplesmente some.

Aqui vai um insight que poucos explicam: propriedades computadas não são gratuitas. Em frameworks reativos como Vue.js ou Solid.js, o sistema de tracking de reatividade depende inteiramente de você acessar as dependências dentro do getter. Se você fizer um cálculo pesado e esquecer de expor alguma dependência que mudará depois, o reactive system não vai invalidar o cache corretamente. O resultado é um valor obsoleto que persiste até a próxima renderização completa, o que em aplicações grandes pode significar dezenas de segundos de lag visível. O outro ponto que as pessoas ignoram é a performance em hot paths. Ler uma propriedade em .NET com validação síncrona no getter é cerca de 3 a 5 vezes mais lento do que acessar um campo público direto. Não é muito em termos absolutos — talvez uns 50 nanossegundos por acesso — mas se você estiver lendo essa propriedade dentro de um loop que roda milhões de vezes, a diferença vira segundos reais. Eu vi isso acontecer num microserviço de processamento de pagamentos que usava Dapper. A query retornava linhas e cada propriedade mapeada tinha um getter com formatação de data. O throughput despencou de 15 mil requests por segundo para cerca de 4 mil. A correção foi usar campos públicos ao invés de propriedades no DTO, já que o mapeamento era feito pelo Dapper mesmo.

Existem cenários onde propriedades simplesmente não fazem sentido. Se você está construindo uma estrutura de dados pura para transferência, como um DTO ou ViewModel, e não precisa de validação, log ou computação, use campos públicos ou init-only properties. Propriedades com lógica complexa dentro de DTOs são um sintoma de responsabilidade mal distribuída — a validação pertence ao service layer, não ao modelo de dados. Outra limitação prática: em alguns linguagens e frameworks, serializadores JSON não chamam setters automaticamente. O Newtonsoft.Json no .NET respeita setters personalizados, mas o System.Text.Json, por padrão, usa reflection direta nos campos privados gerados pelo auto-property. Se você trocar de serializador e tiver lógica no setter, ela vai parar de executar sem aviso algum. Eu perdi um dia inteiro descobrindo que migrei de um para o outro e os dados estavam sendo recebidos errados porque um campo que tinha validação no setter simplesmente estava sendo populado sem nenhuma verificação.

A recomendação prática que dá certo na maioria dos casos é: mantenha propriedades simples para dados puramente transitórios, coloque toda a lógica de negócio em métodos explícitos com nomes que deixam claro o que estão fazendo, e use propriedades apenas quando o getter ou setter realmente precisa interceptar a leitura ou escrita. Isso não é uma regra absoluta, é uma heurística que evita que seu código vire um quebra-cabeça quando alguém tentar dar manutenção meses depois.