Make It A Cohesive Couple

by Sue Petersen

Something happened today that started me thinking, once I got over being frustrated. I've written quite a few Delphi 1 applications for my plumbing business. Recently I upgraded one of my machines and I decided to take advantage of the higher resolution monitor I now had available to display more information on the screen.

This was an interesting problem, but not a particularly challenging one. The only exciting part was making sure that my forms maximized themselves at all the correct times and displayed at half-height the rest of the time. As a convenience, I set most of my forms to a WindowState of wsMaximized at design time. Then, at run-time, I maximize the form if it is called one way, and I change it to wsNormal and set the Height and the Top so that it will display on the bottom half of the screen if it is called another way .

Unfortunately, one of the forms looked fine when I opened it Maximized, but when I tried to open it at the bottom half of the screen it still came up Maximized. And it took me over an hour to find out why. I finally had to step through the code line by line, watching the form's Width, Height, and WindowState properties. It turns out that if the design-time state of a form in Delphi 1 is set to wsMaximized, and if you change it to wsNormal in FormCreate and if you then reset the Height or the Width, the WindowState automagically and invisibly, behind the scenes, changes back to wsMaximized.

In Delphi 1, at least, a form's WindowState and Height (or Width) are connected together in non-obvious ways. They are highly coupled--changing one can, in certain situations, change the other. I believe this is a bug, because it makes no sense to me to alter the behavior of the run-time WindowState of a form depending on what it was set to during design. But whether this is a bug in Delphi 1, albeit minor, or whether this behavior is 'working as designed', it was still a royal pain in the neck! I fixed the problem, once I realized what was going on, by setting the form's WindowState to wsNormal during design. But I believe my experience demonstrates an important principle.

While we've learned a lot about object-oriented design in the past few years, nothing we've learned invalidates the principles and hard lessons we've garnered during the last fifty years of industry experience. Structured design, in particular, is still relevant to today's world. The book The Practical Guide to Structured Systems Design, 2nd edition, by Meilir Page-Jones, is my all-time favorite description of structured design. (Prentice-Hall, Inc. 1988, ISBN 0-13-690769-5, $61) Many years ago, it was my first exposure to the ideas of structured design and it's had an enormous influence on my development as a professional programmer since then. I recently reread it and was impressed by how many of the concepts I still use in my everyday work. In particular, Page-Jones talks about coupling and cohesion, and shows how they are vital ingredients in any stable, reliable, and maintainable system.

Good design is all about information hiding, about building our systems from a series of black boxes. A black box has a simple, clean-cut interface that interacts with the outside world while keeping its internal data and structure hidden. It is cohesive, it does one thing and does it well. It is loosely coupled to the rest of the world. Its uncluttered, minimal interface allows the designer to make changes to its internals without worrying about or affecting anything else. A good black box can even be pulled out and replaced entirely with minimal effects on the rest of the system, as long as the interface remains the same.

Page-Jones defines coupling as the degree of interdependence between two modules. We can reduce coupling by making our modules as independent as possible. We do this in three ways, by eliminating unnecessary relationships, by reducing the number of necessary relationships, and by making any necessary relationships as loose as possible.

Page-Jones uses a stereo system to help us understand coupling. In a typical home stereo, each speaker is coupled to the amplifier, and the amplifier is coupled to the receiver. If we cut one of these connections, the system will no longer work correctly. However, the speakers are not coupled to each other. Each connection is simple and standardized. We can remove a connection, or make a new one, by pulling and inserting standardized plugs. We don't have to open cases, or solder wires, simply to change the speakers or to upgrade the amplifier.

By contrast, the parts of a boom box are much more highly coupled, and are thus harder to work on. This doesn't make a boom box bad, necessarily, at least not for its intended purpose. But it does make it harder to produce an affordable boom box with the same sound quality that a home system has. And if our boom box develops a mechanical problem, it's so hard to repair that we usually throw it away and buy a new one instead.

Page-Jones discusses the different levels of coupling, both acceptable and unacceptable, and describes the situations when each may be necessary. So called 'normal coupling' is when two modules or procedures are connected only by the parameters passed between them. This is the highest form of coupling. Page-Jones defines several different levels of 'normal' coupling, from best to worst, and points out some things that may indicate a possible problem. 'Global', or 'common', coupling is when two modules are connected by a globally accessible data area. Not surprisingly, global coupling has all the trials and tribulations associated with global variables, and is lower on the scale than normal coupling. 'Content', or 'pathological', coupling is when two modules are connected via direct knowledge of, or manipulation of, their internals. Pathological coupling is, well... pathological! It's totally unacceptable, and will lead to major problems down the road.

Cohesion is the flip side of coupling. It measures how the activities within a module or procedure are related to one another. The higher the degree of relatedness, the more cohesive the module. As with coupling, cohesion comes in a range of levels, from very good to unacceptable. Highly cohesive modules are easy to understand, easy to maintain, and easy to reuse. As a bonus, highly cohesive modules will be loosely coupled to the rest of the system.

Following Page-Jones' metaphor, a stereo speaker is highly cohesive. It moves the air, and creates sound. It doesn't contain the ON switch to the stereo system, it doesn't let us change the radio station, and it doesn't try to control the tape player. It only does one thing, and it concentrates on doing it well. It relies on the rest of the system to carry out whatever other functions are necessary.

Coupling and cohesion are more than just theoretical playthings. A system that has been built out of layers of loosely coupled, highly cohesive modules will be faster to build and easier to maintain. It's quick to build because the programmer doesn't have to be concerned with the internals of any module that he is not directly working on. All that matters is what that module (or component, or property) does. It's easy to maintain because it's simpler to track a problem to the offending code when all the modules limit their span of activity. It's easy to extend because once the programmer/designer understands how the black boxes are put together, he can easily plan where to add the new black boxes or extend the old ones.

The Delphi programmer who creates components that are highly cohesive and loosely coupled will lay the strongest possible foundation under the future systems his components are used in. And maybe the crick in my neck will finally get a chance to heal up!

Copyright © by Sue Petersen. All Rights Reserved.