This site will look much better in a browser that supports web standards, but is accessible to any browser or Internet device.

Anomaly ~ G. Wade Johnson Anomaly Home G. Wade Home

October 18, 2007

Objects, Reuse, and Complexity

Over the last few years, I have spent a lot of time talking to lots of different people about object-oriented programming (OOP). I have spent a fair portion of the last three years interviewing and screening people over the phone for development positions. This activity has caused me to spend some time re-evaluating what I know about objects.

Reuse?

Some of the people I talk to say that OOP is about reuse. They say the main thing we get out of objects is reuse. We can reuse the data and functionality from a class by deriving from it. We get more reusable code by packaging it up in classes. Unfortunately, reuse is not confined to OO. Back when I was doing structured programming, we captured reusable code in functions. We used libraries and modules for larger granularity reuse. Obviously, OO is not the only way to reuse code. So, it's kind of hard to claim that the main reason for OO is code reuse.

OO Concepts

So, if reuse is not the purpose for objects, what is? One of the maintenance benefits of OO has to do with the concept of encapsulation. If a class is defined reasonably, the only way to access its data is through its member functions (methods). The practical result of this is the amount of code that can change a piece of data is limited. In a large system, this drastically reduces the amount of code that must be examined to troubleshoot a data problem.

OO provides good support for abstraction. It is possible to make an abstract interface without OO, but it requires more discipline on the part of the programmer and the clients of the library. With classes, it is easier to specify an abstraction and encourage clients of your class to use it.

Complexity

These two concepts are different aspects of the same issue: controlling complexity. By reducing the number of methods that can touch a given piece of data, you are reducing the communication paths in your code. This reduces complexity by introducing constraints in the way data is accessed and modified. Abstraction also reduces complexity by encouraging the client programmer to focus on the concept of the class rather than on its implementation.

In some cases, the complexity isn't actually removed, but only quarantined inside the class. This helps keep complexity inside the class from leaking out, and complexity from the surrounding system from leaking into the class. In many cases, reducing the way complex things interact is the best tool we have for managing complexity in our systems.

By providing interfaces that hide implementation details behind some form of abstraction, we reduce the complexity that the programmer needs to be aware of at any given point in time.

Increasing Complexity

This also highlights one of the points where OO has failed in its promises. Without careful thought about your designs, an OO system can add to the complexity in a system. Several kinds of OO design decisions can add complexity to a system:

  • deep hierarchies
  • badly thought-out interfaces
  • objects that are just collections of random data and methods
  • large quantities of unrelated classes

Another dark side of objects is that hiding the complexity of the system allows us to develop even more complex software because we don't have to deal with all of the complexity all of the time. This has caused many people to ignore the complexity cost of their designs.

Conclusions

People who really understand that OO is about reducing complexity avoid adding one more method to a class to make it more reusable. Classes with only one responsibility abstract the implementation details while providing a lower complexity interface to the functionality. Combine two classes inappropriately and the complexity increases again, because you need to know more to use the two halves of this split-personality class.

Keeping the importance of reducing complexity in mind should help in the creation of cohesive classes. Using classes to provide coherent interfaces that hide complex implementation details should help to reduce the complexity in our software.

Posted by GWade at October 18, 2007 07:29 PM. Email comments
Comments

Good post Mr. J.

You once said something along the lines of, 'design your tools in such a way that the client *wants* to use them, rather than writing their own version'. The main reasons that come to mind why people would not *want* to use your library is that it is missing some required functionality, or that using it is more complex than it needs to be. For me, this is the "holy grail" of library design.. Reducing a complex task to a narrow, yet flexible framework for solving the problem at hand. It's even better if your library allows for easy extensibility as long as the coder stays within the guidelines/rules of the framework.

As an aside, I think what turned me off to Java, is it's sheer size.. the number of choices that are available to you. The result is an "outsider" (that's me) perceiving complexity in the language itself. Reading code written by experts in this language gives me the woolies. Anyway.. off my Java soapbox.

I would be interested to hear your thoughts on "the principles of designing a good design". Perhaps something along the lines of "If you can't answer yes to the following, you should probably rethink your design" -- or something like that. ;)

Posted by: Ian at October 20, 2007 10:06 AM

Thanks for the comments.

Part of what you would like to see in a library is to be "as simple as possible, but no simpler." You also want it to be a powerful as it needs to be, but not more complicated than necessary.

You will probably note that even this simple and high-level a description already contains some very fuzzy trade-offs. These trade-offs are the hard part of design.

I really wish I had some great rules of thumb for distinguishing between a bad design and a good one, but I really don't. What might be a great design in one context would be too simple in another and too complex in a third.

The only real constant I can think of is if the client of your library has to know as much as you do about it to use it, it is a bad design.

Thanks again.

Posted by: G. Wade at October 20, 2007 11:17 AM