Separation of Concern vs Single Responsibility Principle ( SoC vs SRP )
These two great principals that stands on the base of many design and architecture decisions. We very often meet these principals in book, articles, blogs, etc... And main question which risen in my head was what they really all about and how they relate to each other? These two principles are totally discrete from each other or their core principle is the same?
Just to remember what these two principles means lets read following statements which defines the each of them:Separation of Concerns (SoC) – is the process of breaking a computer program into distinct features that overlap in functionality as little as possible. A concern is any piece of interest or focus in a program. Typically, concerns are synonymous with features or behaviors.
http://en.wikipedia.org/wiki/Separation_of_concernsSingle Responsibility Principle (SRP) – every object should have a single responsibility, and that all its services should be narrowly aligned with that responsibility. On some level Cohesion is considered as synonym for SRP.
http://en.wikipedia.org/wiki/Single_responsibility_principleFrom the first sight very simple and easy to understand. The principles really have a lot in common and in general they both talk about decoupling in distinct Logical Units with well defined Boundaries (responsibilities). Logical Unit and Boundaries could be very abstract or concrete, and the boundaries depend on the context of the problem which you are trying to solve.
The separation allows:
-
To allow people to work on individual pieces of the system in isolation;
-
To facilitate reusability;
-
To ensure the maintainability of a system;
-
To add new features easily;
-
To enable everyone to better understand the system;
-
Etc...;
-
What is really the boundary of the Responsibility that you are trying to separate?
-
What is really the boundary of the Concern that you are trying separate?
-
UserSettingsService - to set background
-
SecurityService - to check security
And of course, SoC is not limited to Architecture Layers,
it’s also applied on many other things, such as: an
object that could represent a concern from language point
view, SOA can separate concerns into services, separating
behaviour as concern in logical units, etc...
If to
discuss further about similarities, SRP mostly means the
same thing as SoC for layered architecture example.
However, SRP was re-interpreted by Uncle Bob
with the definition “THERE SHOULD NEVER BE MORE THAN ONE
REASON FOR A CLASS TO CHANGE”. By the definition, SRP was
narrowed down to class level.
The “narrowed” SRP definition also could leave a lot of questions, how we can make sure that our new class really has one responsibility and there is only one reason to change? Similar question we could raise for SoC… What is for sure is that is not one answer, but in general the answer is that there is not a Rule and all depends on the context of the problem. You can find an answer by yourself by answering next questions:
In real-world applications is mostly impossible to
implement an ideal solution, trying to solve by one
principle you can break another, such as YAGNI or over
design…
Is very important to notice that: do not
shift all the principles to extremes, because in real
cases is impossible to achieve them from all point of
views. So is very important to apply them from a certain
and most meaningful angle.
The principles on
certain level have similarities but on another level they
are different things, let’s find out it by an example.
Let’s suppose we have following user story, “user should be able set screen background color because
the color should be customizable for any logged on user,
so user access must be checked before color is set”.
Here is very raw implementation (just for demonstration purpose) of the requirement:
internal class UserSettingsService
{
public void SetBackgroundColor(ConsoleColor color)
{
CheckAccess();
Console.BackgroundColor = color;
Console.WriteLine("- Color is changed...");
}
private static void CheckAccess()
{
if (IsCurrentUserLogedIn())
{
throw new SecurityException("Can't change color."
+ "The User is not Authenticated in the system");
}
}
private static bool IsCurrentUserLogedIn()
{
return Thread.CurrentPrincipal.Identity.IsAuthenticated;
}
}
Main purpose of the SetBackgroundColor method is to
set new background color but before to set a new color we
check if the user has access. Security access checking is
encapsulated by CheckAccess method. After short
explanation, let’s go back to our lovely SoC and SRP, on
method level each method has its own concern and single
responsibility. However on class level they are not, the
class is far from to be a cohesive one, it encapsulates
Security checks and changing screen color logic. But what
if we need to do same check in another classes? then the
Check Access logic is duplicated OR we can change the
Check Access to public and use the class. Of course, both
ways are not the best practices.
Let’s do next step
of refactoring and separate each class with its own
responsibilities:
internal class UserSettingsService
{
public void SetBackgroundColor(ConsoleColor color)
{
SecurityService.CheckAccess();
Console.BackgroundColor = color;
Console.WriteLine("- Color is changed...");
}
}
internal class SecurityService
{
public static void CheckAccess()
{
if (IsCurrentUserLogedIn())
{
throw new SecurityException("Can't change color."
+ "The User is not Authenticated in the system");
}
}
private static bool IsCurrentUserLogedIn()
{
return Thread.CurrentPrincipal.Identity.IsAuthenticated;
}
}
Now the classes are separated so each class has its own responsibility:
which increases their reusability and therefore
maintainability.
So in the last example SRP is not
broken because each class has its own well defined
responsibility. From another perspective if we take the
security checks as infrastructure related concerns and
changing color as domain concerns then SoC is broken,
because set color invokes security checks instead just
setting the color. We can avoid pollution of the domain
logic with infrastructure stuff, by applying Virtual Proxy
Pattern which will wrap UserSettingsService class
and will perform security checks before “real”
SetBackgroundColor method is invoked.
The security checks such in the example above are
considered Cross-Cutting Concerns and that is why
AOP (Aspect Oriented Programming) was
invented for. AOP tries to separate such concerns in
separate component(s) and apply and reuse the component(s)
without introducing dependencies on the components making
easier maintenance.
Conclusion, the SRP and SoC
principles have something in common but in the same time
they have some differences, also they should be viewed as
an advice and not a rule, a developer should feel when and
how to apply and do abstract concerns and responsibilities
for a problem correctly.
[Note: I assume that provided
example could not be ideal or the best one but I hope at
least it shows my idea.]
Thank you,
Artur Trosin