DEV Community

Cover image for Idempotency and Immutable Objects
Thomas Hansen
Thomas Hansen

Posted on • Originally published at ainiro.io

Idempotency and Immutable Objects

The last 3 weeks I have had on average 100+ additional followers on DEV.to on a daily basis. Realising DEV has a lot of young software developers, often times admiring us seniors, looking for advice on how to become a great software developer - I feel somewhat responsible for my followers. In addition I have been attacking most existing paradigms in the industry, without really providing alternative solutions.

I will therefor take some time to explain two of the most important constructs in software development, and why they are important, and how they work.

Immutable objects

An immutable object is an object that cannot have changes in its internal state after created. One of my favourite examples is System.String from .Net Framework. Every single property and field on this class is immutable. This implies that if you want to change a string instance, you cannot. Every single method on this class returns a new object and does not apply changes to the original object at all.

This has the side effect of that System.String is implicitly thread safe. Most problems originating from thread safety originates from multiple threads being able to change the same object simultaneously. If nothing can change the object, obviously two threads cannot interfer with each other here. Another bonus is that the class becomes simpler. For instance, System.String implements the IClonable interface. However, the implemantation of this interface is literally as follows.

public string Clone()
{
    return this;
}
Enter fullscreen mode Exit fullscreen mode

Obviously the Clone method does not do what it promises, simply because it doesn't have to. Every single other method in the class returns a new instance of the type, and cloning therefor becomes irrelevant. Choose to create immutable types whenever you can. It solves hundreds of problems you wouldn't normally even realise you have before 6 months down the road. Immutable types should be your "default choice" because it results in more robust software systems further down the road.

Idempotent methods

Idempotent is one of those weird words few knows what implies. My primary example of idempotency is the HTTP standard's PUT method's description. For the record, most software developers aren't able to correctly apply idempotency, so don't assume every PUT method is idempotent, unless explicitly documented as such.

Idempotency is why most "CRUD update endpoints" uses the PUT verb, or at least should use the PUT verb. An update SQL for updating fields on a single database record is idempotent by default, and you have to add weird stuff to it such as triggers to remove idempotency from it. Imagine the following SQL statement.

update table1 set column1 = 5 where id = 3
Enter fullscreen mode Exit fullscreen mode

Regardless of how many times I run the above SQL statement, the column1 column for the record in my table1 table having an id of 3 will always be 3. This solves a whole range of problems, such as for instance transactional problems, where we have a piece of code that needs to invoke multiple other micro services for the system as a whole to be in a good state. Imagine having a banking system where you need to transfer $5 from account "a" to account "b". This requires two changes to two different records.

If your code is not idempotent, and some error occours after having deducted $5 from account "a", you cannot simply run the method once more, because that will deduct an additional $5 from account "a" before it inserts $5 into account "b". If the method was idempotent though, you could just "rerun" the same method, at which point the $5 deduction from account "a" would not happen again, but only the last parts of the method actually applies state changes to your database by adding $5 to account "b".

Idempotent methods makes it much easier for you to create "long transactions", because you can replay your methods without ending up in an invalid state.

Conclusion

If you want to create robust software, both immutable types and idempotent methods and functions becomes crucial. Maybe not immediately, because as we all know "it works on my system" - But when you deploy your software into a Kubernetes cluster, with load balancing guaranteeing you that you've got state changes not propagating to all containers, and you've got 500,000 threads hammering your web APIs simultaneously, the fact that your code works on "your machine" becomes irrelevant. Idempotency and immutable types solves such problems before they even arrive.

When we built our ChatGPT chatbot both of the two above constructs were applied to its maximum extent. This resulted in a multi tenant, multi user solution, that "simply works". No need to debug hard to track down bugs, race conditions, or dead locks, because the two above constructs results in that such problems cannot even happen in theory.

Choose idempotency and immutable types where you can!

Top comments (8)

Collapse
 
martinhaeusler profile image
Martin Häusler

Immutability and idempotency are extremely important topics. They can help to make your application reliable and robust, and in some cases can even help to boost performance - for example, caching an immutable object is trivial, but a mutable object in a cache is a recipe for disaster. Immutable objects are also easily sharable between threads. Depending on your programming language, immutablilty may be easier or harder to ensure. It's also important to keep in mind that, while immutablity is generally desirable, it can in some cases lead to excessive copying and performance degradation. Knowing when to use immutability (and when not to) is the tricky part.

Collapse
 
polterguy profile image
Thomas Hansen

Great point about cache, and yes, immutable objects have some overhead. However, most modern programming languages can pass objects by references, such as my example with C# and System.String, so the "copy by value problem" isn't all that relevant, albeit still have some relevance ...

Collapse
 
martinhaeusler profile image
Martin Häusler

@polterguy When you have a "flat" object (i.e. a class with fields consisting of primitives and strings) it's usually not a problem to make it immutable from a performance point of view. In my experience, immutability takes its toll on performance when deeply nested objects are involved, because a change in the deepest level requires a shallow copy of all the upper levels. As soon as people start to bring up the topic of "optics", that's usually when performance also becomes a concern with immutability.

Thread Thread
 
polterguy profile image
Thomas Hansen

Great point. I've taught myself "the art of teaching" over the years, and realised it's not about what you say, but what people hear. Junior devs are for instance for weird reasons obsessed about optimisations. If you even vaguely mention that something might have performance overhead, they'll (often) shy away from it as if it was the plague.

I am therefor a bit reluctant towards informing others about (what you truthfully pinpoint) as a problem related to performance, because youngsters tends to "get stuck" on such ideas, not realising that their acts of optimising the code, often in the end results in worse performing code. Donald Knuth comes to mind ...

Premature optimisation is the root of all evil ...

It's like openings in chess, you've got no use for them before you're 2,000+ in rating. Everything having the words "performance penalty, optimisation, execution speed" etc shouldn't even be taught to developers before they're at least 78 years of age if you ask me ... ;)

Collapse
 
arianygard profile image
AriaNygard

Giving advice to those with less experience while explaining why those with more experience should do it too in the same article.. Great writing!

Collapse
 
polterguy profile image
Thomas Hansen

Thank you :)

Collapse
 
squidbe profile image
squidbe

These are such important points. I sometimes think idempotence would be talked about and practiced more if the word weren't so weird 😊.

Collapse
 
polterguy profile image
Thomas Hansen

Hahahahaha :D

100% bulls eye!!