Immutable? A practical application

As a Java developer, you might have always answered the question about immutability involving the String class.

A standard answer might look like String is immutable in Java. This means that if you modify an existing String, it will create a new instance instead of creating a new one. Immutability gives us thread safety and allows memory optimizations.

As an interviewer, my immediate next question is have you used anything else apart from String class that is immutable? Have you ever felt the need of making something immutable? Have you ever wondered, if I make this object immutable, I could solve so and so problems?

On almost all of the occasions, I did not receive any satisfactory answer. However, I have been using the concept of immutability since a long time in my applications and here is my view on one of the ideal candidates for immutability.

A well-architected framework defines clear boundaries between the services/modules/applications. All these modules communicate with each other by passing some data in to it and in turn get some data in the response.

Whenever the data crosses an architectural boundary, it will be appropriate to make it immutable.

Why so?

Let’s say, service A passes some data to service B. Hence, service B is on the receiving side. Basically, service B does not have any control over the data. It does not know (or rather, it should not know) how the data is generated or what is the source of the data. It is very tempting for a programmer to validate the data and do some sort of “auto-correction”. While this might be a valid use-case in certain applications, it should not be a general practice.

In most of the applications, the service receiving the data should not modify the data and process the data as it is. If there is any problem, throw an error.

Similarly, the output generated by service B is not owned by service A. And hence, it should not be able to modify it.

Not following these principle might lead to some hidden buts that are hard to debug.

One good way to achieve this is to use the Google Protobuf library Make sure that your service contracts are defined using protobuf DTOs. The input as well as output.

Doing this might be difficult in the beginning. However, simply following this step will uncover the flaws in your architecture, and surface the hidden anti-patterns.

You might find it difficult to start with, but believe me, once you get hold of it, you will never move away from this practice.

Leave a Reply

Your email address will not be published. Required fields are marked *