Imutabilidade: Você sabe o que é?

Imutabilidade, de forma geral, é a característica ou qualidade de algo não se alterar. Em programação orientada a objetos, por exemplo, uma vez que um objeto imutável é criado/instanciado, o mesmo não poderá sofrer alterações no seu estado até o final da sua vida. A imutabilidade em objetos pode ainda ser total ou parcial. Uma forma fácil de perceber a imutabilidade é o exemplo do cachorro.

Um cachorro nasce cachorro, e permanecerá cachorro até o final da sua vida. Um cachorro uma vez “criado”, nunca poderá se transformar em outro animal, como uma galinha por exemplo. Esse mesmo conceito se aplica aos objetos imutáveis em memória utilizados pelas linguagens de programação.

O conceito de imutabilidade pode parecer estranho no início, pois de que serve um programa que contém objetos estáticos que não podem mudar? Nesse caso a resposta é: Apesar de não ser possível mudar um objeto imutável, é possível transformá-lo em um novo objeto.

Sempre que o estado de um objeto ou valor necessitar ser alterado, um novo objeto é criado em memória e a “variável” que representa o objeto possui suas referências atualizadas para este novo objeto. Vale lembrar que quando criamos uma variável dentro de um programa, esta não contém o valor em si. A variável contém apenas uma referência para um objeto em memória que armazena de fato o valor da variável. Dessa forma, em um nível de abstração mais alto podemos ter a sensação de ser possível alterar um objeto imutável, quando na verdade estamos criando um novo a atualizando a referência daquela variável.

Referencias para objetos imitareis

Realizar alterações em objetos que são imutáveis é caro e pode causar problemas de desempenho, uma vez que a cada alteração um novo objeto é criado e o antigo é destruído (observando a maneira como a linguagem de programação implementa o gerenciamento automático de memória ou coleta de lixo). Vamos imaginar um loop de 1000 repetições, realizando uma soma incremental em uma variável “i”, este objeto em memória será criado e removido 999 vezes durante esse procedimento, e somente o último objeto que contém o valor final será necessário, ou seja, pensando de forma simplificada, houve um desperdício de recursos de memória, processamento e consequentemente tempo.

Ainda nesse contexto, podemos trazer para a discussão um contraponto, que é a “mutabilidade”. Um problema que a mutabilidade pode nos trazer é justamente o “efeito colateral”, ou seja, um objeto mutável fica a mercê de alterações não previstas no seu estado. Realizar alterações em objetos mutáveis é mais barato, uma vez que a cada alteração, o mesmo objeto em memória é utilizado e apenas o seu estado é alterado. Porém, é preciso entender que ao alterar um objeto mutável, todas as referências (variáveis) que apontam para este objeto, irão refletir as alterações. Caso isso seja feito de maneira não controlada, comportamentos inesperados podem surgir no fluxo ou resultado do programa.

Por exemplo, se um método A alterar um objeto indevidamente, este pode causar um bug ou resultados indevidos em outro método B que também utiliza este objeto, pois em um primeiro momento o método B espera um objeto de um tipo ou valor, e no outro momento o método B acessa o mesmo objeto com outro tipo ou valor. Isso é muito comum em aplicações que controlam o saldo de uma conta bancária, por exemplo, onde é necessário garantir que ao manipular o saldo da conta, este contenha o seu valor original e que nenhum outro código tenha alterado o seu valor, caso contrário teríamos um saldo incorreto do ponto de vista das transações financeiras. Esse problema também pode ser observado em programas multi processos (mult-threading), onde dois processos diferentes, podem acessar e manipular o mesmo objeto em paralelo, causando efeitos colaterais imprevistos.

A Imutabilidade é uma característica que avança além de código e existe a nível de arquitetura. Domain Driven Design é uma abordagem de desenvolvimento de software que utiliza uma coleção de padrões de projetos para resolver problemas comuns no desenvolvimento de sistemas. O DDD utiliza duas formas básicas para representação de objetos do domínio nos sistemas as Entidades (Entities) e os Objetos de Valor (Value Objects).

As Entidades representam no sistema algo relevante do domínio, devem possuir um identificador único, o ID que é sua principal característica, para distingui-lo das outras entidades mesmo que o valor dos demais atributos sejam iguais. São transformados ao longo do tempo, são mutáveis e devem ser mantidos ao longo do tempo, isto é, são persistidos.

O Objeto de Valor mensura, quantifica ou descreve algo do domínio. Deve ser imutável e modela um conceito ao reunir vários atributos como um valor único. É totalmente descartável quando um desses atributos é alterado, sendo assim, pode ser comparado a outros objetos baseado na igualdade de seus atributos. Funções aplicadas aos objetos de valor não possuem efeitos colaterais, já que novas instâncias podem ser criadas sem se preocupar com as obsoletas. Podemos utilizar o objeto endereço, que é composto por 5 atributos, como exemplo: Rua (tipo de logradouro) Felipe Guerra (logradouro), 205 (número) Apto 203 (complemento), Centro(bairro). O objeto endereço só existe a partir da união desses atributos pois juntos dão sentido ao mesmo de forma única.

Value Object

As situações apresentadas acima são casos típicos que ocorrem quando os conceitos de imutabilidade não são observados com cuidado, fazendo com que a aplicação possa se comportar de maneira inesperada devido a um objeto ter mudado indevidamente. A imutabilidade nos garante que situações desse tipo não ocorram. Porém, é necessário conhecer como cada linguagem implementa esse conceito. Algumas linguagens oferecem por padrão tipos de dados que são nativamente imutáveis e mutáveis. Implementações de chamadas de funções que possibilitam ao desenvolvedor informar como será o comportamento dos objetos do ponto de vista da imutabilidade, e ainda recursos que podem controlar e determinar quais e quando os objetos devem ser mutáveis e imutáveis.

Por fim, podemos concluir:
(1) objetos imutáveis ​​são recomendados ​​quando você precisa garantir que o objeto que você criou permanecerá sempre o mesmo até o final da sua vida;

(2) é importante saber se o tipo de dados utilizado é imutável ou mutável, pois a eficiência da memória é altamente afetada quando os objetos apropriados são usados;

(3) é necessário conhecer a linguagem de programação utilizada no sentido de como ela implementa os conceitos de imutabilidade para não cair em pegadinhas, comportamentos estranhos ou indevidos e situações inesperadas na utilização dos programas.

Este post é a transcrição do relatório apresentando na disciplina de Algoritmos e Estrutura de dados, ministrada na turma de Mestrado em Engenharia de Sofrware no IMD/UFRN, pelos mestrandos Eduardo Luiz, François Dantas, Marcelo Luiz e Marcos Alvarenga.

Links:
Imutabilidade – Relatório
Imutabilidade – Apresentação