Pathologies of Uncohesive Code

Uncohesive code is code that either has too many responsibilities or has poorly defined responsibilities. Typically, it’s code that tries to do too much.

Poorly cohesive classes are difficult to understand and maintain. They’re harder to debug and more difficult to extend. The bottom line is the more issues a class has to deal with, the more things can possibly go wrong.

Classes that have poor cohesion end up becoming overly complex. They couple multiple issues together that shouldn’t necessarily be coupled together.

Classes become uncohesive when we don’t take the time to call out the entities for which the behaviors belong when we’re building out behaviors. You might think this is no big deal but it adds up. Without calling out in the domain, the object model becomes distorted and it becomes harder to understand and maintain in the future. And my number one goal when writing code is to communicate to other developers what it is I’m doing, so building out the object model and naming the elements well is fundamental to building good software.

One way to create cohesive classes is to look for behaviors that share or affect a common set of data. The common set of data can become instance data for the class, and the behaviors can be methods on the class. If cohesive classes are about having a single responsibility, then cohesive methods are about fulfilling some functional aspect of that single responsibility. Methods are the behavior of classes and they should be clearly defined.

Poorly cohesive methods are methods that may have overly generalized interfaces. For example, many years ago I worked on the OS/2 operating system and we believed that having a generalized API was a good thing. It minimized the number of APIs you needed to provide and it seemed to be making more efficient use of memory, which was quite expensive back then.

Today I believe just the opposite. Overly generalized method interfaces give orthogonal clients access to the same APIs. This means they become a coupling point for many different types of clients and can create side effects between different clients and couple them together in unexpected ways. Methods that try to do too much are also very difficult to use.

Poorly cohesive methods are also very difficult to refactor. Extract Method is the most common refactoring that I see aside from Rename, which is my favorite refactoring because it’s safe and it embeds knowledge into the system. Extract Method is my number one defense against poorly cohesive methods, which are simply methods that are trapped within a loner method. If I can name what the behavior does then I’ll extract that behavior into its own method and give it that name. I find that this makes my code far easier to read and understand. I much prefer to delegate to a private method with a meaningful name than to insert a comment explaining what the block of code does.

Sometimes bad things can tell us good things and I think this is true with cohesion. When we look at the price we pay for poor cohesion in code, we see that it’s simply not worth it. It’s far better to take the time and craft method interfaces for specific types of clients and to craft our object models with entities that are focused and singular.

To view or add a comment, sign in

More articles by David Scott Bernstein

  • Green Tests and Red Tests

    In practice, I found that there are times that I want a bit more test coverage than I get from just doing test-first…

  • Radiators and Silos

    In the old days of corporate America, the way you got ahead was through hard work and perseverance. You strove to…

    2 Comments
  • Makers and Menders

    I’ve been getting back into some research interests of mine that require data acquisition from a variety of sensors so…

  • Core Developer Practices

    Every field of engineering has a core set of practices that they follow and software engineering is no different. But…

    1 Comment
  • Still XP After All These Years

    Are you humming in your head Paul Simon’s “Still Crazy After All These Years”? I am. And it does seem crazy.

  • The Importance of Continuous Integration

    Perhaps the most important yet easiest to implement of all the software development practices in Agile is continuous…

  • The Importance of Technical Practices (Again)

    Software development has undergone many revolutions over the last few decades. The way we build software today is…

  • Summary of Seven Strategies Series

    I finished my “Seven Strategies” series of 72 blog posts with seven strategies for implementing each of the nine…

    1 Comment
  • Refactor to Learn What Not to Do

    One of the things that I was not expecting when I started refactoring other people’s code was that I started to see…

    4 Comments
  • Refactor to Clean Up Before Moving On

    Of course, the best time to refactor code is while it’s fresh in your mind, right after having worked with it. Once I…

Others also viewed

Explore content categories