Neil Harrison's Position paper
Lucent Technologies
11900 N. Pecos st. Room 30F-31
Denver, CO 80234
Before we answer the question, "What is it about objects that makes it easy to maintain a system?" we need to answer the question, "Do objects really make it easy to maintain a system?" In order to answer that question, though, we need to understand the nature of maintaining software. In other words, what makes it hard to maintain software in the first place? Let's start here.
The traditional answer to what makes software hard to maintain is that poorly structured code with high coupling and low cohesion is a major factor. In other words, it's hard to maintain spaghetti code. Some software just starts out poorly structured, but often, software starts with a resonably sound architecture and a clean implementation. However, over time, changes creep in, and the software begins to grow warts. Eventually, the original structure of the code can become obscured by all the changes. The result is sometimes a "Big Ball of Mud". The more a software system has been changed, the more likely it is to look like a Big Ball of Mud [Foote and Yoder: "Big Ball of Mud", in "Patterns of Program Design 4", Addison-Wesley, 1999.]
A related issue concerns the nature of the changes required to a software system. Software architecture and design are exercises in partitioning -- they carve the solution into smaller and smaller parts. Of course, there are many ways to slice the solution, and part of the architect's skill is in knowing the best way to slice it. If all goes well, subsequent changes will affect only a few parts of the software. However, occasionally changes come along that cut across the architecture, rather than with the architecture. When that happens, it causes a major upheaval in the software. In some cases, the original architecture is just wrong, but more often, the change is wholly unanticipated; out of the blue. Nobody would have imagined it in advance.
A third cause of difficulty maintaining software is the effort required to figure out what the software is doing. Software is very complex, and it requires a deep understanding of the code to know what it does. Most people have had the experience of writing some software and picking it up several months later, only to have no idea of what it does. It's even harder to pick up someone else's code and figure out what it does. These so-called "discovery costs" are usually just lumped into general development costs, so their impact is generally not appreciated.
So do objects make any of these areas easier? Objects to encourage (but not enforce) low coupling and high cohesion. Inheritance can help maintain the original architecture, since it is usually possible to use a derived class in exactly the same manner as the parent class. Of course, you need to start with a sound architecture; objects do not guarantee that the architecture will be any good. Furthermore, an OO architecture is not appropriate in all cases; use the paradigm that fits best. If you force-fit an OO architecture onto a non-OO problem, you already have one foot in the mud puddle.
What about unforseen changes that cut across the architecture? Here, it seems that the impact of OO is somewhat smaller. The real difficulty here is being able to anticipate and accommodate the changes, and OO does not bestow an added measure of clairvoyance. You are still going to get blindsided. Objects may be a bit more resiliant in the face of such changes, but I don't have any data to substantiate this hunch.
Objects may help with discovery costs. It seems that in a design where the objects map well to the real world entities, the software may be easier to understand. However, discovery cost has not been studied in depth, so the only thing we have to go on is a few testamonials. In addition, objects in a design tend to proliferate, and one is faced with large numbers of objects that do not have an obvious relationship to the problem. Such objects can impede understanding.
So what can we do about it? Much of the difficulty lies in the fact that software systems are very complex; we can't do much about that. However, there are some things we can do that can help make software easier to maintain. Here are some suggestions:
Recognize essential and artificial complexity in a potential solution, and eliminate as much of the artificial complexity as we can. The essential complexity should tend to map to the real world. Artificial complexity tends to obscure the real problem. In short, we need to teach -- and perhaps learn ourselves -- how to design software: how to create tight software designs that clarify the essential complexity and minimize the artificial complexity. Improving the ability of software designers may be the most important thing that can be done.
Perhaps we should think carefully about how we teach objects. It may be best to teach multiple paradigms, and then teach analysis skills to discern which paradigm is most appropriate for the problem at hand. This should help counter the phenomonem that "if you give a man a hammer, everything looks like a nail."
There are management practices that can help. Discovery cost is related to experience with the code, so there should be some sort of incentive for people to remain with a particular project for some length of time. In other words, reward people for staying on the project. In addition, probably the biggest factor in the success of many projects is the ability of the staff. Managers should work to attract and nurture very good people. Of course, these items are independent of OO. In my experience, many companies are somewhat reluctant to recognize the importance of these actions.
Domain analysis may help you recognize and accommodate areas likely to change. Naturally, it is still only as good as your ability to forecast the future, but it does instill a discipline which encourages you to consider areas of change that you might not have otherwise considered. You can use this information to create an architecture that can accommodate likely changes. One problem with many domain analysis techniques is that they are quite labor and time intensive. The frenetic pace of software product introductions can discourage such analysis. Developers will probably have to decide for each project whether they can afford to take the time to perform a domain analysis of their project's domain.
You will notice that creating reusable components is conspicously absent from my list of recommendations. Does it help? I have not seen convincing evidence. I think its significance pales in comparison with the four actions I discuss above. Indeed, reuse will be a by-product of good design. But poorly designed software that becomes a component simply increases the audience of the pain it inflicts on its users and maintainers.
To participate in this workshop please read the Call for Participation