Fear of making changes to your system or difficulty in following code logic are signs that your legacy code has consistently violated the Separation of Concerns principle. The Separation of Concerns principle is a cornerstone of good engineering and a hallmark of using this principle is code that’s easy to read, easy to test, and easy to refactor. The Separation of Concerns principle is about creating stable, easily maintainable code, systems that won’t fall to pieces just because you made one little change (or even sweeping changes) somewhere. Code that is separated by layers is easier to automatically test, and automated tests make code even easier to refactor. Code that is effectively organized also allows more developers to work on a project without tripping over each other in source control, either by waiting to check out a file or puzzling through a change-comparison.

What is Separation of Concerns?

Separation of Concerns deals with organizing systems based on “concerns”, where a concern can be a functionality, purpose, responsibility, or any focus of attention that can be grouped together to form a cohesive unit. A concern can be thought of as a component which encapsulates other sub-components who are themselves separated by purpose and responsibility. On a broad scale, a component can be a separation of logical layers by purpose such as presentation, business logic, and data access. On a smaller scale, a component can be a class or method. Simplistically, it can be said that a component should have a single purpose with one and only one reason to change. For example, if you have a number of classes, html pages, and css files grouped as a presentation layer concern, then those classes, files, etc should only change for UI reasons and never need to change for other concerns such as a change in databases. On a more granular level within the presentation layer, you could separate content, format, and style concerns by grouping them into resource, html, and css files.

In another example, if you have a class that gets a person’s name from the database and arranges the order of the first, last, and middle names, then there are two reasons to change this component. You would need to change the class to change how it got data from the database and you would need to change the class to change the order of the names. If you separated these two purposes into a data access class that fetched the data and a presentation class that arranged the name order, then if one of the purposes needed a change, you would only need to modify one class.

The flip side of Separation of Concerns principle is that there should be one and only one place to make a change. By inherently incorporating the DRY (Don’t Repeat Yourself) principle, the Separation of Concerns principle reduces the amount of code that needs to be maintained. There’s a saying in server management: duplicate files are never duplicates for long. It seems like a matter of seconds after a file is copied before someone changes it and doesn’t synch it with their duplicate. The same is true for code duplication. It’s just too easy to miss one of the dupes while refactoring, then bugs are introduced. By using the Separation of Concerns principle you minimize the need to hunt down functionality all over your code in order to modify it.

Litmus test for the Separation of Concerns principle

Look at how much you would have to modify if you changed one thing. How tightly coupled are you to a coding approach? How deeply is the code embedded in the rest of the system? For example, if we changed from a web app to a desktop app (or vice versa), or changed from a relational database on a local server to an object-oriented database in the cloud, how much would have to change in the business logic layer?

How do you deal with cross cutting concerns?

Cross cutting concerns such as logging and validation are tough to deal with in static languages. They get embedded in all kinds of classes, cluttering up the code and making refactoring difficult. Aspect-oriented and dynamic programming languages can handle cross-cutting concerns better, but there are techniques you can use in static languages like C# to keep your code fairly clean. For example, you could create extension methods or decorate methods or classes with custom attributes. You could encapsulate validation within a utility class that can be called by the presentation, business logic, and persistence layers. Interceptors could be used to inject functionality into method calls. You could wrap IoC containers in a class in your solution so if you switched from say Castle Windsor to StructureMap, you could do it with a minimum of code changes.

Not a one-time decision

As you add new features and change functionality, be mindful of how components’ purposes are changing. A purpose may change or a clearer understanding of purpose may be discovered. As the system evolves, you may notice that some procedures you’ve created need to be refactored to be made less brittle. If you consistently maintain the Separation of Concerns principle, such refactoring is easy to do. Never add functionality to a method or class just because it’s already where you need the new function to act. If the new functionality serves a different purpose, write the extra lines of code to keep them separated.

That’s a problem for future Homer

The Separation of Concerns deals mostly with problems that may occur in the future. But how likely are those problems? How serious are they, really? Let’s explore some scenarios.

Are we really likely to change our system’s database?

Database migration was common years ago when you would start off an app with a cheap small-scale database like Access, then migrate to SQL Server or Sybase when you got bigger, then to Oracle when you get bigger yet. Once Microsoft and Oracle provided free entry-level databases and could scale, you didn’t have to do major refactoring because you could stick with the same vendor from small-scale to enterprise-scale. So for a few years, there really wasn’t a need to easily switch databases. Now there are more and more open source databases that provide stable enterprise platforms for free, so many organizations are switching from increasingly expensive database licenses to free open source databases. Some systems are changing from relational databases to object –oriented databases. More and more organizations are pushing the database to the cloud. It’s not just possible but probable that a system will need to change databases during its lifetime.

Who cares if I embed SQL statements in the button click events?

Ignoring the problems of the resulting code duplication, what if you find an easier way to access data like using Fluent NHibernate instead of SQL? What if you change databases and you need to change SQL syntax and data access code? It’ll be hard to track down all those changes if they’re splattered all over your code base, especially if they’re hidden in magic strings. Placing that plumbing in one location makes it easier to find and refactor later. Automated unit tests become easier to write, which makes refactoring even less stress in the future.

Are we really going to change a desktop app to a web app?

Cloud computing is the new hotness and everyone has a smartphone. Changing the front end of an application is an increasingly likely scenario and once the decision is made to convert, you’ll want your presentation logic as decoupled from your business and persistence logic as possible.

Can you carry the Separation of Concerns principle too far?

Yes. As with anything, extremes are dangerous and there is no ideal. Sometimes it’s difficult to fathom the “concern”, “purpose”, or “responsibility” of a component, let alone determine where boundaries lie. A purpose or responsibility can change simply by changing your point of view. It’s difficult to whittle down classes to bare bone functionality without creating spaghetti code.

As Edsger W. Dijkstra (who is credited with coining the phrase “separation of concerns” in 1971) explained in his paper “On the role of scientific thought”, adhering to this principle is not easy: “It is what I sometimes have called “the separation of concerns”, which, even if not perfectly possible, is yet the only available technique for effective ordering of one’s thoughts, that I know of. This is what I mean by “focusing one’s attention upon some aspect”: it does not mean ignoring the other aspects, it is just doing justice to the fact that from this aspect’s point of view, the other is irrelevant. It is being one- and multiple-track minded simultaneously.”

It is important to keep in mind that the Separation of Concerns principle is just that, a principle. Principles are broad strokes, not rigid and distinct directives. Having said that, the more time you spend thinking about business purposes and responsibilities and trying to achieve the ideal, even if you don’t “get it right” the first time, the better you’ll be able to quickly organize and refactor code, making you a better developer and more valuable asset to the company. Exercising your mind by looking at problems from different perspectives strengthens your general intelligence, and I would say, makes you a wiser person. Furthermore, absorbing the context and meaning for what you’re doing tends to make the job more enjoyable and rewarding.

Conclusion

Keep in mind that one reason most projects don’t make sweeping foundation changes, like user interfaces or vendor providers, is that they can’t. By decoupling your business logic from your persistence code, you give yourself the freedom to dump an expensive database vendor as your business grows. By separating presentation layer code from business logic, you can feasibly move your app off the desktop and into the web or onto a smart phone. At the end of the day, following the Separation of Concerns principle just makes your job as a developer easier and less stressful.

« »