Why you desperately need Value Objects in your life
Tags: cleancode, valueobjects, domaindrivendesign, architecture
Published: 2022-06-25 09:57:56

This article is targeted toward developers who want to level up their programming skills. I’ll introduce you to Value Objects, an advanced concept that will help:
- Making sure your system is always in a valid state
- Better organize your code and keep it DRYer
- Increase testability, readability, and maintainability
- Make your software more robust, fail-proof, and less buggy

## The Value in Value Objects

Let me walk you through an example to demonstrate the problem we’re trying to solve. Let’s assume that we need to write a function that sends an invitation to a birthday party. The crudest implementation might look something like this:


![initial function](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iyorc80edx7pz33ovwnp.png)

> I’m using Typescript throughout the examples, but the principles I’ll discuss here are relevant in pretty much any language and can even be implemented to some extent in non-typed languages. The examples are simplistic and I’m not using the latest syntax to keep things easy to understand.

Notice that the function has no input validation, nothing prevents passing to it arguments that will either break it (like an invalid recipient email) or will simply produce a weird and unwanted output (like “d4$k” as the name or  -6.293 as the age).

Typescript does a nice job enforcing **some** business rules, it ensures that “senderName” is a string, and that “age” is a number, but that’s not nearly enough! If we look, for example, at the first argument (”senderName”) and think about what makes up a valid name, we can come up with the following specification:

- A string
- Consists only of alphabetical characters and spaces (no digits or symbols)
- Between 2-100 characters long

There’s a lot more we can add to that list, like rules around whitespace, capitalization, etc. But these 3 rules will do for the sake of our example. The point to take here is that real life entities can rarely be modeled to a simple primitive data type in our code (string / number / boolean etc.). They usually have a set of business rules that determine what a valid value looks like, even seemingly simple models such as a name.

## Introducing Validation

So because we want to avoid processing invalid input, we introduce validations into our function:


![function containing validation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5il7phn8udmr6b4f903s.png)

What do you think about the way we handle validation here? Notice anything wrong? I mean it’s fine, it’s doing its job. But writing code that works is the easy part and is not enough, writing readable, maintainable, testable, and extensible code is much harder. It’s what separates great programmers from bad ones.

## What’s wrong then?

The last change might look harmless, but I argue that it introduced several problems into our codebase.

First of, does the name validation actually belong here? What if we’re handling names in other places in the app, do we duplicate the validation? That wouldn’t be DRY… And we are likely to encounter more and more use cases that require a valid name as our application grows.

So maybe we can extract the validation to a common service? That’s not a bad idea, but it will be very hard to keep track on whether a certain value has been validated already or not. I’ll probably want to validate the values before passing them as arguments to functions, at the same time I must validate the input on the beginning of every function I write, because how can I be **100% certain** that the input was validated before being passed to the function? You can see how difficult to manage this gets. I guarantee that if you go with that solution you’re going to find yourself unnecessarily validating the same value multiple times, and the name validation code is going to be scattered all over the codebase resulting in clutter and taking the focus away from the important business logic.

Besides, the function in the example is about sending birthday invitations. Ideally, that’s the only thing it should do (single responsibility principle). It shouldn’t be concerned with the validation logic of each parameter.

## How can we remedy this?

Here’s a wild idea - wouldn’t it be great if we could know for sure that the values we pass around are **always** valid, so we can avoid frantically validating them all around our functions and services? Wouldn’t it be nice if we make sure that our value **cannot** be modified into an invalid value?

Let’s recap our needs:

- We need **one** sensible place that will encapsulate all the business rules concerning the validity of a given value.
- We need to disallow modifications to that value that will put it in an invalid state.
- We need to enforce that our solution is used 100% of the time.

## Enter Value Objects

Value Objects act as a container that holds a value and all the business rules to validate it. They run all the validations on creation, and since they are immutable (cannot be changed) they don’t allow the value to ever go invalid. If you want to modify a Value Object, instead of changing the existing one you just create a new one in its place. The idea is to pass around the Value Object rather than the primitive value, then we can always be confident that it’s valid.

So let’s get our hands dirty and create a Value Object for the name data model, we will implement the value object principles one by one.

### Principle no. 1 - Validates on Creation:


![initial value object](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oqnswln3dn7ry7li4beo.png)


![instatiation examples](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r6t8uaecvb5oqhh8mlch.png)

Now, whenever we create a Name we can be certain that it’s valid, but we have no assurance that it won’t be modified into an invalid value somewhere along the way. Like so:


![modification allowed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ygmo3g961xwio922l170.png)

### Principle no. 2 - Value Objects Are Immutable

So the next step would be to make the value immutable, in Typescript we can do that by using the “readonly” keyword at the property declaration:


![adding readonly](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2u08tm2e19u9f9ydhkya.png)

This prevents the value from being changed after instantiation:


![immutability example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n3ompbyrwereo5btpy24.png)

### Principle no. 3 - Enforce The Use of Value Objects

Now that we’ve created this awesome Value Object, we need to make sure that it is always used when calling the “sendBirthdayInvitation” function. So we declare it as the parameter type, like so:


![change name parameter](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ftgmehhf7k27fm6jrouf.png)

Unfortunately this isn’t enough. Even after setting “Name” as the parameter type, the following arguments are completely acceptable by TypeScript:


![structural typing problems](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cm8ofzz2owo5bbqny9q5.png)

What the hell is this? Why would TypeScript allow a literal object and a class other than the “Name” class to be passed as an argument? This has to do with the fact that Typescript employs a structural type system. Without going into too much detail, this means that Typescript compares types by their interface (structure), so two types of the same interface are interchangeable as far as TypeScript concerns. Our Name class interface is just one property called “value” of type string, so any object with a “value“ property of type string will be accepted by TypeScript.

This completely circumvents our efforts to enforce using the “Name” Value Object whenever calling “sendBirthdayInvitation”. But worry not, I’ve found an easy way to workaround it - all we need to do is to add a private property to the class:


![adding private property](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/am5o78udqikufucnwqm2.png)

I gave the private property the weird name of “\_X_” just to make sure it won’t clash with property names I would want to use in the future, but you can really name it anything you like.

Let’s see how TypeScript reacts if we try to pass anything but a “Name” instance now:


![literal object rejection](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sw1cuhke5eb5319ejh3a.png)

So no one will ever be able to pass a literal object, because literal objects cannot have private properties. What about classes?


![other class rejection](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wl223soppm4qfhe5j6hy.png)

Notice that TypeScript complains even if I add a private “\_X_” property to this class too. This is perfect for us because it means that we can use this private property in all of our Value Objects.

## Congratulations

Our first Value Object is now complete, here it is with all it’s glory:


![complete value object](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/caiud4ja472tuqpjadg4.png)

Take a moment to appreciate how easy it is to unit test it. How readable and maintainable it is. We defined our domain model so well that it is now virtually impossible to put it in an illegal state at some point in the future. 

>	The approach I used to implement the Value Object utilizes classes, which is a pretty Object-Oriented way to do that. If you’re into Functional Programming know that this can be done in a functional way as well. You’re likely to find better implementations of Value Objects online, the one I use here is simplified to make it more understandable.

## Putting Value Objects in Use

If we go back to our original “sendBirthdayInvitation” function, once I define Name as the parameter type, I can rest assured that the argument passed is a Name instance which means it had undergone all the required validations. If we do the same with the other parameters, we can have the function purely focused on its responsibility and clean of any input validation:


![value objects as parameters](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cfclvnqgjrxq8argc9rz.png)

Make all of your values into Value Object and you can be confident that your business rules will always be respected. Your functions will be much cleaner and as a result, easier to change or refactor.

Many software architecture patterns advocate organizing your application into several layers, what we did here is essentially created a separate layer for our data models. That way other layers can remain uncontaminated with our models business rules, which usually manifest themselves as convoluted input validations, if statements, and case clauses.

## One more added benefit

I sure hope that at this point you are already convinced that using Value Objects can tremendously improve the quality of your code. Still, I’d like to mention one last perk in using them - it acts as the perfect place to document the data model it represents:


![documentation comment](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eibh01gyr1u1kqdna6wb.png)


![documentation tooltip](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b4in5fnsgqq7ukmhmjm9.png)

## Conclusion

That’s It! If you made it this far give yourself a pat on the back. 

I Hope you enjoyed my work and that I managed to convey the immense benefit I see in Value Objects. It was the tip of the iceberg, there’s so much that can be improved in this Value Object implementation, and there’s so much more to Value Objects than what I showcased here, but I tried to keep this article bite sized. I hope it ignited your curiosity and I encourage you to explore this subject further.

**Please feel free to provide feedback**, and let me know if you want to see more content on this subject. There’s so much we didn’t touch on like better error handling, creating a Value Object super class, how Value Objects play out in the Domain Driven Design framework and so on. For any questions/comments you can contact me on [linkedin](https://www.linkedin.com/in/zohar-pfeffer-156575173/).

This article was heavily influenced by Domain Driven Design, Secure by Design, Clean architecture, and Khalil Stemmler’s blog.