ValueObject Performance

💡 UPDATE 2024: This post described the performance hit on using a now-obsolete package named 'StringlyTyped.
ValueObjects'. There is a newer project that does not have the same performance impact, named Vogen.
But be aware that there are value object libraries still out there that do have the issues described in this post.

In my previous post, I covered what PrimitiveObsession is and how ValueObjects help. I linked to a NuGet package that provides a simple implementation of ValueObject in .NET.

In this short post I'm going to touch more on where to use ValueObjects and where not to to use ValueObjects.

TL;DR: don't swap all your primitives everywhere for ValueObjects because it's slower and uses more memory. If you do this, you'll end up with a new 'code smell', which I have just named ValueObjectObsession!


ValueObjects solve a particular problem but are not a silver bullet to be used everywhere.

Just to recap on the terms

Probably the most important phrase here is domain ideas. In our pretend Billing domain, we have the following method (written by our young naive selves before we realised and addressed our PrimitiveObsession):

void SendInvoice(int customerId, int orderId)

Because it's obsessed with primitives, we have to dedicate half of the method to validating the input parameters. Here's the same using ValueObjects:

void SendInvoice(CustomerId customerId, OrderId supplierId)

We don't need to check the validity of what we're given, because we're guaranteed that in our Billing domain, that it's impossible to create an invalid CustomerId or OrderId.

So all is good in the domain and our ValueObjects are used to represent our domain ideas. ValueObjects are a good fit here because the domain is where our domain logic and models reside. Domain models, where ValueObjects live, are generally stable - that is, it's not a place where millions of objects are created and destroyed in quick succession.

That 'and destroyed' bit above is important: the biggest difference between primitives and ValueObjects are that the primitives could've be on the stack, but ValueObjects (at least in the implementation linked to above) are objects that live on heap.

In contrast to the relatively stable area of the domain, is infrastructure. This usually contains adapters for various technologies and can be a lot more turbulent in terms of object creation and destruction. So, it probably wouldn't be a good place to use ValueObjects instead of primitives, as you'd be creating a lot of extra work for the Garbage Collector (in .NET) which both increases memory usage and slows performance.

I did a very rough 'simulation' for this with Benchmark.net. The simulation compared primitives with ValueObjects in two scenarios:

Here's the results:

It shows:

🔮 future thinking: In the future, perhaps record structs # in C# 10 will give us the best of both worlds; clear representation of domain ideas in something that is as cheap to use and destroy as a primitive (and it also might have operators!)

What have we seen? #

🙏🙏🙏

Since you've made it this far, sharing this article on your favorite social media network would be highly appreciated 💖! For feedback, please 🦋 ping me on Bluesky! 🦋

Leave a comment

Comments are moderated, so there may be a short delays before you see it.

Published