Jon Kruger -
  • About Me
  • Blog
  • Resume
  • Values
  • Presentations
About Me
Blog
Resume
Values
Presentations
  • About Me
  • Blog
  • Resume
  • Values
  • Presentations
Jon Kruger
Design, OOP

Balancing DRY and readability

We all love the DRY principle (Don’t Repeat Yourself). It really is a good idea, we don’t want to have two places in the code that do the same thing, and we want good object-oriented design. But even DRY can go too far.

Recently I’ve run into some cases where DRY decreases the readability of the code. I had some simple classes to write that do some relatively simple calculations, and the business rules are fairly similar to some other classes that exist, but with a few differences. I started down the path of making one class that can handle all situations, with hooks for modifying the behavior of the class (either virtual methods or configuration settings somewhere else).

This is all well and good until you realize that now you’ve taken something simple and turned it into something really complicated that even you have a hard time understanding anymore.

DRY is great, but I lost sight of why DRY is good. DRY is good because it makes code more maintainable, more consistent, and easier to understand and add new functionality. But as soon as DRY stops providing those benefits, maybe it’s time to keep things simple and just write readable code that makes sense, even if it means you have a little bit of duplication.

February 24, 2014by Jon Kruger
Design, OOP

Why I don’t put load/save/delete methods on entity objects

Someone asked me the other day if putting Load(), Save(), and Delete() methods in entity objects is a bad thing. While I tried my best to explain why I don’t put these methods on entities, I thought it was worthy of a blog post.

I am a .NET developer, so I’m going to answer the question with how I would do it in .NET. If you’re working in a dynamic language like Ruby, things are certainly different and you don’t have all of the limitations that you have in .NET. So what I’m about to say really only applies to the static-typed languages (.NET, Java, C++, etc.).

First of all, I am writing unit tests, which means that I’m using concepts like dependency injection. Someone who doesn’t write unit tests or use dependency injection might not see value in structuring their code the way I structure it. But the arguments here only partially have to do with testability.

Let’s say that I have these entities in my application — Product, State, Country, Customer, Order. In this list I have some things that change often (Customer, Order) and some things that won’t change often (Product, State, Country). So let’s say that I decide that I’m going to cache the entities that don’t change often.

Let’s think of this in terms of loading, saving, and deleting. When I load them, I’m going to check the cache first. When I save them, I’m going to save the object to the cache as well as the database. When I delete them, I’m going to remove them from the cache. I’m going to change how these types of entities are loaded, saved, and deleted.

Now let’s imagine that my entities had methods like Load(), Save(), and Delete(). I would have to implement the special cached loading, saving, and deleting in three places – Product, State, and Country (and whatever other cacheable entities that I have). Any time you have to copy and paste code you should start to wonder if something is wrong.

In this case, I might deduce that the way to solve the duplication would be to split out the code that loads, saves, and deletes cacheable entities into some other class that is outside of the entity class. These classes would be powerful because they aren’t just acting an individual entity type, they are acting on certain kinds of entities. Maybe you specify that an entity is cacheable by having it implement and interface or maybe you decorate it with an attribute.

Now when you have another cacheable entity, all you have to do is implement the right interface or put an attribute on the entity class and it will automatically work with the cache!

This is a good example of the difference between object-oriented code and procedural code. We want to do more object-oriented programming and less procedural programming because object-oriented code is more testable, flexible, and reusable.

There are also testability reasons for not putting Load(), Save(), and Delete() on entity objects. If you don’t understand dependency injection, you should go read about it first so that this makes more sense.

When using dependency injection, you take in dependent classes through the constructor, but you don’t do this with entity objects because entity objects do not have dependencies. Entity objects define what the model is, and other classes (“domain services”) define how the entities work together.

Earlier in the post I talked about how I would create a class that knows how to save cacheable entities. If I had a Save() method on my entity class, I would need to call this other class (a dependency) from my entity’s Save() method. But remember, entities don’t take in dependencies, and I don’t want to new up the class that does the saving because now I can’t mock that class in a unit test.

You might be reading this and it might not make a whole lot of sense, but that’s OK. This is much different from how some people have written code for a long time, and they don’t teach you this type of stuff in school. But it’s always a good idea to question why things are done certain ways and maybe you’ll learn something new that can really help you out.

November 5, 2009by Jon Kruger

About Me

I am a technical leader and software developer in Columbus, OH, currently working as a Director of Engineering at Upstart. Find out more here...

I am a technical leader and software developer in Columbus, OH, currently working as a Senior Engineering Manager at Upstart. Find out more here...