Showing posts from 2016

Inheritance as Polymorphism vs Inheritance as Code Sharing

We've all heard the mantra that we should favor composition over inheritance, and in most cases this is good advice. Occasionally, though, we really do need an inheritance relationship. Inheritance provides that useful “is-a” relationship that sometimes fits a situation so well. The pitfall we have to watch out for is using inheritance for code sharing between classes that should otherwise not be related, and not for polymorphism, that “is-a” relationship. What makes code sharing through inheritance so bad in the first place? An inheritance relationship is one of the tightest dependencies that could be made between two classes. It is hard-compiled in, and cannot be swapped out at runtime. It's an all-or-nothing relationship, and anything the parent wants to expose, the child must also expose. The child class may be able to override some of the parent behaviors, but the parent may finalize some methods and prevent this, locking the child class in even more tightly. This may be

Trapped in the Purgatory of a Big Refactoring

Sometimes, it's not just a method that needs refactoring, or even a class. Sometimes it's several large packages with a spider web of dependents that just need a complete "rehacktoring." This can happen when years of legacy code build up in a system. It is complicated by the fact that the thing you want to change or delete or rename or move has tendrils of dependents spread all across the system, sometimes into classloaders and reflection and dynamic scripts that you cannot begin to search-and-replace all of. It is going to be a big, long slog into the swamp. We don't want our massive change to be a surprise to our team, though. We want to commit and merge the bits as we're going along. They don't represent complete refactorings. We might have pulled out a class just to put some code in a separate place, knowing that down the road we're going to merge it together with some other class and move that other method somewhere else. We're not quite su

YAGNI vs Uncertainty

You're sitting there staring at the (pretty good if you say so yourself) code you just wrote. It solves a pretty tricky problem in a pretty elegant way. But something is worrying you: this code might need to change. You're not sure when and you're not sure how, but you just get this feeling tingling in the back of your neck that this code is going to have to change, and probably sooner rather than later. Somehow sensing your hesitation from across the room, that guy comes over. Yo, bro, looks like you got a problem. Just remember, bro, YAGNI! You ain't gonna need all that! You've heard it all before from that guy . You've even followed his advice a couple of times. Once, yeah, he was right, but that other time... oh, that other time. So much extra work that you just know you could have avoided, somehow. Maybe I exaggerate a bit, but we've all seen or heard of or (shudder) worked with someone who strictly follows the One True YAGNI. They never add any co

#FOChaCo: Fear of Changing Code

In code, as in life, things are always changing, whether we want them to or not. (Focusing on the code part,) Operating systems, libraries, protocols, languages, standards, and best practices are changing on the regular underneath every bit of code we write. While many of these systems work hard to change in "backwards-compatible" ways, sometimes there are changes that break things. As software developers, our job is to write our code that is robust to change, so that it still works well when the future arrives. But sometimes there are those among us who suffer from #FOChaCo: the fear of changing code. Despite the inevitability of the future, they fight tooth and nail to keep things exactly as they were. They might insist that we cannot support anything later than version X of our platform, or that we should not update any libraries unless there is a dire need to do so. These developers are well-intentioned. They may have been bit in the past by a library update. They might

How Big Is Your Object's Interface? The Answer Might Surprise You!

We have a Person object, eddie . Part of the responsibilities of a Person object is to operate a Car , accessible as eddie.getCar() . Car s are made of parts like Door s and Seat s and an Engine . Starting a Car entails starting its Engine . So how would we start eddie 's Engine ? eddie.getCar().getEngine().start(); This accomplishes the task, but we see a violation of the Law of Demeter in this code. We can see this quite plainly: look at all the dots! But what is this "law," and who passed it? I don't think Congress concerns itself with these matters (at least not yet). How bad can writing code like this really be? To understand why we should follow Demeter, we have to see what happens when we don't. Our Person , eddie seems to have a very simple interface so far, a getCar() method. He just has that one method, but that method gives us back a Car with a getEngine() method. That method then gives us an Engine with a start() method. Each intermedi