Sign in to follow this  
Sappharos

The SRP

Recommended Posts

I'm trying to understand the Single Responsibility Principle - I've read up on a few articles (Object Mentor, Wikipedia etc.) but it seems purist, and impossible to apply to any practical situation. Obviously I need to change my way of thinking to grasp it.

For example, let's say I have a simple text-based game where scene state consists of several integer variables. I want to load these variables from file, and be able to change them during gameplay. Now, I would store these variables as private data in a single class, and use methods for file access and updating. According to my interpretation of [url="http://www.objectmentor.com/resources/articles/srp.pdf"]this article[/url], the resulting class has two responsibilities, or "axes of change" because its data can change for two reasons. This is apparently bad. So how should I split the responsibilities? Should I create a class devoted to file access, and/or a class devoted to reaching into the scene class and updating it? Doesn't this approach make the resulting code stupidly complex?

Share this post


Link to post
Share on other sites
SRP is about one module only providing one service as its interface. In your case, you aren't talking about multiple responsibilities - you're talking about multiple [i]consumers[/i] of a [i]single[/i] responsibility.

Consider std::string. I can use std::string in a million ways for a million different purposes - does that mean string violates SRP? Of course not! It still provides one fundamental service: it's a string.

Number of consumers is totally unrelated to the number of services offered. The point of SRP is not to try and control the consumer count (because you shouldn't even want to!) but instead to ensure that when I go to consume a service, I'm not talking to a module that also offers 12 other services.

Share this post


Link to post
Share on other sites
[quote name='ApochPiQ' timestamp='1311628309' post='4840198']
SRP is about one module only providing one service as its interface. In your case, you aren't talking about multiple responsibilities - you're talking about multiple [i]consumers[/i] of a [i]single[/i] responsibility.

Consider std::string. I can use std::string in a million ways for a million different purposes - does that mean string violates SRP? Of course not! It still provides one fundamental service: it's a string.

Number of consumers is totally unrelated to the number of services offered. The point of SRP is not to try and control the consumer count (because you shouldn't even want to!) but instead to ensure that when I go to consume a service, I'm not talking to a module that also offers 12 other services.
[/quote]

Thanks. :) To clarify: in the scene class and the std::string examples, what are the consumers and services? I'm a bit confused by the comparison.

Edit: I think I understand. In my example, the scene data is the service, and the methods such as LoadFromFile() and Update() are consumers. Bearing this in mind, the class does not need to be seperated. Is this correct?

Share this post


Link to post
Share on other sites
You should probably separate loading scenes from the scene representation.
Updating a scene is part of the public interface that defines responsibilities and makes a scene a reusable "service" in ApochiPiQ's terms.
Loading a scene from a file is one of many particular uses of he scene's public interface, and most users don't [i]want[/i] to know about it, as scenes could be populated in other ways (e.g. hardcoded for tests, procedurally, by combining stuff from other scenes, and so on) before being treated in the same way.

Share this post


Link to post
Share on other sites
[quote name='LorenzoGatti' timestamp='1311675416' post='4840438']
You should probably separate loading scenes from the scene representation.
Updating a scene is part of the public interface that defines responsibilities and makes a scene a reusable "service" in ApochiPiQ's terms.
Loading a scene from a file is one of many particular uses of he scene's public interface, and most users don't [i]want[/i] to know about it, as scenes could be populated in other ways (e.g. hardcoded for tests, procedurally, by combining stuff from other scenes, and so on) before being treated in the same way.
[/quote]

I've been thinking along similar lines: that I might want to use the scene without knowing about file access.
Are you recommending packaging the file I/O into a separate class or function which uses public method/s of Scene?

I was hoping that with such a simple example, there would be one correct approach which I could then extend to other situations...

Share this post


Link to post
Share on other sites
The SRP is an attempt to explain the [url="http://en.wikipedia.org/wiki/Class_invariant"]class invariant[/url].

Classes as syntax construct presented in OO-like languages have no actual meaning. They are just a keyword denoting something to compiler.

From OO perspective it means just that - classes should exist only and only to enforce class invariants. For everything else, they are redundant.


STL is a good example of such design. String class, for example. What does a string class need:[code]struct String {
char * characters;
int length;
int used.
};[/code]These three are a tuple that must be modified as a unit. We cannot modify 'length' without examining 'used' and reallocating 'characters'.

This class has single responsibility - it enforces the String Class invariant. Any methods that exist in such class will deal with that and that alone. Searching the string, for example, does not belong in it.


SRP then means the following. Identify those pieces of data that are interconnected and subject to invariants. Model the classes in such a way that each encapsulates precisely one.

Due to language design, many of popular OO languages today simply define Class as only primitive. In Java or C#, everything is an object, even when most do not need to be. This is mostly syntactic issue but it tends to distract from 'object as syntax declaraction' vs. 'object as encapsulated behavior'.

[quote]According to my interpretation of [url="http://www.objectmentor.com/resources/articles/srp.pdf"]this article[/url],[/quote]

ObjectMentor is a consultancy which sells training on OO and Agile design, mostly limited to Java. Their goal is not to improve any of them (that would put them out of business), their goal is to sell training. The more training they sell, the better they are. They are also authors of now infamous Agile design tutorial that resulting in a demonstration of how out-of-touch "best practices" when confronted with actual problem to solve.


The designs demonstrated in that article are same as everything in such materials. They make people nod but have next to no real world value since those that design them aren't interested in dealing with actual problems, but instead hammering the problem space into how they think it should look.

When designing OO, there is only one criteria - soundness. When completed, is the design sound with regard to problem being solved. In that article, violation of SRP has no meaning. If given classes are sound (they model the modem correctly), then design is correct.

As a side note, neither of the examples given and the solutions proposed are actually how good designs look in practice if actual domain knowledge is required. They just change the classes for sake of proving a point, not solving the problem or even analyzing the actual requirements (of which there aren't any).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this