Every Case Is Special

Special cases are everywhere. This one little thing has to work this other way. Soon, there is an if/else chain twenty conditions long. Worse, that if/else chain is embedded in another chain of twelve conditions, all in one happy method. The next person making a kind of change has to tack on another condition and hope nothing blows up.

We know it's bad when we see a bird's nest like that. How can we deal with it? Why should we? The problem with code no one understands is that no one understands it. We will have a huge problem the day it stops working. We assume that, if it works now, it will work forever. That is a faulty assumption. The world changes around us. The solid rock beneath that code can erode away. And our hair will be on fire when that day comes.

Special cases are special. Normal cases are also special. Every case is special in some way. There are some classic special cases common to many code bases. There are quirky special cases unique to your own code. We need strategies to deal with those special cases in a maintainable way. We have to do two things: name those special cases, and encapsulate them.

null is the most common special case in code. null is a magic thing that is nothing and can be anything. It is a cloud of anti-matter. If you touch it, it blows up in your face. We must carefully contain it everywhere. We sprinkle null-checks liberally throughout our code. They just make things worse. Because dealing with null is so common, there are strategies for dealing with it. There is the Null Object pattern. Instead of returning null, we return an object of the correct type but with default or empty behavior. We name a thing to represent nothing, and then we encapsulate its nothingness. The calling code is none-the-wiser, but much happier without checking for null.

There are other common special cases. There's the "old way/new way." We were doing something in the code. One day, we need to do something else, but we still need to do the old thing too. We wrapped them up in a conditional and switched on a flag between them. We now have two things. They might be radically different. They might share a chunk of logic. But we don't have a name for them, and we haven't encapsulated them. When we need to add the "new new way," we're going have to work it into that conditional. Instead, we can extract classes to represent the two ways. We can tweak them so that they have the same interface. Then we can encapsulate them away behind simple logic that knows which one to pick. The two ways are not just random conditional bits of code. They are first-class objects with names that can be referenced and discussed. They are encapsulated so that changing them or adding a new way is much less risky.

By naming and encapsulating special cases, we can treat them just like the normal cases. By doing so, we reduce the risk of introducing unstable conditional code. We can deal with all cases at their level of abstraction while not cluttering up the calling code. We get all the tools of object-oriented design to improve those special cases because they are isolated. Treating every case as special, worthy of a name and a place, makes our code better.


Popular posts from this blog

Trying Out FreeBSD

Exposing Dependencies: Getting Worse Before Getting Better