Service Classes And Anemic Objects

Vineeth Venudasan
Mar 22 · 4 min read

As I’ve progressed in my career, I’ve come across more and more projects where “a class design is considered good enough if it works”. With such a belief, programmers often come up with myopic class designs that can create maintenance nightmares.

Photo by Vlad Alexandru Popa from Pexels

For the sake of this post, I will provide a simple example, albeit a real-life one. Consider an application whose purpose is to deal with payments. A core domain class in such an application is a Money class. After all processing payments is impossible without Money.

An often seen version of the Money class looks like this:

This class leaks it’s internal state.

When you need to do business operations with this class, the problem manifests itself. Business logic with data-object styled classes such as above tend to be handled through specific Service/Transaction-Script classes.

While this is perfectly fine for extra-small applications, it is an no-no for bigger ones that have complex business logic, or one that is frequently updated with more and more features.

For example, the incident that I had seen involved

  1. having to know if the final invoice for a customer was above a specific threshold value of 275 EUR, and
  2. to do something very specific if that was the case.

Do note that this application was available across various European countries, even those that have not adopted the Euro currency.

The class where this was done looked pretty much like this:

In the particular case that I am referring to, this Service that you see above was implemented in two separate modules. Unbeknownst to the developer who had implemented this new feature, the amount of thresholdValue in function parameter was sent as Euros in one module, where as it was the local currency of the market in the other module.

The code nor the semantics made this explicit. It was a disaster waiting to happen.

Making it a bit better

Further changes

Can we do more?

My problem with the above solution is that core Money related logic will be now spread across another two classes, the ConversionService (for conversion) and the BillCalculatingService (is one Money of greater numerical value than the other).

This means all these three classes are coupled.

We have taken a simple example here of a single class, but imagine a scenario where an entire application is written with data-objects like the Money class, and all business logic spread out in various Service classes. As projects grow with more and more features, there is more chances of introducing extremely coupled classes, making changes very cumbersome.

My preferred approach

A different Money class implementation would look like this

There are two differences here

  • both the value and the currency are not exposed through getters
  • the value comparison is done through the Money class itself

This removes the need for Money comparison in the BillCalculatingService class, and the conversion logic in the ConversionService is invoked through the Money class too.

But I would take this a bit further. Rather than merely invoking the ConversionService method, I would move that logic elsewhere too.

With this approach, every time a new currency is introduced into the application (for example, a roll-out into a new country), having to specify the conversion factor becomes mandatory, since this will be a compile time check now.

Thinking even more in ‘Objects’

Now if you think about it ThresholdAmount is-a Money, but the only difference is how it is initialized, the former being done through configuration. (Remember, this value was configurable)

This is why I think there can be a ThresholdAmount object.

Conclusion

Too little can, too!

Finding the sweet spot is something that we need to learn, and often this happens with experience.

The key is to know when a refactor is needed, and then convincing your team and maybe your manager of the same. Well designed classes are often a serious tool to help you move faster in implementing new feature or avoiding bugs. The next person who maintains your code-base will thank you.

CodeX

Everything connected with Tech & Code

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store