The Art of Decoupling.
Monday, December 3rd, 2007Some people think the power of OO design is that the classes represent real-life concepts that are easier for a human to understand. Others think that its power comes from code reuse. Still other just accept OO as the paradigm that they are supposed to use, simply because they were told so.
The truth is that using any of those approaches to design may well leave you with a brittle, unmanageable, ugly mess. Personally, I strive for the “real-life concepts” as one top-level goal. The other top level goal is decoupling. Transcending all goals, of course, is creating a “correct” program. Not necessarily “correct” in the academic sense. I don’t verify every algorithm I use, and I don’t necessarily determine valid pre/post conditions. I mean correct in as much as, it works for what I need it to work for.
For small programs, this is pretty easy. When you get to larger systems, this becomes a slightly different problem to solve. In the days of goto, spaghetti code arose due to poor organization and ad hoc control transfer. Structured programming helped some by organizing the control codes into a set of well-defined idioms. Object oriented programming helped further by organizing responsibility into encapsulated modules. All of these paradigms had something in common; you could write brittle code or malleable code in any one of them. Granted, writing flexible code has gotten easier with Object Oriented programming, but only if you know what makes code brittle.
Over dependence of one section of code on another section of code. In software engineering, we call this coupling. If the behavior of A is dependent on the behavior of B, then A is dependent on B. Changing the behavior of B could change the behavior of A. This isn’t always a bad thing, but if A and B are written by different people (or the same person at different times) with different goals, it could be catastrophic. It isn’t always feasible to decouple two classes, or two methods, or even two lines of code, but if you can do it easily, consider what might be gained by that.
One syndrome I’ve noticed is that with any concept, some people take it to the extreme. For those readers who stopped at the above paragraph and decided I was right, and everything should be as decoupled as possible, you might see a design that I would call disintegrated. It is possible to create code that is so decoupled as to be impossible to figure out how one thing affects another, even though the overall system is design for A to affect B. Don’t do this
One approach to decoupling two classes is to have them communicate through an event system. This will couple them both to the event system, but not to eachother. This approach allows you to replace one of the pair without changing the other side at all. This makes a lot of sense for GUI applications, for example, where user interactions with the component (such as a button) generates an event that can be handled very differently, depending on the needs of the program. Most object oriented languages, and Java in particular, already has a useful mechanism for invoking behavior on other objects. Its called method invocation, the act of making a method call. Event systems are useful for decoupling the method call from the class that needs to know about the call, its not so useful as a replacement for normal method invocation.
There are plenty of other ways to decouple you code (often through use of patterns), but I won’t get into them here. GIYF
Software design is about making difficult choices. If you didn’t have to make choices, then it would be easy to create a simple program that can design software. Your job as an engineer is to decide what should be decoupled from what. Decoupling can be a great tool to create a reusable component, but not everything should be designed to be reusable. If you’ve written something that was coupled, but needs to be made reusable… Well, thats what refactoring is for. Decoupling two classes that only communicate with each other can actually add complexity for that use case, so unless you strongly believe that at least one of the two classes will be useful in other situations, it is a waste of cognitive power to separate them.
My goal for production-quality software design? Create the simplest design that meets all my requirements, but is flexible enough to adapt to future requirements.
