Recently, I was asked which patterns and principles I would use in an OO-project.

As I started summing them up, I noticed the person who asked getting a StackOverflowException :) . Obviously, I had a lot to tell about the subject…
I’ll add a description (I’ll try to keep it short) to each one of them, but if you don’t know the meaning, just read the papers, blogs, or books. I’ll link to them (also check the titles, they may be links).

Feel free to add anything I forgot!

 

Single Responsibility principle (The S in SOLID principles)

This principle states an object should only have one responsibility. Why? So a class only has one reason to change. Why? Because when a class has several responsibilities, they become coupled. So? If you change one responsibility of the class, it could have consequences in the other responsibilities, so you have to retest all responsibilities.
It’s a bit confusing in the beginning to recognize a responsibility. Uncle Bob says a responsibility within SRP can be defined as a reason to change. That should get you started!

Open Closed principle (The O in SOLID principles)

The OCP states that software entities, should be open for extension, but closed for modification. What? You should be able to extend a SE without changing it. Why? If you don’t change it, you won’t break it. You will only have to test what you extended. How? Abstract away the functionality that could be implemented in different ways. If you have calculations, create an interface ICalculation, and add an implementation per calculationtype. The consequence is, that your calculation is closed for modification (a calculation calculates something and that’s it) but open for extension (if you have an addition, but also need a substraction, just add a class that implements ICalculation and you’re done). This is also a perfect example of the Strategy pattern.

Liskov Substitution principle (The L in SOLID principles)

This principle states that if you have a base class Base and two subclasses SubC and SubD, you should always be reffering to them as Base and not as their specific implementations SubC and SubD. What? Let’s get back to the calculation issue. If you have an AdditionCalculation and a SubstractionCalculation, you have to refer to both of them as Calculations. Why? Well, imagine, that apart from the Addition and Substraction calculation, you create a multiplication, a division, an exponent, … The code where you are referring to addition and substraction has to be modified to also know how to handle multiplications and divisions… Consequence => you’re code explodes to unreliable, unmaintanable, unreadable spaghetti… If you would have referred to addition and substraction as a calculation in the first place, you would have never need to make a modification.

Interface seggregation principle (The I in SOLID principles)

The ISP states that a client should not be forced to implement members they won’t use. I know this is a very common example of this principle, but since I’ve been personally confronted with it, I’m going to use it as clarification. Just take a look at it, and you’ll get the point :D  

Dependency Inversion principle (The D in SOLID principles)

This principle states that:
a) High level modules should not depend on low level modules, they both should depend on abtractions
b) Abstractions should not depend upon details, but the details upon the abstractions.

That’s a mouthfull.
Just imagine calculating a wage. Here in Belgium, we discount RSZ (social security) and taxes. Of course this is oversimplified for the sake of this example. The calculation of RSZ depends on your statute. The RSZ is always 13.07% of the bruto salary.
- for laborers, this percentage is applied to 108% of the bruto salary
- for employees it’s applied on 100% of your salary.
The WageCalculator, shouldn’t be making this distinction. Why? Well, reread SRP and OCP if you don’t know why… How? Well if you just pass a parameter IRszCalculator to the WageCalculator class, you can just call it’s Calculate method without worrying about the implementation. You can imagine that calculation a Wage is a bit more complicated than this, and eventually you can end up with a few parameters, including IRszCalculator. That’s where Dependency injection comes into the picture.
What? The client calling the Calculate method of the WageCalculator class, is now responsible for passing the correct IRszCalculation to the method, and when you’ve got several of these, the burden on the client grows. This can be solved with Dependency Injection. How? Several containers exist that resolve the dependencies needed by methods for you, such as Windsor, Unity, StructureMap, Spring.NET… How you do that, deserves it’s own post, but Davy already covered that one for me:
- Intro to Dependency Injection
- Intro to DI with Widsor

Chris Brandsma also gives a great overview of all DI-containers out there. Check it out.

Dry prinicple

DRY stands for Don’t repeat yourself. The goal of this principle, is to avoid repetitive code. In other words: copy and paste is forbidden. Why? I’ll just tell you a story.
A while ago, I was working on an existing codebase. I got a workitem assigned that told to fix an issue regarding the processing of incoming data. OK, no problemo! I fixed it, tested it, and it worked. I released a new version and got an angry e-mail. This issue isn’t fixed, the processing-bug is still there! I ran the processing method again, to check what was wrong. Nothing was wrong! Ok, let’s try again. Eventually, I called a business analyst by my side, to show that it DID work. We went through the steps to trigger the processing, and it worked. How can this be possible??? It doesn’t work for me!!! (Note the frustration and anger in my signs !!!). Finally I said: I don’t have magic hands, I promise. Do it yourself, and you’ll see it works too. He started the application, and started the processing. BA: You see? There it is! It doesn’t work!. Me: Could you please repeat what you just did? The BA repeated what he did, and again, there was the error. The way I triggered the processing, and the way he triggered it, was different… Normally that shouldn’t matter, but it was obvious that in this case, it did matter. I went back to my computer, opened the codebase, and confirmed what I already knew. The processing method was copied.
The DRY principle shouldn’t only be applied with code. Apply it in your DB, tests, documentation, …, thus in your whole system.
I rest my case.

YAGNI principle

I’ll tell you about this one with another story. Some time ago, I had the chance to work out a project on my own. I analyzed the domain and built up a model. The data I had to create, needed to satisfy a couple of rules, so I wrote them out in specifications. I created the data I needed, and compared it to my spec as a validation (Read more about using specifications for validation in the blue bible). I added tests that checked if my specs worked. All was good.
The tests passed, I had a great code coverage, and even the BA didn’t find functional bugs. Great! I had only one question. How healthy (or unhealthy) was my codebase? NDepend to the rescue. I performed an analysis, and everything looked OK. But then the results of a particular CQL query got my attention. Potentially unused methods = 2. How could that be?
After digging into my codebase (which you can do with a double click from NDepend!), I found out that 2 specs I wrote in the beginning, weren’t being used. They turned out to be unnecessary, and the problem I thought they would be solving, was handled in another way. They existed without a reason. So? Well, in this case I’m talking about two small spec-classes, but if you don’t keep an eye on this, it can result in a code bloat. I also had tests that covered the spec, so that’s -again- unecessary code to maintain.
This is what YAGNI aims to prevent. Don’t just write code you -think- you are going to need in the future. Only write code you need right now. If in the end you need the other code too, so be it. If not, you will not have waisted your time writing it, nor maintaining it.

Law of demeter

I’ll try to demonstrate this one with a bit of dummy code.
This code violates LoD:

public class Class1
{
	Class2 class2Instance = new Class2(); 

	public Class1()
	{
		// violates Law of Demeter since Class1 needs to access Class3 and does that trough Class2
		class2Instance.Class3.DoSomething();
	}
} 

public class Class2
{
	// we also need some serious information hiding here!
	public Class3 Class3 { get; set; }
} 

public class Class3
{
	public void DoSomething()
	{}
}

This is wrong because Class1 needs to know about the internal structure of class2 to be able to do something.

This code fixes the problem above:

public class Class1
{
	Class2 class2Instance = new Class2(); 

	public Class1()
	{
		// doesn't violate Law of Demeter since Class2 propagates Class1's request to Class3
		class2Instance.DoSomething();
	}
} 

public class Class2
{
	private Class3 Class3 { get; set; } 

	public void DoSomething()
	{
		Class3.DoSomething();
	}
} 

public class Class3
{
	public void DoSomething()
	{ }
}

Another solution could be:

public class Class1
{
	Class2 class2Instance = new Class2();
	Class3 class3Instance = new Class3(); 

	public Class1()
	{
		// doesn't violate Law of Demeter since Class2 directly calls Class3
		class3Instance.DoSomething();
	}
} 

public class Class2
{
} 

public class Class3
{
	public void DoSomething()
	{ }
}

You should decide what the best option is depending on the situation, of course.

Roundup

This turned about to be a longer post than I thought, sorry! But hey, I’m covering a lot of stuff here. I think I covered the most important principles when designing and developing an object oriented application. There’s a lot more information about this principles out there. My examples were pretty brief, and without lots of concrete examples. Just Google them, and you’ll find everything you need to know. If that’s not enough, read the Agile Principles, Patterns and Practices in C#. I havn’t read it yet, but plan to in the near future (it sure has some great reviews out there). I know it covers the topics I wrote about in this post, just take a look at the table of contents.

Share it:
  • Kick it!
  • DotNetShoutout
  • Technorati
  • DZone
  • TwitThis
  • Facebook
  • LinkedIn
  • del.icio.us
  • Digg
  • Reddit
  • Google
  • E-mail this story to a friend!