There is much to complain about the object-oriented approach to software development: how it tends to result in big systems, that it favours over-engineering, etc. But one principle I think OO gets right is encapsulation: the idea of coming up with a domain model, exposing the operations as methods, and completely hiding how these operations are implemented.

It would do well for devs to relearn this principal, including myself. When I moved to Go, I experienced a subtle shift away from the practice of encapsulating types, favouring Go primitives that made sense where they could. This is not the fault of the language designers: the standard library is full of opaque types that can only be used with public methods. Maybe it’s simply an over-correction on my part after designing huge, complicated type hierarchies during my Java days.

But I think encapsulation is a principal that’s worth relearning. Why? Well, let’s travel to a world where encapsulation was never a thing. You’re working as a software developer that’s building an e-commerce site, and you need to add the notion of a shopping basket. This is a pretty typical thing such a site might have: a customer adds products they wish to buy to the basket, remove products they’re no longer interested in, or empty the basket completely when they release they’re not interested in participating in rampant capitalism and want to do something meaningful with their day.

How would you do implement this? Well, something like a map might do, where the product ID is mapped to an integer representing the number of items of said product that’s in the basket. Adding a product will add one to the quantity mapped to the product ID, and removing a product will decrement it by one. When the customer removes the last item of a product, the quantity will go to zero.

“But wait,” you say. “Should the product quantity go to zero, or should the product be removed completely from the map?” No reason why either shouldn’t work, and one option’s as good as the other. So you choose the zero quantity approach. You continue on until you get to the part where you need to save your basket in the database. Uh-oh: the database doesn’t support zero map values. Looks like you’ll have to go with removing the zero items from map. So you back-up and make the change. PR raised, merged, and shipped to prod. All good.

Months pass and someone new is working in that area of the code base. You show them what you did and assume that they recognise the approach you took when customers remove items form the basket. You didn’t make clear to anyone the issue you had with the database, but you figured others will cotton on and keep zero values out of the map.

In my experience, this assumption is flawed. Might be that you’re working in a language where zero values can be returned if a key doesn’t exist in a map1. This other dev may wonder what difference it makes whether the zero quantity item is in the map or not? They’re not thinking about how this looks in the database. Why would they? That’s been working in prod for a while. And they’ve got their own stuff to do.

Now, this is a contrived example: modern databases are pretty robust, after all. But I just encountered something very much like this in my real job that introduced a subtle bug which was difficult to track down. It was only my chance that I noticed how it looked in the database.

So what’s the solution? Well, encapsulation. Build a Basket type with the relevant operations — addItemToBasket, removeItemFromBasket, etc. — and hide how it’s implemented from others. That shields everyone from knowing about the unseen decisions imposed by external forces you had to make to get it working in the first place. They don’t even get to know that it even is a map. As a bonus, it make this a little more understandable from a business logic perspective. There is such a thing as being too concise, and simply peppering your service methods with elementary operations directly on maps can introduce noise when you’re simply trying to understand how something works.

So, encapsulation. A good thing. Do more of it.


  1. Go supports this in the form of the two result index lookup. ↩︎