Skip to main content

Better Software Design: Separation of Concerns

When I first learned computer programming, I thought I was a fine computer programmer. I produced much code that kind of worked; but looking back on it now I realize that the quality could have been much better. One of the important ideas I have learned since then is separation of concerns.
"We can solve any problem by introducing an extra level of indirection...except for the problem of too many levels of indirection." -Wheeler, et al.
Separation of concerns is the idea that any program that is even a little bit complicated has more than one concern, and that code for each of those concerns should be kept separate in the program. For example, we might write a program that asks a person's name, remembers it, and greets the user back by name. The naive way I would have written this when I started out might have been:
  1. Create a variable to store a person's name
  2. Display a message requesting the person's name
  3. Wait until the user has finished entering input
  4. Move data from user input into the prepared variable
  5. Put together a message greeting the user, getting the name out of the variable
  6. Display the prepared message
That basic sequence might be called business logic. The problem is that real programs are a little more complicated than that basic sequence of business logic. Let's say the first version used an old fashioned text only UI (user interface). The complete program might look like this: (notice the additions in bold)
  1. Create a variable to store a person's name
  2. Use the text only UI to display a message requesting the person's name
  3. Use the text only UI to wait until the user has finished entering input
  4. Use the text only UI to move data from user input into the prepared variable
  5. Put together a message greeting the user, getting the name out of the variable
  6. Use the text only UI to display the prepared message
This starts to be repetitive, but it might still make some sense...until we need to upgrade it. Let's say we discovered that we can use a new graphical UI to display messages and receive input. Using the graphical UI would require different code from the text only UI. Now the new version of the program would need to be:
  1. Create a variable to store a person's name
  2. Use the graphical UI to display a message requesting the person's name
  3. Use the graphical UI to wait until the user has finished entering input
  4. Use the graphical UI to move data from user input into the prepared variable
  5. Put together a message greeting the user, getting the name out of the variable
  6. Use the graphical UI to display the prepared message
Now we have a problem. And, the bigger the program becomes, the bigger problem becomes. Every time we need to use a feature like the UI we need to repeat or copy and paste duplicate code to every area of the program we need to do the same thing. If we want to change the way we use that feature, we must make the same kind of change repeatedly in many different places. As I soon found out as a beginning programmer, that makes it easy to have all kinds of bugs. That is why we need separation of concerns.

In a program, a common reusable feature like the UI is a concern. Each area of code in the program should only have one concern; and each concern should only be dealt with in one area of the program. A program with proper separation of concerns might look more like this:

With Separation of Concerns:
  1. When using the UI
    1. Version 1: use the text only UI
    2. Version 2: use the graphical UI
  2. Use this business logic:
    1. Create a variable to store a person's name
    2. Use the UI to display a message requesting the person's name
    3. Use the UI to wait until the user has finished entering input
    4. Use the UI to move data from user input into the prepared variable
    5. Put together a message greeting the user, getting the name out of the variable
    6. Use the UI to display the prepared message
As you can see, this code is more orderly compact, so if the actual code were very complicated, this arrangement might be easier to understand at a glance. Much smaller changes are required to upgrade from Version 1 to Version 2. This also makes the code much less likely to have bugs. User interfaces and business logic are only a few examples of many possible concerns that can benefit from separation.

However, separating software in this way is not always a good idea: if some code is already very simple and not likely to change, it might actually make it more complicated and therefore worse, to try to separate it into concerns. A good rule of thumb might be:
If you find yourself copying and pasting code, think twice and ask yourself whether this might be a good opportunity to improve the code by implementing separation of concerns.
It made me a much better programmer when I learned to understand these ideas and use them in programming.

Comments

Popular posts from this blog

Reality Checks to Demystify Buzzwords

As an IT insider, I feel I have something valuable to offer nontechnical people in terms of correcting misinformation. Here are a few simple tests for some popular buzzwords in tech. When evaluating a product or service, if you can honestly answer Yes to the reality check question, the buzzword probably truly applies. If the answer is No, it is probably fake. agile Does it make the developers happy? blockchain Does it cut out the middleman? cloud Does it automatically scale? microservice Does it only do one thing? object oriented Is it mostly made of interfaces? RESTful When requests arrive at a certain address, are they ready to use (without parsing)? unit test Does it prevent the tested code from touching anything outside itself?

The Importance of Direction

Which would you say is more important: getting somewhere faster, pushing something harder, or going the right direction? It should be obvious that no matter how much speed or power you use, that won't do any good if you're going the wrong direction. It could also be pointed out that early in a journey, even a small change in direction makes a big difference in where you end up. Therefore, we should make sure we have our direction correct, as the first priority.

How (Not) to Handle Different Exceptions

Came across this sample from a certain multi-billion-dollar company, purporting to show how to implement exception handling. I slightly changed a few cosmetic details to make it anonymous. try { // ... } catch (GeneralException e) { if (e instanceof SpecificExceptionA){ // ... } else if (e instanceof SpecificExceptionB){ // ... } } This is a true actual story--you can't make this stuff up. Yeah, I thought it was pretty hilarious; so I felt like I had to share it.