The Single Responsibility Principle is about your code doing only 1 thing and you can split all functionality in several classes which all are meant for doing 1 specific thing.
An example is a specific class for validation, doing some business logic, enriching a model, retrieving data, updating data, navigation, etc.
The Separation of Concerns is about your code not being tightly coupled to some other classes/systems. Using interfaces in your code helps a lot, this way you can loosly couple classes/systems to you code. A plusside on this is that it's easier to unit-test your code also. There are a lot of (IoC) frameworks which can help you achieve this, but you can implement such a thing yourself also of course.
An example of something SoC, but not having SRP
public class Foo
{
private readonly IValidator _validator;
private readonly IDataRetriever _dataRetriever;
public Foo(IValidator validator, IDataRetriever dataRetriever)
{
_validator = validator;
_dataRetriever = dataRetriever;
}
public NavigationObject GetDataAndNavigateSomewhereIfValid()
{
var data = _dataRetriever.GetAllData();
if(_validator.IsAllDataValid(data))
{
object b = null;
foreach (var item in data.Items)
{
b = DoSomeFancyCalculations(item);
}
if(_validator.IsBusinessDataValid(b))
{
return ValidBusinessLogic();
}
}
return InvalidItems();
}
private object DoSomeFancyCalculations(object item)
{
return new object();
}
private NavigationObject ValidBusinessLogic()
{
return new NavigationObject();
}
private NavigationObject InvalidItems()
{
return new NavigationObject();
}
}
As you can see, this code isn't tightly coupled to classes or other systems, because it only uses some interfaces to do stuff. This is good from a SoC standpoint.
As you can see this class also contains 3 private methods which do some fancy stuff.
From a SRP standpoint, those methods should probably be placed within some classes of their own. 2 of them do something with navigation, which would fit in some INavigation class. The other does some fancy calculations on an item, this could probably be placed within an IBusinessLogic class.
Having something like this, you both have the SoC and SRP in place:
public class Foo
{
private readonly IValidator _validator;
private readonly IDataRetriever _dataRetriever;
private readonly IBusinessLogic _businessLogic;
private readonly INavigation _navigation;
public Foo(IValidator validator, IDataRetriever dataRetriever, IBusinessLogic businessLogic, INavigation navigation)
{
_validator = validator;
_dataRetriever = dataRetriever;
_businessLogic = businessLogic;
_navigation = navigation;
}
public NavigationObject GetDataAndNavigateSomewhereIfValid()
{
var data = _dataRetriever.GetAllData();
if(_validator.IsAllDataValid(data))
{
object b = null;
foreach (var item in data.Items)
{
b = _businessLogic.DoSomeFancyCalculations(item);
}
if(_validator.IsBusinessDataValid(b))
{
return _navigation.ValidBusinessLogic();
}
}
return _navigation.InvalidItems();
}
}
Of course you could debate if all this logic should be placed in the GetDataAndNavigateSomewhereIfValid
method. This is something you should decide for yourself. To me it looks like this method is doing way too much stuff.
I think that the SRP translates directly to the principles of orthogonal design and full normalization in relational databases.
If you recollect that SRP states that there there should never be more than one reason for a class to change then the analogy becomes immediately apparent.
However, whether the database should be split into multiple smaller databases is an orthogonal issue, which is more of interest for pracical reasons then logical.
Best Answer
They're two different principles. Pretty much the only thing they have in common is the word "single."
Single Source of Truth is the end result of the process of normalizing a database. Every piece of entity information is stored once, and only once.
Single Source of Truth explains why we put Customers in one table, and Products in another. By associating customers with products, using a CustomerProducts table, we avoid storing either customers or products in two different places, and instead put pointers in the CustomerProducts table that point to each customer and product. This also allows us to associate multiple customers with a product, and multiple products with a customer, without duplicating information such as the product name or its price.
Having a Single Source of Truth (each datum is stored in only one place) means that, when you change that datum, the entire system sees the same change at the same instant. Contrast that with multiple sources of truth, where you have to change the datum in all places where it is stored. Different parts of the system might see two different values for the same datum, at least temporarily.
Single Responsibility Principle (SRP) means that a class should only have one responsibility or one reason to change. The example that Fowler gives is that of a Modem class:
This class violates SRP, because it has two major responsibilities: establishing a connection, and sending data. To correct the problem, you would split the interface into two different interfaces: a connection interface, and a communication interface. The first interface would contain the dial and hangup methods, and the second interface would contain the send and receive methods.
SRP is not a law, but merely a principle. Sometimes SRP is violated for convenience or other reasons. The same is true of database normalization; sometimes data is kept in a denormalized form (includes some duplication) for performance or other reasons.
Persistence Ignorance is another form of SRP: a class should have no knowledge of how to save itself to a data store. That's not its responsibility; it's the responsibility of some other class. Were this not the case, you would have to change every class that uses the data store if you wanted to change the data store to some other type of data store.