Over the last 3 or 4 years, I’ve started to get frustrated with something I see a lot in code. It’s a two-headed monster. The first head is lack of classes, and the second is not properly using the classes that do exist.
First things first, I find despite the fact that my entire professional career has involved C++ (7 years), C# (5 years) and Visual Basic.Net (1 year), all of which can be called “Object Oriented”, most of the code I interact with doesn’t have enough classes. I think there is a unspoken idea that more classes is bad design. It’s as if we decided a while back that having fewer large classes that do several different things is better than having more, smaller classes that each do fewer tasks.
Because of this mindset, it’s as if we’re afraid to create classes. Instead, we pass around a lot of parameters. The gist below isn’t an exact code snippet that I’ve worked on, but it’s similar enough to call it a pseudo-real-world example:
I’ve written and seen controllers like this seemingly a thousand times. When looking at code like this I now ask myself “Who’s responsibility is it to validate the data?” In the sample above, it is the controller’s responsibility. But a controller’s responsibility is supposed to be more of a dispatcher or organizer. It takes incoming requests, farms them out and returns the results. It’s the infrastructure of the application. So the teams I’ve worked on have started adding logic classes. The new logic classes make the above snippet look like this:
At least with this snippet, the controller is acting more like a controller. It’s receiving a request and returning a view. Everything else is done outside. But we have to ask the same question as above, “Who’s responsibility is it to validate the data?” In this case, it’s the UserLogic class. Maybe that’s ok. Maybe we’ve pushed it down far enough, but I don’t think we have.
Right now all we’re doing is creating a new user, what happens when we need to update a user? We’d probably have something like this:
Now we have a problem, we have the same boilerplate validation logic in two methods. What if we have some other operation on the User controller that needs to validate the same parameters? If we weren’t class averse, we could easily clean this up to look like:
Now we have a user class that is responsible for it’s own validation. After all, who better to know if an object is valid than that object. This has the benefit that everyone that needs to validate a user object can reuse the validation, and reduce the risk of not validating part of the object. We also have an update method. This allows the user object to know any special logic that might go into updating the object. In our case, it’s just a straight update, no special logic.
Not Using What You Have
The final snippet above shows us using our User object to do validation. However, the second part of the problem is not using the classes you have. For example, we might see something like this:
Here our User object is really nothing more than a DTO. Instead of asking the User object if it’s valid, we’re asking it for all the information and then deciding if it’s valid. This would be akin to you pulling your car into your garage and when you went to turn it off the car asked you “Am I in park?” and if you said “yes” it would let you turn it off. If you said no, it would hold on to your key. It doesn’t make sense with cars, and it doesn’t make sense with objects.
How Did We Get Here?
I’m not entirely sure how we got here. I think some of it is just human nature. As we’re developing, we’re thinking we need to validate the object. It’s easier for us to write the code in the controller or the logic class instead of creating a class. After all, thats where we’re at when we start thinking about validation.
However, I think there is something to be said about some of the language features as well. For example, for about the past 5 years, C# has given us Object Initializers. Before this, the only way to set fields of an object was to create a constructor. We’d often wind up with code like this at the top of our class:
For every combination of parameters that we might need for this class we needed a unique constructor. We also did things like copy constructors, where you’d pass in another User object and copy it’s fields to a new User. This works well if you know beforehand what fields your users will want to instantiate with. It also works reasonably well for classes with a few fields. If your class has 10 or 15 different fields, the constructor permutations become cumbersome.
However, the constructor permutations might be a good time to ask yourself if you need to be creating a class with that many fields. Is it really true that the majority of your methods on that object use a majority of those fields? Or are there actually classes that exist within your class?
Now, we have object initializers, so we can create objects just like this:
I have found when I create objects in this manner, I think of them less like objects and more as data containers, or really, a property bag. Something to just hold a bunch of somewhat related data.
Another language feature that helps us wind up with the bad code above is the way C# handles properties. When I first started writing code professionally, I could either make public fields (which was a good way to get my code thrown out during a code review) or write getters and setters for my properties. The second method usually meant that you didn’t expose all your properties or fields because you wouldn’t want to write 2 methods for each property.
However, now, I use properties in C# almost exclusively. I do typically have a couple private fields on the class, but most of the fields are actually properties. It’s so easy to implement, and it makes it easy to grab whatever data from an object that you want.
It’s not all negative, however. These features were required for C# to implement some of their LINQ functionality. They made things like Entity Framework, LinqToSql and other features of C# possible. The features themselves aren’t bad, but how we use them can be.
It’s not bad to have classes, in fact most of the time it’s good. Not only does having classes provide you with reusability, it also lends to cleaner code. It should also help make more clear who has what responsibility. So let’s get out there and add some class to our code.