Don't do it; it will overcomplicate stuff and You Ain't Gonna Need It
... is the answer I would have written here 2 years ago. Now, though, I'm not so sure; in fact, in recent months I've started migrating old code to this format, not because I have nothing better to do but because I genuinely needed it for implementing new features or changing existing ones. I understand the automatic aversions others here have seeing that code, but I think this is something that deserves serious thought.
Benefits
Chief among benefits is the ability to modify and extend the code. If you use
class Point {
int x,y;
// other point operations
}
instead of just passing a couple of integers around - which is something that, unfortunately, many interfaces do - then it becomes far easier to later add another dimension. Or change the type to double
. If you use List<Author> authors
or List<Person> authors
instead of List<String> authors
it later becomes much easier to add more information to what an author represents. Writing it down like this it feels like I'm stating the obvious, but in practice I've been guilty of using strings this way many times myself, especially in cases where it wasn't obvious at start then I'd need more than a string.
I'm currently trying to refactor some string list which is intertwined throughout my code because I need more information there, and I feel the pain :\
Beyond that, I agree with the blog's author that it carries more semantic information, making it easier for the reader to understand. While parameters are often given meaningful names and get a dedicated line of documentation, this is often not the case with fields or locals.
The final benefit is type safety, for obvious reasons, but in my eyes it's a minor thing here.
Drawbacks
It takes longer to write. Writing a small class is fast and easy but not effortless, especially if you need a lot of these classes. If you find yourself stopping every 3 minutes to write some new wrapper class, it can be a real detriment to your concentration, too. I'd like to think, however, that this state of effort will usually only happen at the first stage of writing any piece of code; I can usually get a pretty good idea quickly of what entities will need to be involved.
It can involve a lot of redundant setters (or constructions) and getters. The blog author gives the truly ugly example of new Point(x(10), y(10))
instead of new Point(10, 10)
, and I'd like to add that a usage might also involve stuff like Math.max(p.x.get(), p.y.get())
instead of Math.max(p.x, p.y)
. And long code is often considered harder to read, and justly so. But in all honesty, I have a feeling a lot of code moves objects around, and only select methods create it, and even fewer need access to its gritty details (which isn't OOPy anyway).
Debatable
I'd say whether or not this helps with the readability of code is debatable. Yes, more semantic information, but longer code. Yes, it's easier to understand the role of each local, but it's harder to understand what you can do with it unless you go and read its documentation.
As with most other programming schools of thought, I think it's unhealthy to take this one to the extreme. I don't see myself ever separating the x and y coordinate to be each of a different type. I don't think Count
is necessary when an int
should suffice. I dislike the unsigned int
usage in C - while theoretically good, it just doesn't give you enough information, and it does prohibit extending your code later to support that magical -1. Sometimes you do need simplicity.
I think that blog post is a bit on the extreme side. But overall, I have learned from painful experience that the basic idea behind it is made from the right stuff.
I have a deep aversion to over-engineered code. I truly do. But used right, I don't think this over-engineering.