Design Patterns: DRY

A while ago, I was working with a younger man and as I was doing a code review, I came across some code that looked kind of like this:

readColumnA () {
      columnA = columnReader("columnA");
      processColumn(columnA);
}

readColumnB () {
      columnB = columnReader("columnB");
      processColumn(columnB);
}

It isn’t really important what was in the file, or what the processing being done was.  These two methods are basically identical, the only difference is the value passed to columnReader.

I suggested that he change this code to look more like this:

columnProcessor (String columnName) {
      column = columnReader(columnName);
      processColumn(column);
}

Then, you could call it for each column you need to process.

When you remove duplication like this you are making your code DRY.  DRY stands for don’t repeat yourself.  In the first example you can see that we repeated the algorithm for processing the columns for each column we needed to process.  We can see that the only thing that changed was the column name, and extract that part out, and then have a generic method to process columns.

My colleague had heard of DRY, but thought that he shouldn’t use it here since he was pretty sure that we would change and want to process columnA differently than columnB in the future.  While this argument makes a certain amount of sense, we need to remember that we are not psychic, and while we can speculate on how a software project might evolve, we are never really sure.  The requirements and priorities change under our feet, and our guesses are often wrong.

In my opinion, and in my experience it is always better to keep your code clean because you want to be able to make changes easily.  If, at some point, in the example above, column A and column B processing diverge, then (and only then) you should change the code to accommodate this.

 

But we are “Agile”

I’ve heard that phrase many, many times.  Usually it’s used to justify not following the current processes, like mashing sizing and grooming together instead of having separate meetings, or making changes to a story after it’s partially (or fully) developed.

Developer:  The change you are asking for will require re-doing most of the development already done this sprint.  We’ll need a new story for this that we can work on in the next sprint

Product Owner (or any business lead):  But we’re agile, we should be able to make this change now.  You are already working in that part of the code…

It seems like being “Agile” is synonymous with not having to follow a defined process to some people.  In my opinion, this couldn’t be farther from the truth.  Agile works best when you strictly follow your process. Always, no exceptions, ever.  I think that’s worth repeating: Agile works best when you strictly follow your process. Always, no exceptions, ever.

Why?

Notice that it says your process. I’m not suggesting to follow some process in a book somewhere.  Follow the process Your Team created.  Assuming your team is following agile practices, the team has developed a very good process that works best for them, and is constantly reviewing and making improvements. If the business goes around the process, then the team is being robbed of the opportunity to improve it.

If having separate grooming and sizing meetings is too slow – isn’t it too slow for all of the other stories? If changes are needed after development is started, wouldn’t it be better to figure out why we have these late changes and how to avoid them?

It’s better to bring up the cases where the process is not working well and fix it for all stories/projects, not just the special ones.  If the process isn’t fixed, you’ll have to keep going around it every time you have tight timelines (or whatever the reason for breaking the process).

Agile works because it makes it very obvious when part of the process isn’t working well.  Everything is done in very short cycles – grooming, sizing, sprint planning, and retrospectives all happen every single sprint (if you are doing it “right”).  If it doesn’t work well, it doesn’t work well all the time.  People get tired of the process failing and will find a solution quickly.  If the pain is alleviated by not using the process, there is no motivation to fix it, so it stays broken.

My suggestion:

Follow YOUR process religiously.  If it doesn’t work well for something, fix the process, don’t avoid it.

Then, when this same type of issue happens again – your process will handle it. Sure, it might take a couple iterations to find a process that works, but you’ll be on the way to success.

 

Agile Mindset

High Cohesion

When I first started learning about object oriented programming, and really digging into the best practices, loose coupling and high cohesion kept cropping up.  I had a hard time trying to keep them straight and remember which one I wanted more of and which one I wanted to reduce.  My biggest difficulty was I couldn’t keep the definitions of coupling vs cohesion straight!

Coupling refers to how much a set of classes rely on one another.  If we have two classes, A and B that each use methods from the other, these classes would be tightly coupled.  If we have those same two classes and only one needs methods from the other, then those are more loosely coupled.

The little metal ends on a garden hose that you can twist together are called couplings.  You use them to join two pieces of hose together.  I like to use this to help me remember that coupling is about how two (or more) classes interact with one another.

Cohesion refers to how much the methods in a particular class belong together.  For example, let’s say we have a class representing a soup can.  The soup can should know about how big it is, what it is made out of, what shape it is and what color it is.  If we start adding information about the soup that is stored inside the can, then we are breaking the cohesion.  Information about the soup is not important to the actual can.  The information about the soup should be contained in a separate class that the can could know about.

Thinking about a cohesive group of people helps me remember what this means.  A cohesive group of people are people that work very well together and really seem to belong together, much the same way as a cohesive class design has methods that really belong together.

I have another post about coupling here.

High Cohesion

When we talk about cohesion, we are really talking about how well the ideas in a class or a data structure belong together.  I mention data structure  here because this principle can and should be used when designing database tables, or any data storage scheme, as well as when you are designing a class.  We are gong to focus on cohesion in code in this article.

Now that we have a better understanding of what cohesion means, why is it important?  Why should we worry about creating things that are really cohesive?  The program will work even if we throw a bunch of different concepts into one pile, right?

Technically, yes.  It is possible to write an entire application in one file.  And…you might even be able to hold all of the context of the application in your head at once while you are writing it.  Just because you can , doesn’t mean you should.

Why not put it all into one class?

There is a term for a class that ends up knowing too much about too many things…”god class”.  This is not the good kind of god, it is the spiteful, vengeful type of god, and you really don’t want to go creating them.

When you have a class that knows too much about too many things, it makes changing that class REALLY dangerous.

When a class knows too much, and does too many things, making a small change can impact many parts of the application, since it is likely used there too!  When we break things out into small classes, those classes are often used in fewer places, and their methods are very well defined.

Also, when everything is in one class, there is often a fear of touching that class.  We cannot understand everything that it is trying to do, so we don’t want to make a change that will cause unknown issues.  When we are afraid to touch classes, we don’t try to improve them, we just try to patch the hole and get out as quickly as possible.  This is not good for the overall health of our application, and is not good for our overall mental health.

 

Single Responsibility

High cohesion and the SRP (Single Responsibility Principle) go hand in hand.  When you design your classes, they should have one main purpose, one main reason to change.

Breaking your classes down this way not only means that each individual class will be changed less often, but it also helps us humans reason about the system as a whole.  Often systems are very complex, and contain a lot of concepts.  If we can break down the ideas into smaller and smaller parts, we can more easily understand these tiny parts, and can then build up our mental model much more easily.