A model .NET web service based on Domain Driven Design Part 2: DDD basics

Introduction

In the previous post we discussed how a traditional data access based layering can cause grief and sorrow. We’ll now move on to a better design and we’ll start with – what else – the domain layer. It is the heart of software, as Eric Evans put it, which should be the centre of the application. It should reflect our business entities and rules as close as possible. It will be an ever-evolving layer where you add, modify and remove bits of code as you get to know the domain better and better. The initial model will grow to a deep model with experimenting, brainstorming and knowledge crunching.

Before we dive into any code we have to discuss a couple of important terms. The domain layer is so important that an entire vocabulary has evolved around it. I promise to get to some real C# code after the theory.

Entities and value objects

Domain objects can be divided into entities and value objects.

An entity is an object with a unique ID. This unique ID is the most important property of an entity: it helps distinguish between two otherwise identical objects. We can have two people with the same name but if their IDs are different then we’re talking about two different people. Also, a person can change his/her name, but if the ID is the same then we know we’re talking about the same person. An ID is typically some integer or a GUID or some other string value randomly generated based on some properties of the object. Once the entity has been persisted, its ID should never change otherwise we lose track of it. In Sweden every legal person and company receives a personal registration number. Once you are given this ID it cannot be changed. From the point of view of the Swedish authorities this ID is my most important “property”. EntityA == EntityB if and only if EntityA.ID == EntityB.ID. Entities should ideally remain very clean POCO objects without any trace of technology-specific code. You may be tempted to add technology specific elements such s MVC attributes in here, e.g. [Required] or [StringLength(80)]. DON’T DO THAT. EVER! We’ll see later where they belong.

A value object on the other hand lacks any sort of ID. E.g. an office building may have 100 windows that look identical. Depending on your structure of the building you may not care which exact window is located where. Just grab whichever and mount it in the correct slot. In this case it’s futile to assign an ID to the window, you don’t care which one is which. Value objects are often used to group certain properties of an Entity. E.g. a Person entity can have an Address property which includes other properties such as Street and City. In your business an Address may well be a value object. In other cases, such as a postal company business, an Address will almost certainly be an Entity. A value object can absolutely have its own logic. Note that if you save value objects in the database it’s reasonable to assume that they will be assigned an automatic integer ID, but again – that’s an implementation detail that only concerns how our domain is represented in the storage, the domain layer doesn’t care, it will ignore the ID assigned by the data storage mechanism.

Sometimes it’s not easy to decide whether a specific object is an entity or a value object. If two objects have identical properties but we still need to distinguish between them then it’s most likely an entity with a unique ID. If two objects have identical properties and we don’t care which one is which: a value object. If the same object can be shared, e.g. the same Name can be attached to many Person objects: most likely a value object.

Aggregates and aggregate roots

Objects are seldom “independent”: they have other objects attached to them or are part of a larger object graph themselves. A Person object may have an Address object which in turn may have other Person objects if more than one person is registered there. It can be difficult to handle in software: if we delete a Person, then do we delete the Address as well? Then other Person objects registered there may be “homeless”. We can leave the Address in place, but then the DB may be full of empty, redundant addresses. Objects may therefore have a whole web of interdependency. Where does an object start and end? Where are its boundaries? There’s clearly a need to organise the domain objects into logical groups, so-called aggregates. An aggregate is a group of associated objects that are treated as a unit for the purpose of data changes. Every aggregate has a root and clear boundaries. The root is the only member of an aggregate that outside objects are allowed to hold references to.

Example

Take a Car object: it has a unique ID, e.g. the registration number to distinguish it from other cars. Each tire must also be measured somehow, but it’s unlikely that they will be treated separately from the car they belong to. It’s also unlikely that we make a DB search for a tire to see which car it belongs to. Therefore the Car is an aggregate root whose boundary includes the tires. Therefore consumers of the Car object should not be able to directly change the tire settings of the car. You may go as far as hiding the tires entirely within the Car aggregate and only let outside callers “get in touch with them” through methods such as “MoveCarForward”. The internal logic of the Car object may well modify the tires’ position, but to the outside world that is not visible.

An engine will probably also have a serial number and may be tracked independently of the car. It may happen that the engine is the root of its own aggregate and doesn’t lie within the boundaries of the Car, it depends on the domain model of the application.

Car aggregate root

An important term in conjunction with Aggregates is invariants. Invariants are consistency rules that must be maintained whenever data changes, so they represent business rules.

General guidelines for constructing the domain layer

Make sure that you allocate the best and most experienced developers available at your company to domain-related tasks. Often experienced programmers spend their time on exploring and testing new technologies, such as WebSockets. Entry-level programmers are then entrusted to construct the domain layer as technologically it’s not too difficult: write abstract and concrete classes, interfaces, methods, properties, that’s it really. Every developer should be able to construct these elements after completing a beginners’ course in C#. So people tend to think that this is an entry-level task. However, domain modelling and writing code in a loosely coupled and testable manner are no trivial tasks to accomplish.

Domains are the most important objects in Domain Driven Design. They are the objects that describe our business. They are so central that you should do your utmost to keep them clean, well organised and testable. It is worth building a separate Domain layer even during the mockup phase of a new project, even if you ignore the other layers. If you need to allocate time to maintain each layer within your solution then this layer should be allocated the most. This is important to keep in mind because you know how it usually goes with test projects – if management thinks it’s good then you often need to continue to build upon your initial design. There’s no time to build a better application because suddenly you are given a tight deadline. Then you’re stuck with a domain-less solution.

Domain objects should always be the ones that take priority. If you have to change the domain object to make room for some specific technology, then you’re taking the wrong direction. It is the technology that must fit the domain objects, not vice versa.

Domain objects are also void of persistence-related code making them technology agnostic or persistence ignorant. A Customer object will not care how it is stored in a database table, that is an irrelevant implementation detail.

Domain objects should be POCO and void of technology-specific attributes, such as the ones available in standard MVC, e.g. [Required]. Domain objects should be clear of all such ‘pollution’. Also, all logic specific to a domain must be included in the domain. These business rules contain validation rules as well, such as “the quantity should not be negative” or “a customer must not buy more than 5 units of this product”. Resist the temptation to write external files, such as CustomerHelper etc. where you put domain-specific logic, that’s not right. A domain is responsible to implement its specific domain logic. Example: in a banking application we may have an Account domain with a rule saying that the balance cannot be negative. You must include this validation logic within Account.cs, not in some other helper class. If the Account class has a complex validation logic then it’s fine to factor out the IMPLEMENTATION of the validation. i.e. the method body to a separate helper class. However, having a helper class that totally encapsulates domain validation and other domain-specific logic is the incorrect approach. Consumers of the domain will not be aware that there is some external class that they need to call. If domain specific logic is placed elsewhere then not even a visual inspection of the class file will reveal the domain logic to the consumer.

Make sure to include logic specific to a single domain object. Example: say you have an object called Observation with two properties of type double: min and max. If you want to calculate the average then Observation.cs will have a method called CalculateAverage and return the average of min and max, i.e. it performs logic on the level of a single domain object.

In the next post we’ll look at how these concepts can be written in code.

View the list of posts on Architecture and Patterns here.

A model .NET web service based on Domain Driven Design Part 1: introduction

Introduction

Layered architecture has been the norm in enterprise projects for quite some time now. We layer our solutions into groups of responsibilities: UI, services, data access, infrastructure and others. We can connect these layers by setting references to them from the consuming layer. There are various ways to set these layers and references. The choices you make here depend on the project type – Web, WPF, WCF, games etc. – you’re working on and the philosophy you follow.

On the one hand you may be very technology driven and base your choices primarily on the technologies available to build your project: Entity Framework, Ajax, MVC etc. Most programmers are like that and that’s natural. It’s a safe bet that you’ve become a developer because you’re interested in computers and computer-related technologies like video games and the Internet. It’s exciting to explore and test new technologies as they emerge: .NET, ORM, MVC, WebAPI, various JavaScript libraries, WebSockets, HighCharts, you name it. In fact, you find programming so enthralling that you would keep doing it for free, right? Just don’t tell your boss about it in the next salary review… With this approach it can happen in a layered architecture that the objects in your repository layer, i.e. the data access layer, such as an SQL Server database, will receive the top focus in your application. This is due to the popular ORM technologies available in .NET: EntityFramework and Linq to SQL. They generate classes based on some database representation of your domain objects. All other layers will depend on the data access layer. We’ll see an example of this below.

On the other hand you may put a different part of the application to the forefront: the domain. What is the domain? The domain describes your business. It is a collection of all concepts and logic that drive your enterprise. If you follow this type of philosophy, which is the essence of Domain Driven Design (DDD), then you give the domain layer the top priority. It will be the most important ingredient of the application. All other layers will depend on the domain layer. The domain layer will be an entirely independent one that can function on its own. The most important questions won’t be “How do we solve this with WebSockets?” or “How does it work with AngularJs?” but rather like these ones:

  • How does the Customer fit into our domain?
  • Have we modelled the Product domain correctly?
  • Is this logic part of the Product or the OrderItem domain?
  • Where do we put the pricing logic?

Technology-related questions will suddenly become implementation details where the exact implementation type can vary. We don’t really care which graph package we use: it’s an implementation detail. We don’t really care which ORM technology we use: it’s an implementation detail.

Of course technology-related concerns will be important aspects of the planning phase, but not as important as how to correctly represent our business in code.

In a technology-driven approach it can easily happen that the domain is given low priority and the technology choices will directly affect the domain: “We have to change the Customer domain because its structure doesn’t fit Linq to SQL”. In DDD the direction is reversed: “An important part of our Customer domain structure has changed so we need to update our Linq to SQL classes accordingly.”. A change in the technology should never force a change in your domain. Your domain is an independent entity that only changes if your business rules change or you discover that your domain logic doesn’t represent the true state of things.

Keep in mind that it is not the number of layers that makes your solution “modern”. You can easily layer your application in a way that it becomes a tightly coupled nightmare to work with and – almost – impossible to extend. If you do it correctly then you will get an application that is fun and easy to work with and is open to all sorts of extensions, even unanticipated ones. This last aspect is important to keep in mind. Nowadays customers’ expectations and wishlists change very often. You must have noticed that the days of waterfall graphs, where the the first version of the application may have rolled out months or even years after the initial specs were written, are over. Today we have a product release every week almost where we work closely with the customer on every increment we build in. Based on these product increments the customer can come with new demands and you better be prepared to react fast instead of having to rewrite large chunks of your code.

Goals of this series

I’ll start with stating what’s definitely not the goal: give a detailed account on all details and aspects of DDD. You can read all about DDD by its inventor Eric Evans in this book. It’s a book that discusses all areas of DDD you can think of. It’s no use regurgitating all of that in these posts. Also, building a model application which uses all concepts from DDD may easily grow into full-fledged enterprise application, such as SAP.

Instead, I’ll try to build the skeleton of a .NET solution that takes the most important ideas from DDD. The result of this skeleton will hopefully be a solution that you can learn from and even tweak it and use in your own project. Don’t feel constrained by this specific implementation – feel free to change it in a way that fits your philosophy.

However, if you’re completely new to DDD then you should still benefit from these posts as I’ll provide explanations for those key concepts. I’ll try to avoid giving you too much theory and rather concentrate on code but some background must be given in order to explain the key ideas. We’ll need to look at some key terms before providing any code. I’ll also refer to ideas from SOLID here and there – if you don’t understand this term then start here.

Also, it would be great to build the example application with TDD, but that would add a lot of noise to the main discussion. If you don’t know what TDD means, start here.

The ultimate goal is to end up with a skeleton solution with the following layers:

  • Infrastructure: infrastructure services to accommodate cross-cutting concerns
  • Data access (repository): data access and persistence technology layer, such as EntityFramework
  • Domain: the domain layer with our business entities and logic, the centre of the application
  • Application services: thin layer to provide actions for the consumer(s) such as a web or desktop app
  • Web: the ultimate consumer of the application whose only purpose is to show data and accept requests from the user

…where the layers communicate with each other in a loosely coupled manner through abstractions. It should be easy to replace an implementation with another. Of course writing a new version of – say – the repository layer is not a trivial task and layering won’t make it easier. However, the switch to the new implementation should go with as little pain as possible without the need to modify any of the other layers.

The Web layer implementation will actually be a web service layer using the Web API technology so that we don’t need to waste time on CSS and HTML. If you don’t know what Web API is about, make sure you understand the basics from this post.

UPDATE: the skeleton application is available for download on GitHub here.

Doing it wrong

Let’s take an application that is layered using the technology-driven approach. Imagine that you’ve been tasked with creating a web application that lists the customers of the company you work for. You know that layered architectures are the norm so you decide to build these 3 layers:

  • User Interface
  • Domain logic
  • Data access

You know more or less what the Customer domain looks like so you create the following table in SQL Server:

Customer table in SQL Server

Then you want to use the ORM capabilities of Visual Studio to create the Customer class for you using the Entity Framework Data Model Wizard. Alternatively you could go for a Linq to SQL project type, it doesn’t make any difference to our discussion. At this point you’re done with the first layer in your project, the data access one:

Entity Framework model context

EntityFramework has created a DbContext and the Customer class for us.

Next, you know that there’s logic attached to the Customer domain. In this example we want to refine the logic of what price reduction a customer receives when purchasing a product. Therefore you implement the Domain Logic Layer, a C# class library. To handle Customer-related queries you create a CustomerService class:

public class CustomerService
{
	private readonly ModelContext _objectContext;

	public CustomerService()
	{
		_objectContext = new ModelContext();
	}

	public IEnumerable<Customer> GetCustomers(decimal totalAmountSpent)
	{
		decimal priceDiscount = totalAmountSpent > 1000M ? .9m : 1m;
		List<Customer> allCustomers = (from c in _objectContext.Customers select c).ToList();
		return from c in allCustomers select new Customer()
		{
			Address = c.Address
			, DiscountGiven = c.DiscountGiven * priceDiscount
			, Id = c.Id
			, IsPreferred = c.IsPreferred
			, Name = c.Name
		};
	}
}

As you can see the final price discount depends also on the amount of money spent by the customer, not just the value currently stored in the database. So, that’s some extra logic that is now embedded in this CustomerService class. If you’re familiar with SOLID then the ‘_objectContext = new ModelContext();’ part immediately raises a warning flag for you. If not, then make sure to read about the Dependency Inversion Principle.

In order to make this work I had to add a library reference from the domain logic to the data access layer. I also had to add a reference to the EntityFramework library due to the following exception:

The type ‘System.Data.Entity.DbContext’ is defined in an assembly that is not referenced. You must add a reference to assembly ‘EntityFramework, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089’.

So I import the EntityFramework library into the DomainLogic layer to make the project compile.

At this point I have the following projects in the solution:

Data access and domain logic layer

The last layer to add is the UI layer, we’ll go with an MVC solution. The Index() method which lists all customers might look like the following:

public class HomeController : Controller
{
	public ActionResult Index()
	{
		decimal totalAmountSpent = 1000; //to be fetched with a different service, ignored here
		CustomerService customerService = new CustomerService();
		IEnumerable<Customer> customers = customerService.GetCustomers(totalAmountSpent);
		return View(customers);
	}	
}

In order to make this work I had to reference both the DomainLogic AND the DataAccess projects from the UI layer. I now have 3 layers in the solution:

DDD three layers

So I press F5 and… …get an exception:

“No connection string named ‘ModelContext’ could be found in the application config file.”

This exception is thrown at the following line within CustomerService.GetCustomers:

List<Customer> allCustomers = (from c in _objectContext.Customers select c).ToList();

The ModelContext object implicitly expects that a connection string called ModelContext is available in the web.config file. It was originally inserted into app.config of the DataAccess layer by the EntityFramework code generation tool. So a quick fix is to copy the connection string from this app.config to web.config of the web UI layer:

<connectionStrings> 
    <add name="ModelContext" connectionString="metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=mycomputer;initial catalog=Test;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
</connectionStrings>

Evaluation

Have we managed to build a “modern” layered application? Well, we certainly have layers, but they are tightly coupled. Both the UI and the Logic layer are strongly dependent on the DataAccess layer. Examples of tight coupling:

  • The HomeController/Index method constructs a CustomerService object
  • The HomeController/Index directly uses the Customer object from the DataAccess layer
  • The CustomerService constructs a new ModelContext object
  • The UI layer is forced to include an EntityFramework-specific connection string in its config file

At present we have the following dependency graph:

DDD wrong dependency graph

It’s immediately obvious that the UI layer can easily bypass any logic and consult the data access layer directly. It can read all customers from the database without applying the extra logic to determine the price discount.

Is it possible to replace the MVC layer with another UI type, say WPF? It certainly is, but it does not change the dependency graph at all. The WPF layer would also need to reference both the Logic and the DataAccess layers.

Is it possible to replace the data access layer? Say you’re done with object-relational databases and want to switch to file-based NoSql solutions such as MongoDb. Or you might want to move to a cloud and go with an Azure key-value type of storage. We don’t need to go as far as entirely changing the data storage mechanism. What if you only want to upgrade your technology Linq to SQL to EntityFramework? It can be done, but it will be a difficult process. Well, maybe not in this small example application, but imagine a real-world enterprise app with hundreds of domains where the layers are coupled to such a degree with all those references that removing the data access layer would cause the application to break down immediately.

The ultimate problem is that the entire domain model is defined in the data access layer. We’ve let the technology – EntityFramework – take over and it generated our domain objects based on some database representation of our business. It is an entirely acceptable solution to let an ORM technology help us with programming against a data storage mechanism in a strongly-typed object-oriented fashion. Who wants to work with DataReaders and SQL commands in a plain string format nowadays? However, letting some data access automation service take over our core business and permeate the rest of the application is far from desirable. The CustomerService constructor tightly couples the DomainLogic to EntityFramework. Since we need to reference the data access layer from within our UI even the MVC layer is coupled to EntityFramework. In case we need to change the storage mechanism or the domain logic layers we potentially have a considerable amount of painful rework to be done where you have to manually overwrite e.g. the Linq to SQL object context references to EntityFramework object context ones.

We have failed miserably in building a loosely coupled, composable application whose layers have a single responsibility. The domain layer, as stated in the introduction, should be the single most important layer in your application which is independent of all other layers – possibly with the exception of infrastructure services which we’ll look at in a later post in this series. Instead, now it is a technological data access layer which rules and where the domain logic layer is relegated to a second-class citizen which can be circumvented entirely.

The domain is at the heart of our business. It exists regardless of any technological details. If we sell cars, then we sell cars even if the car objects are stored in an XML file or in the cloud. It is a technological detail how our business is represented in the data storage. It is something that the Dev department needs to be concerned with. The business rules and domains have a lot higher priority than that: it is known to all departments of the company.

Another project type where you can easily confuse the roles of each layer is ASP.NET WebForms with its code behind. It’s very easy to put a lot of logic, database calls, validation etc. into the code-behind file. You’ll soon end up with the Smart UI anti-pattern where the UI is responsible for all business aspects of your application. Such a web application is difficult to compose, unit test and decouple. This doesn’t mean that you must forget WebForms entirely but use it wisely. Look into the Model-View-Presenter pattern, which is sort of MVC for WebForms, and then you’ll be fine.

So how can we better structure our layers? That will be the main topic of the series. However, we’ll need to lay the foundation for our understanding with some theory and terms which we’ll do in the next post.

View the list of posts on Architecture and Patterns here.

SOLID design principles in .NET: the Dependency Inversion Principle Part 5, Hello World revisited

Introduction

I realise that the previous post should have been the last one on the Dependency Inversion Principle but I decided to add one more, albeit a short one. It can be beneficial to look at one more example where we take a very easy starting point and expand it according to the guidelines we’ve looked at in this series.

The main source in the series on Dependency Injection is based on the work of Mark Seemann and his great book on DI.

Demo

The starting point of the exercise is the good old one-liner Hello World programme:

static void Main(string[] args)
{
	Console.WriteLine("Hello world");
}

Now that we’re fluent in DIP and SOLID we can immediately see a couple of flaws with this solution:

  • We can only write to the Console – if we want to write to a file then we’ll have to modify Main
  • We can only print Hello world to the console – we have to manually overwrite this bit of code if we want to print something else
  • We cannot easily extend this application in a sense that it lacks any seams that we discussed before – what if we want to add logging or security checks?

Let’s try to rectify these shortcomings. We’ll tackle the problem of message printing first. The Adapter pattern solves the issue by abstracting away the Print operation in an interface:

public interface ITextWriter
{
	void WriteText(string text);
}

We can then implement the Console-based solution as follows:

public class ConsoleTextWriter : ITextWriter
{
	public void WriteText(string text)
	{
		Console.WriteLine(text);
	}
}

Next let’s find a solution for collecting what the text writer needs to output. We’ll take the same approach and follow the adapter pattern:

public interface IMessageCollector
{
	string CollectMessageFromUser();
}

…with the corresponding Console-based implementation looking like this:

public class ConsoleMessageCollector : IMessageCollector
{
	public string CollectMessageFromUser()
	{
		Console.Write("Type your message to the world: ");
		return Console.ReadLine();
	}
}

These loose dependencies must be injected into another object, let’s call it PublicMessage:

public class PublicMessage
{
	private readonly IMessageCollector _messageCollector;
	private readonly ITextWriter _textWriter;

	public PublicMessage(IMessageCollector messageCollector, ITextWriter textWriter)
	{
		if (messageCollector == null) throw new ArgumentNullException("Message collector");
		if (textWriter == null) throw new ArgumentNullException("Text writer");
		_messageCollector = messageCollector;
		_textWriter = textWriter;
	}

	public void Shout()
	{
		string message = _messageCollector.CollectMessageFromUser();
		_textWriter.WriteText(message);
	}
}

You’ll realise some of the most basic techniques we’ve looked at in this series: constructor injection, guard clause, readonly private backing fields.

We can use these objects from Main as follows:

static void Main(string[] args)
{
	IMessageCollector messageCollector = new ConsoleMessageCollector();
	ITextWriter textWriter = new ConsoleTextWriter();
	PublicMessage publicMessage = new PublicMessage(messageCollector, textWriter);
	publicMessage.Shout();

	Console.ReadKey();
}

Now we’re free to inject any implementation of those interfaces: read from a database and print to file; read from a file and print to an email; read from the console and print to some web service. The PublicMessage class won’t care, it’s oblivious of the concrete implementations.

This solution is a lot more extensible. We can use the decorator pattern to add functionality to the text writer. Let’s say we want to add logging to the text writer through the following interface:

public interface ILogger
{
	void Log();
}

We can have some default implementation:

public class DefaultLogger : ILogger
{
	public void Log()
	{
		//implementation ignored
	}
}

We can wrap the text printing functionality within logging as follows:

public class LogWriter : ITextWriter
{
	private readonly ILogger _logger;
	private readonly ITextWriter _textWriter;

	public LogWriter(ILogger logger, ITextWriter textWriter)
	{
		if (logger == null) throw new ArgumentNullException("Logger");
		if (textWriter == null) throw new ArgumentNullException("TextWriter");
		_logger = logger;
		_textWriter = textWriter;
	}

	public void WriteText(string text)
	{
		_logger.Log();
		_textWriter.WriteText(text);
	}
}

In Main you can have the following:

static void Main(string[] args)
{
	IMessageCollector messageCollector = new ConsoleMessageCollector();
	ITextWriter textWriter = new LogWriter(new DefaultLogger(), new ConsoleTextWriter());
	PublicMessage publicMessage = new PublicMessage(messageCollector, textWriter);
	publicMessage.Shout();

	Console.ReadKey();
}

Notice that we didn’t have to do anything to PublicMessage. We passed in the interface dependencies as before and now we have the logging function included in message writing. Also, note that Main is tightly coupled to a range of objects, but it is acceptable in this case. We construct our objects in the entry point of the application, i.e. the composition root which is the correct place to do that. We don’t new up any dependencies within PublicMessage.

This was of course a very contrived example. We expanded the original code to a lot more complex solution with a lot higher overhead. However, real life applications, especially enterprise ones are infinitely more complicated where requirements change a lot. Customers are usually not sure what they want and wish to include new and updated features in the middle of the project. It’s vital for you as a programmer to be able to react quickly. Enabling loose coupling like that will make your life easier by not having to change several seemingly unrelated parts of your code.

View the list of posts on Architecture and Patterns here.

SOLID design principles in .NET: the Dependency Inversion Principle Part 4, Interception and conclusions

Introduction

I briefly mentioned the concept of Interception in the this post. It is a technique that can help you implement cross-cutting concerns such as logging, tracing, caching and other similar activities. Cross-cutting concerns include actions that are not strictly related to a specific domain but can potentially be called from many different objects. E.g. you may want to cache certain method results pretty much anywhere in your application so potentially you’ll need an ICacheService dependency in many places. In the post mentioned above I went through a possible DI pattern – ambient context – to implement such actions with all its pitfalls.

If you’re completely new to these concepts make sure you read through all the previous posts on DI in this series. I won’t repeat what was already explained before.

The idea behind Interception is quite simple. When a consumer calls a service you may wish to intercept that call and execute some action before and/or after the actual service is invoked.

It happens occasionally that I do the shopping on my way home from work. This is a real life example of interception: the true purpose of my action is to get home but I “intercept” that action with another one, namely buying some food. I can also do the shopping when I pick up my daughter from the kindergarten or when I want to go for a walk. So I intercept the main actions PickUpFromKindergarten() and GoForAWalk() with the shopping action because it is convenient to do so. The Shopping action can be injected into several other actions so in this case it may be considered as a Cross-Cutting Concern. Of course the shopping activity can be performed in itself as the main action, just like you can call a CacheService directly to cache something, in which case it too can be considered as the main action.

The main source in the series on Dependency Injection is based on the work of Mark Seemann and his great book on DI.

The problem

Say you have a service that looks up an object with an ID:

public interface IProductService
{
	Product GetProduct(int productId);
}
public class DefaultProductService : IProductService
{
	public Product GetProduct(int productId)
	{
		return new Product();
	}
}

Say you don’t want to look up this product every time so you decide to cache the result for 10 minutes.

Possible solutions

Total lack of DI

The first “solution” is to directly implement caching within the GetProduct method. Here I’m using the ObjectCache object located in the System.Runtime.Caching namespace:

public Product GetProduct(int productId)
{
	ObjectCache cache = MemoryCache.Default;
	string key = "product|" + productId;
	Product p = null;
	if (cache.Contains(key))
	{
		p = (Product)cache[key];
	}
	else
	{
		p = new Product();
		CacheItemPolicy policy = new CacheItemPolicy();
		DateTimeOffset dof = DateTimeOffset.Now.AddMinutes(10);
		policy.AbsoluteExpiration = dof;
		cache.Add(key, p, policy);
	}
	return p;
}

We check the cache using the cache key and retrieve the Product object if it’s available. Otherwise we simulate a database lookup and put the Product object in the cache with an absolute expiration of 10 minutes.

If you’ve read through the posts on DI and SOLID then you should know that this type of code has numerous pitfalls:

  • It is tightly coupled to the ObjectCache class
  • You cannot easily specify a different caching strategy – if you want to increase the caching time to 20 minutes then you’ll have to come back here and modify the method
  • The method signature does not tell anything to the caller about caching, so it violates the idea of an Intention Revealing Interface mentioned before
  • Therefore the caller will need to intimately know the internals of the GetProduct method
  • The method is difficult to test as it’s impossible to abstract away the caching logic. The test result will depend on the caching mechanism within the code so it will be inconclusive

Nevertheless you have probably encountered this style of coding quite often. There is nothing stopping you from writing code like that. It’s quick, it’s dirty, but it certainly works.

As an attempt to remedy the situation you can factor out the caching logic to a service:

public class SystemRuntimeCacheStorage
{
	public void Remove(string key)
	{
		ObjectCache cache = MemoryCache.Default;
		cache.Remove(key);
	}

	public void Store(string key, object data)
	{
		ObjectCache cache = MemoryCache.Default;
		cache.Add(key, data, null);
	}

	public void Store(string key, object data, DateTime absoluteExpiration, TimeSpan slidingExpiration)
	{
		ObjectCache cache = MemoryCache.Default;
		var policy = new CacheItemPolicy
		{
			AbsoluteExpiration = absoluteExpiration,
			SlidingExpiration = slidingExpiration
		};

		if (cache.Contains(key))
		{
			cache.Remove(key);
		}
		cache.Add(key, data, policy);
	}

	public T Retrieve<T>(string key)
	{
		ObjectCache cache = MemoryCache.Default;
		return cache.Contains(key) ? (T)cache[key] : default(T);
	}
}

This is a generic class to store, remove and retrieve objects of type T. As the next step you want to call this service from the DefaultProductService class as follows:

public class DefaultProductService : IProductService
{
	private SystemRuntimeCacheStorage _cacheStorage;

	public DefaultProductService()
	{
		_cacheStorage = new SystemRuntimeCacheStorage();
	}

	public Product GetProduct(int productId)
	{
		string key = "product|" + productId;
		Product p = _cacheStorage.Retrieve<Product>(key);
		if (p == null)
		{
        		p = new Product();
			_cacheStorage.Store(key, p);
		}
		return p;
	}
}

We’ve seen a similar example in the previous post where the consuming class constructs its own dependency. This “solution” has the same errors as the one above – it’s only the stacktrace that has changed. You’ll get the same faulty design with a factory as well. However, this was a step towards a loosely coupled solution.

Dependency injection

As you know by now abstractions are the way to go to reach loose coupling. We can factor out the caching logic into an interface:

public interface ICacheStorage
{
	void Remove(string key);
	void Store(string key, object data);
	void Store(string key, object data, DateTime absoluteExpiration, TimeSpan slidingExpiration);
	T Retrieve<T>(string key);
}

Then using constructor injection we can inject the caching mechanism as follows:

public class DefaultProductService : IProductService
{
	private readonly ICacheStorage _cacheStorage;

	public DefaultProductService(ICacheStorage cacheStorage)
	{
		_cacheStorage = cacheStorage;
	}

	public Product GetProduct(int productId)
	{
		string key = "product|" + productId;
		Product p = _cacheStorage.Retrieve<Product>(key);
		if (p == null)
		{
			p = new Product();
			_cacheStorage.Store(key, p);
		}
		return p;
	}
}

Now we can inject any type of concrete caching solution which implements the ICacheStorage interface. As far as tests are concerned you can inject an empty caching solution using the Null object pattern so that the test can concentrate on the true logic of the GetProduct method.

This is certainly a loosely coupled solution but you may need to inject similar interfaces to a potentially large number of services:

public ProductService(ICacheStorage cacheStorage, ILoggingService loggingService, IPerformanceService performanceService)
public CustomerService(ICacheStorage cacheStorage, ILoggingService loggingService, IPerformanceService performanceService)
public OrderService(ICacheStorage cacheStorage, ILoggingService loggingService, IPerformanceService performanceService)

These services will permeate your class structure. Also, you may create a base service for all services like this:

public ServiceBase(ICacheStorage cacheStorage, ILoggingService loggingService, IPerformanceService performanceService)

If all services must inherit this base class then they will start their lives with 3 abstract dependencies that they may not even need. Also, these dependencies don’t represent the true purpose of the services, they are only “sidekicks”.

Ambient context

For a discussion on this type of DI and when and why (not) to use it consult this post.

Interception using the Decorator pattern

The Decorator design pattern can be used as a do-it-yourself interception. The product service class can be reduced to its true purpose:

public class DefaultProductService : IProductService
	{		
		public Product GetProduct(int productId)
		{
			return new Product();
		}
	}

A cached product service might look as follows:

public class CachedProductService : IProductService
{
	private readonly IProductService _innerProductService;
	private readonly ICacheStorage _cacheStorage;

	public CachedProductService(IProductService innerProductService, ICacheStorage cacheStorage)
	{
		if (innerProductService == null) throw new ArgumentNullException("ProductService");
		if (cacheStorage == null) throw new ArgumentNullException("CacheStorage");
		_cacheStorage = cacheStorage;
		_innerProductService = innerProductService;
	}

	public Product GetProduct(int productId)
	{
		string key = "Product|" + productId;
		Product p = _cacheStorage.Retrieve<Product>(key);
		if (p == null)
		{
			p = _innerProductService.GetProduct(productId);
			_cacheStorage.Store(key, p);
		}

		return p;
	}
}

The cached product service itself implements IProductService and accepts another IProductService in its constructor. The injected product service will be used to retrieve the product in case the injected cache service cannot find it.

The consumer can actively use the cached implementation of the IProductService in place of the DefaultProductService class to deliberately call for caching. Here the call to retrieve a product is intercepted by caching. The cached service can concentrate on its task using the injected ICacheStorage object and delegates the actual product retrieval to the injected IProductService class.

You can imagine that it’s possible to write a logging decorator, a performance decorator etc., i.e. a decorator for any type of cross-cutting concern. You can even decorate the decorator to include logging AND caching. Here you see several applications of SOLID. You keep the product service clean so that it adheres to the Single Responsibility Principle. You extend its functionality through the cached product service decorator which is an application of the Open-Closed principle. And obviously injecting the dependencies through abstractions is an example of the Dependency Inversion Principle.

The Decorator is a well-tested pattern to implement interception in a highly flexible object-oriented way. You can implement a lot of decorators for different purposes and you will adhere to SOLID pretty well. However, imagine that in a large business application with hundreds of domains and hundreds of services you may potentially have to write hundreds of decorators. As each decorator executes one thing only to adhere to SRP you may need to implement 3-4 decorators for each service.

That’s a lot of code to write… This is actually a practical limitation of solely using this pattern in a large application to achieve interception: it’s extremely repetitive and time consuming.

Aspect oriented programming (AOP)

The idea behind AOP is strongly related to attributes in .NET. An example of an attribute in .NET is the following:

[PrincipalPermission(SecurityAction.Demand, Role = "Administrator")]
protected void Page_Load(object sender, EventArgs e)
{
}

This is also an example of interception. The PrincipalPermission attribute checks the role of the current principal before the decorated method can continue. In this case the ASP.NET page won’t load unless the principal has the Administrator role. I.e. the call to Page_Load is intercepted by this Security attribute.

The decorator pattern we saw above is an example of imperative coding. The attributes are an example of declarative interception. Applying attributes to declare aspects is a common technique in AOP. Imagine that instead of writing all those decorators by hand you could simply decorate your objects as follows:

[Cached]
[Logged]
[PerformanceChecked]
public class DefaultProductService : IProductService
{		
	public Product GetProduct(int productId)
	{
		return new Product();
	}
}

It looks attractive, right? Well, let’s see.

The PrincipalPermission attribute is special as it’s built into the .NET base class library (BCL) along with some other attributes. .NET understands this attribute and knows how to act upon it. However, there are no built-in attributes for caching and other cross-cutting concerns. So you’d need to implement your own aspects. That’s not too difficult; your custom attribute will need to derive from the System.Attribute base class. You can then decorate your classes with your custom attribute but .NET won’t understand how to act upon it. The code behind your implemented attribute won’t run just like that.

There are commercial products, like PostSharp, that enable you to write attributes that are acted upon. PostSharp carries out its job by modifying your code in the post-compilation step. The “normal” compilation runs first, e.g. by csc.exe and then PostSharp adds its post-compilation step by taking the code behind your custom attribute(s) and injecting it into the code compiled by csc.exe in the correct places.

This sounds enticing. At least it sounded to me like heaven when we tested AOP with PostSharp: we wanted to measure the execution time and save several values about the caller of some very important methods of a service. So we implemented our custom attributes and very extremely proud of ourselves. Well, until someone else on the team started using PostSharp in his own assembly. When I referenced his project in mine I suddenly kept getting these funny notices that I have to activate my PostSharp account… So what’s wrong with those aspects?

  • The code you write will be different from what will be executed as new code will be injected into the compiled one in the post-compilation step. This may be tricky in a debugging session
  • The vendors will be happy to provide helper tools for debugging which may or may not be included in the base price and push you towards an anti-pattern where you depend on certain external vendors – also a form of tight coupling
  • All attributes must have default parameterless constructors – it’s not easy to consume dependencies from within an attribute. Your best bet is using ambient context – or abandon DI and go with default implementations of the dependencies
  • It can be difficult to fine-grain the rules when to apply an aspect. You may want to go with a convention-based applicability such as “apply the aspect on all objects whose name ends with ‘_log'”
  • The aspect itself is not an abstraction; it’s not straightforward to inject different implementations of an aspect – therefore if you decide to go with the System.Runtime.Cache in your attribute implementation then you cannot change your mind afterwards. You cannot implement a factory or any other mechanism to inject a certain aspect in place of some abstract aspect as there’s no such thing

This last point is probably the most serious one. It pulls you towards the dreaded tight-coupling scenario where you cannot easily redistribute a class or a module due to the concrete dependency introduced by an aspect. If you consume such an external library, like in the example I gave you, then you’re stuck with one implementation – and you better make sure you have access to the correct credentials to use that unwanted dependency…

Dynamic interception with a DI container

We briefly mentioned DI containers, or IoC containers in this series. You may be familiar with some of them, such as StructureMap and CastleWindsor. I won’t get into any details regarding those tools. There are numerous tutorials available on the net to get you started. As you get more and more exposed to SOLID in your projects then eventually you’ll most likely become familiar with at least one of them.

Dynamic interception makes use of the ability of .NET to dynamically emit types. Some DI containers enable you to automate the generation of decorators to be emitted straight into a running process.

This approach is fully object-oriented and helps you avoid the shortcomings of AOP attributes listed above. You can register your own decorators with the IoC container, you don’t need to rely on a default one.

If you are new to DI containers then make sure you understand the basics before you go down the dynamic interception route. I won’t show you any code here on how to implement this technique as it depends on the type of IoC container of your choosing. The key steps as far as CastleWindsor is concerned are as follows:

  • Implement the IInterceptor interface for your decorator
  • Register the interceptor with the container
  • Activate the interceptor by implementing the IModelInterceptorsSelector interface – this is the step where you declare when and where the interceptors will be invoked
  • Register the class that implements the IModelInterceptorsSelector interface with the container

Carefully following these steps will ensure that you can implement dynamic interception without the need for attributes. Note that not all IoC containers come with the feature of dynamic interception.

Conclusions

In this mini-series on DI within the series about SOLID I hope to have explained the basics of the Dependency Inversion Principle. This last constituent of SOLID is probably the one that has caused the most controversy and misunderstanding of the 5. Ask 10 developers on the purposes of DIP and you’ll get 11 different answers. You may absolutely have come across ideas in these posts that you disagree with – feel free to comment in that case.

However, I think there are several myths and misunderstandings about DI and DIP that were successfully dismissed:

  • DI is the same as IoC containers: no, IoC containers can automate DI but you can by any means apply DI in your code without a tool like that
  • DI can be solved with factories: look at the post on DI anti-patterns and you’ll laugh at this idea
  • DI requires an IoC containers: see the first point, this is absolutely false
  • DI is only necessary if you want to enable unit testing: no, DI has several advantages as we saw, effective unit testing being only one of them
  • Interception is best done with AOP: no, see above
  • Using an IoC container will automatically result in DI: no, you have to prepare your code according to the DI patterns otherwise an IoC container will have nothing to inject

View the list of posts on Architecture and Patterns here.

SOLID design principles in .NET: the Dependency Inversion Principle Part 3, DI anti-patterns

In the previous post we discussed the various techniques how to implement Dependency Injection. Now it’s time to show how NOT to do DI. Therefore we’ll look at a couple of anti-patterns in this post.

The main source in the series on Dependency Injection is based on the work of Mark Seemann and his great book on DI.

Lack of DI

The most obvious DI anti-patterns is the total absence of it where the class controls it dependencies. It is the most common anti-pattern in DI to see code like this:

public class ProductService
{
	private ProductRepository _productRepository;

	public ProductService()
	{
		_productRepository = new ProductRepository();
	}
}

Here the consumer class, i.e. ProductService, creates an instance of the ProductRepository class with the ‘new’ keyword. Thereby it directly controls the lifetime of the dependency. There’s no attempt to introduce an abstraction and the client has no way of introducing another type – implementation – for the dependency.

.NET languages, and certainly other similar platforms as well, make this extremely easy for the programmer. There is no automatic SOLID checking in Visual Studio, and why would there be such a mechanism? We want to give as much freedom to the programmer as possible, so they can pick – or even mix – C#, VB, F#, C++ etc., write in an object-oriented way or follow some other style, so there’s a high degree of control given to them within the framework. So it feels natural to new up objects as much as we like: if I need something I’ll need to go and get it. If the ProductService needs a product repository then it will need to fetch one. So even experienced programmers who know SOLID and DI inside out can fall into this trap from time to time, simply because it’s easy and programming against abstractions means more work and a higher degree of complexity.

The first step towards salvation may be to declare the private field as an abstract type and mark it as readonly:

public class ProductService
{
	private readonly IProductRepository _productRepository;

	public ProductService()
	{
		_productRepository = new ProductRepository();
	}
}

However, not much is gained here yet, as at runtime _productRepository will always be a new ProductRepository.

A common, but very wrong way of trying to resolve the dependency is by using some Factory. Factories are an extremely popular pattern and they seem to be the solution to just about anything – besides copy/paste of course. I’m half expecting Bruce Willis to save the world in Die Hard 27 by applying the static factory pattern. So no wonder people are trying to solve DI with it too. You can see from the post on factories that they come in 3 forms: abstract, static and concrete.

The “solution” with the concrete factory may look like this:

public class ProductRepositoryFactory
{
	public ProductRepository Create()
	{
		return new ProductRepository();
	}
}
public ProductService()
{
	ProductRepositoryFactory factory = new ProductRepositoryFactory();
	_productRepository = factory.Create();
}

Great, we’re now depending directly on ProductRepositoryFactory and ProductRepository is still hard-coded within the factory. So instead of just one hard dependency we now have two, well done!

What about a static factory?

public class ProductRepositoryFactory
{
	public static ProductRepository Create()
	{
		return new ProductRepository();
	}
}
public ProductService()
{
	_productRepository = ProductRepositoryFactory.Create();
}

We’ve got rid of the ‘new’, yaaay! Well, no, if you recall from the introduction using static methods still creates a hard dependency, so ProductService still depends directly on ProductRepositoryFactory and indirectly on ProductRepository.

To make matters worse the static factory can be misused to produce a sense of freedom to the client to control the type of dependency as follows:

public class ProductRepositoryFactory
{
	public static IProductRepository Create(string repositoryTypeDescription)
	{
		switch (repositoryTypeDescription)
		{
			case "default":
				return new ProductRepository();
			case "test":
				return new TestProductRepository();
			default:
				throw new NotImplementedException();
		}
	}
}
public ProductService()
{
	_productRepository = ProductRepositoryFactory.Create("default");
}

Oh, brother, this is a real mess. ProductService still depends on the ProductRespositoryFactory class, so we haven’t eliminated that. It is now indirectly dependent on the two concrete repo types returned by factory. Also, we now have magic strings flying around. If we ever introduce a third type of repository then we’ll need to revisit the factory and inform all actors that there’s a new magic string. This model is very difficult to extend. The ability to configure in code, or possibly in a config file, gives a false sense of security to the developer.

You can create a mock Product repository for a unit test scenario, extend the switch-case statement in the factory and maybe introduce a new magic string “mock” only for testing purposes. Then you can put “mock” in the Create method, recompile and run your test just for unit testing. Then you forget to put it back to “sql” or whatever and deploy the solution… Realising this you may want to overload the ProductService constructor like this:

public ProductService(string productRepoDescription)
{
	_productRepository = ProductRepositoryFactory.Create(productRepoDescription);
}

That only moves the magic string problem up the stacktrace but does nothing to solve the dependency problems outlined above.

Let’s look at an abstract factory:

public interface IProductRepositoryFactory
{
	IProductRepository Create(string repoDescription);
}

ProductRepositoryFactory can implement this interface:

public class ProductRepositoryFactory : IProductRepositoryFactory
{
	public IProductRepository Create(string repositoryTypeDescription)
	{
		switch (repositoryTypeDescription)
		{
			case "default":
				return new ProductRepository();
			case "test":
				return new TestProductRepository();
			default:
				throw new NotImplementedException();
		}
	}
}

You can use it from ProductService as follows:

private IProductRepositoryFactory _productRepositoryFactory;
private IProductRepository _productRepository;

public ProductService(string productRepoDescription)
{
	_productRepositoryFactory = new ProductRepositoryFactory();
	_productRepository = _productRepositoryFactory.Create(productRepoDescription);
}

We need to new up a ProductRepositoryFactory, so we’re back at square one. However, abstract factory is still the least harmful of the factory patterns when trying to solve DI as we can refactor this code in the following way:

private readonly IProductRepository _productRepository;

public ProductService(string productRepoDescription, IProductRepositoryFactory productRepositoryFactory)
{
	_productRepository = productRepositoryFactory.Create(productRepoDescription);
}

This is not THAT bad. We can provide any type of factory now but we still need to provide a magic string. A way of getting rid of that string would be to create specialised methods within the factory as follows:

public interface IProductRepositoryFactory
{
	IProductRepository Create(string repoDescription);
	IProductRepository CreateTestRepository();
	IProductRepository CreateSqlRepository();
	IProductRepository CreateMongoDbRepository();
}

…with ProductService using it like this:

private readonly IProductRepository _productRepository;

public ProductService(IProductRepositoryFactory productRepositoryFactory)
{
	_productRepository = productRepositoryFactory.CreateMongoDbRepository();
}

This is starting to look like proper DI. We can inject our own version of the factory and then pick the method that returns the necessary repository type. However, this is a false positive impression again. The ProductService still controls the type of repository returned by the factory. If we wanted to test the SQL repo then we have to revisit the product service – and all other services that need a repository – and select CreateSqlRepository() instead. Same goes for unit testing. You can certainly create a mock repository factory but you’ll need to make sure that the mock implementation returns mock objects for all repository types the factory returns. That breaks ISP in SOLID.

No, even in the above case the caller cannot control type of IProductRepository used within ProductRepository. You can certainly control the concrete implementation of IProductRepositoryFactory, but that’s not enough.

Conclusion: factories are great for purposes other than DI. Use one of the strategies outlined in the previous post.

Lack of DI creates tightly coupled classes where one cannot exist without the other. You cannot redistribute the ProductService class without the concrete ProductRepository so it diminishes re-usability.

Overloaded constructors

Consider the following code:

private readonly IProductRepository _productRepository;

public ProductService() : this(new ProductRepository())
{}

public ProductService(IProductRepository productRepository)
{
        _productRepository = productRepository;
}

It’s great that we have can inject an IProductRepository but what’s the default constructor doing there? It simply calls the overloaded one with a concrete implementation of the repository interface. There you are, we’ve just introduced a completely unnecessary coupling. Matters get worse if the default implementation comes from an external source such as a factory seen above:

private readonly IProductRepository _productRepository;

public ProductService() : this(new ProductRepositoryFactory().Create("sql"))
{}

public ProductService(IProductRepository productRepository)
{
	_productRepository = productRepository;
}

By now you know why factories are not suitable for solving DI so I won’t repeat myself. Even if clients always call the overloaded constructor the class still cannot exist without either the ProductRepository or the ProductRepositoryFactory class.

The solution is easy: get rid of the default constructor and force clients to provide their own implementations.

Service locator

I’ve already written a post on this available here, so I won’t repeat the whole post. In short: a Service Locator resembles a proper IoC container such as StructureMap but it introduces easily avoidable couplings between objects.

Conclusion

We’ve discussed some of the ways how not to do DI. There may certainly be more of those but these are probably the most frequent ones. The most important variant to get rid of is the lack of DI which is exacerbated by the use of factories. That’s also the easiest to spot – look for the ‘new’ keyword in conjunction with dependencies.

The use of static method and properties can also be indicators of DIP violation:

DateTime.Now.ToString();
DataAccess.SaveCustomer(customer);
ProductRepositoryFactory.Create("sql");

We’ve seen especially in the case of factories that static methods and factories only place the dependencies one step down the execution ladder. Static methods are acceptable if they don’t themselves have concrete dependencies but only use the parameters already used by the object that’s calling the static method. However, if those static methods new up other dependencies which in turn may instantiate their own dependencies then that will quickly become a tightly coupled nightmare.

View the list of posts on Architecture and Patterns here.

SOLID design principles in .NET: the Interface Segregation Principle

Introduction

The Interface Segregation Principle (ISP) states that clients should not be forced to depend on interfaces they do not use. ISP is about breaking down big fat master-interfaces to more specialised and cohesive ones that group related functionality. Imagine that your class needs some functionality from an interface but not all. If you have no direct access to that interface then all you can do is to implement the relevant bits and ignore the methods that are not relevant for your class.

The opposite is that an interface grows to allow for more functionality where there’s a chance that some methods in the interface are not related, e.g. CalculateArea() and DoTheShopping(). All implementing classes will of course need to implement all methods in the interface where the unnecessary ones may only have a throw new NotImplementedException as their method body.

For the caller this won’t be obvious:

Person.DoTheShopping();
Neighbour.DoTheShopping();

Triangle.CalculateArea();
Square.CalculateArea();

These look perfectly reasonable, right? However, if the interface they implement looks like this…:

public interface IMasterInterface
{
    void DoTheShopping();
    double CalculateArea();
}

…then the client may as well make the following method calls:

Person.CalculateArea();
Triangle.DoTheShopping();

…where the true implementations will probably throw a NotImplementedException or will have an empty body or return some default value such as 0 at best. Also, if you loop through an enumeration of IMasterInterface objects then the caller expects to be able to simply call the CalculateArea() on every object in the list adhering to the LSP principle of the previous post. Then they will see exceptions thrown or inexplicable 0’s returned where the method does not apply.

The above example is probably too extreme, nobody would do anything like that in real code I hope. However, there are more subtle differences between two ‘almost related’ objects than between a Person and a Triangle as we’ll see in the demo.

Often such master interfaces are a result of a growing domain where more and more properties and behaviour are assigned to the domain objects without giving much thought to the true hierarchy between classes. Adhering to ISP will often result in small interfaces with only 1-3 methods that concentrate on some very specific tasks. This helps you create subclasses that only implement those interfaces that are meaningful to them.

Big fat interfaces – and abstract base classes for that matter – therefore introduce unnecessary dependencies. Unnecessary dependencies in turn reduce the cohesion, flexibility and maintainability of your classes and increase the coupling between dependencies.

Demo

We’ll simulate a movie rental where movies can be rented in two formats: DVD and BluRay. The domain expert correctly recognises that these are indeed related products that both can implement the IProduct interface. Open Visual Studio, create a new Console app and add the following interface:

public interface IProduct
{
	decimal Price { get; set; }
	double Weight { get; set; }
	int Stock { get; set; }
        int AgeLimit { get; set; }
	int RunningTime { get; set; }
}

Here I take the interface approach but it’s perfectly reasonable to follow an approach based on an abstract base class instead, such as ProductBase.

The following two classes implement the interface:

public class DVD : IProduct
{
	public decimal Price { get; set; }
	public double Weight { get; set; }
	public int Stock { get; set; }
        int AgeLimit { get; set; }
	public int RunningTime { get; set; }
}
public class BluRay : IProduct
{
	public decimal Price { get; set; }
	public double Weight { get; set; }
	public int Stock { get; set; }
        int AgeLimit { get; set; }
	public int RunningTime { get; set; }
}

All is well so far, right? Now management comes along and says that they want to start selling T-Shirts with movie stars printed on them so the new product is more or less related to the main business. The programmer first thinks it’s probably just OK to implement the IProduct interface again:

public class TShirt : IProduct
{
	public decimal Price { get; set; }
	public double Weight { get; set; }
	public int Stock { get; set; }
        int AgeLimit { get; set; }
	public int RunningTime { get; set; }
}

Price, stock and weight are definitely relevant to the TShirt domain. Age limit? Not so sure… Running time? Definitely not. However, it’s still there and can be set even if it doesn’t make any sense. Also, the programmer may want to extend the TShirt class with the Size property so he adds this property to the IProduct interface. The DVD and BluRay classes will then also need to implement this property, but does it make sense to store the size of a DVD? Well, maybe it does, but it’s not the same thing as the size of a TShirt. The TShirt size may be a string, such as “XL” or an enumeration, e.g. Size.XL, but the size of a DVD is more complex. It is more likely to be a dimension with 3 values: width, length and depth. So the type of the Size property will be different. Setting the type to Object is a quick fix but it’s a horrendous crime against OOP I think.

The solution is to break up the IProduct interface into two smaller ones:

public interface IProduct
{
	decimal Price { get; set; }
	double Weight { get; set; }
	int Stock { get; set; }
}

The IProduct interface still fits the DVD and BluRay objects and it fits the new TShirt interface as well. The RunningTime property is only relevant to movie-related objects:

public interface IMovie
{
	int RunningTime { get; set; }
}

BluRay and DVD implement both interfaces:

public class BluRay : IProduct, IMovie
{
	public decimal Price { get; set; }
	public double Weight { get; set; }
	public int Stock { get; set; }
	public int RunningTime { get; set; }
}
public class DVD : IProduct, IMovie
{
	public decimal Price { get; set; }
	public double Weight { get; set; }
	public int Stock { get; set; }
	public int RunningTime { get; set; }
}

Now you can have a list of IProduct objects and call the Price property on all of them. You won’t have access to the RunningTime property which is a good thing. By default it will be 0 for all TShirt objects so you could probably get away with that in this specific scenario, but it still goes against ISP. As soon as you’re dealing with IMovie objects then the RunningTime property makes perfect sense.

A slightly different solution after breaking out the IMovie interface is that IMovie implements the IProduct interface:

public interface IMovie : IProduct
{
	int RunningTime { get; set; }
}

We can change the implementing objects as follows:

public class TShirt : IProduct
{
	public decimal Price { get; set; }
	public double Weight { get; set; }
	public int Stock { get; set; }
}
public class BluRay : IMovie
{
	public decimal Price { get; set; }
	public double Weight { get; set; }
	public int Stock { get; set; }
	public int RunningTime { get; set; }
}
public class DVD : IMovie
{
	public double Weight { get; set; }
	public int Stock { get; set; }
	public int RunningTime { get; set; }
	public decimal Price { get; set; }
}

So the DVD and BluRay classes are still of IProduct types as well because the IMovie interface implements it.

A real life example

If you’ve worked with ASP.NET then you must have come across the MembershipProvider object in the System.Web.Security namespace. It is used within .NET for built-in membership providers such as SqlMembershipProvider which provides functions to create new users, authenticate your users, lock them out, update their passwords and much more. If the built-in membership types are not suitable for your purposes then you can create your own custom membership mechanism by implementing the MembershipProvider abstraction:

public class CustomMembershipProvider : MembershipProvider

I won’t show the implemented version because it’s too long. MembershipProvider forces you to implement a whole range of methods, e.g.:

public override bool ChangePassword(string username, string oldPassword, string newPassword)
public override bool DeleteUser(string username, bool deleteAllRelatedData)
public override bool EnablePasswordRetrieval
public override int MinRequiredPasswordLength

At the time of writing this post MembershipProvider includes 27 methods and properties for you to implement. It has been criticised due to its size and the fact that if you only need half of the methods then the rest will throw the dreaded NotImplementedException. If you’re building a custom Login control then all you might be interested in is the following method:

public override bool ValidateUser(string username, string password)

At best you can provide some null objects to quietly ignore the unnecessary methods but it may be confusing to the callers that expect a reasonable result from a method.

An alternative solution in cases where you don’t own the code is to follow the Adapter pattern to hide the unnecessary parts in the original abstraction.

View the list of posts on Architecture and Patterns here.

SOLID design principles in .NET: the Liskov Substitution Principle

Introduction

After visiting the letters ‘S‘ and ‘O‘ in SOLID it’s time to discuss what ‘L’ has to offer. L stands for the Liskov Substitution Principle (LSP) and states that you should be able to use any derived class in place of a parent class and have it behave in the same manner without modification. It ensures that a derived class does not affect the behaviour of the parent class, i.e. that a derived class must be substitutable for its base class.

The principle is named after Barbara Liskov who first described the problem in 1988.

More specifically substitutability means that a caller that communicates with an abstraction, i.e. a base class or an interface, should not be aware of and should not be concerned with the different concrete types of those abstractions. The client should be able to call BaseClass.DoSomething() and get a perfectly usable answer regardless of what the concrete class is in place of BaseClass. For this to work the derived class must also “behave well”, meaning:

  • They must not remove any base class behaviour
  • They must not violate base class invariants, i.e. the rules and constraints of a class, in order to preserve its integrity

The first point means the following: if a base class defines two abstract methods then a derived class must give meaningful implementations of both. If a derived class implements a method with ‘throw new NotImplementedException’ then it means that the derived class is not fully substitutable for its base class. It is a sign that the base class is ‘NOT-REALLY-A’ base class type. In that case you’ll probably need to reconsider your class hierarchy.

All who study OOP must at some point come across the ‘IS-A’ relationship between a base class and a derived class: a Dog is an Animal, a Clerk is an Employee which is a Person, a Car is a vehicle etc. LSP refines this relationship with ‘IS-SUBSTITUTABLE-FOR’, meaning that an object is substitutable with another object in all situations without running into exceptions and unexpected behaviour.

Demo

As usual in this series on SOLID we’ll start with some code which violates LSP. We’ll then see why it’s bad and then correct it. The demo is loosely connected to the one we worked on in the SRP and OCP posts: an e-commerce application that can refund your money in case you send back the item(s) you purchased. At this company you can pay using different services such as PayPal. Consequently the refund will happen through the same service as well.

Open Visual Studio and create a new console application. We’ll start off with an enumeration of the payment services:

public enum PaymentServiceType
{
	PayPal = 1
	, WorldPay = 2
}

It would be great to explore the true web services these companies have to offer to the public but the following mockup APIs will suffice:

public class PayPalWebService
	{
		public string GetTransactionToken(string username, string password)
		{
			return "Hello from PayPal";
		}

		public string MakeRefund(decimal amount, string transactionId, string token)
		{
			return "Auth";
		}
	}
public class WorldPayWebService
	{
		public string MakeRefund(decimal amount, string transactionId, string username,
			string password, string productId)
		{
			return "Success";
		}
	}

We concentrate on the Refund logic which the two services carry out slightly differently. What’s common is that the MakeRefund methods return a string that describes the result of the action.

We’ll eventually need a refund service that interacts with these API’s somehow but it will need some object that represents the payments. As the payments can go through the two services mentioned above, and possible others in the future, we’ll need an abstraction for them. An abstract base class seems appropriate:

public abstract class PaymentBase
	{
		public abstract string Refund(decimal amount, string transactionId);
	}

We can now create the concrete classes for the PayPal and WorldPay payments:

public class PayPalPayment : PaymentBase
	{
		public string AccountName { get; set; }
		public string Password { get; set; }

		public override string Refund(decimal amount, string transactionId)
		{
			PayPalWebService payPalWebService = new PayPalWebService();
			string token = payPalWebService.GetTransactionToken(AccountName, Password);
			string response = payPalWebService.MakeRefund(amount, transactionId, token);
			return response;
		}
	}
public class WorldPayPayment : PaymentBase
	{
		public string AccountName { get; set; }
		public string Password { get; set; }
		public string ProductId { get; set; }

		public override string Refund(decimal amount, string transactionId)
		{
			WorldPayWebService worldPayWebService = new WorldPayWebService();
			string response = worldPayWebService.MakeRefund(amount, transactionId, AccountName, Password, ProductId);
			return response;
		}
	}

Each concrete Payment class will communicate with the appropriate payment service to log on and request a refund. This follows the Adapter pattern in that we’re wrapping the real API:s in our own classes. We’ll need to be able to identify the correct payment type. In the previous post we used a variable called IsMatch in each concrete type – here we’ll take the Factory approach just to see another way of selecting a concrete class:

public class PaymentFactory
	{
		public static PaymentBase GetPaymentService(PaymentServiceType serviceType)
		{
			switch (serviceType)
			{
				case PaymentServiceType.PayPal:
					return new PayPalPayment();
				case PaymentServiceType.WorldPay:
					return new WorldPayPayment();
				default:
					throw new NotImplementedException("No such service.");
			}
		}
	}

The factory selects the correct implementation using the incoming enumeration. Read the blog post on the Factory pattern if you’re not sure what’s happening here.

We’re ready for the actual refund service which connects the above ingredients:

public class RefundService
{
	public bool Refund(PaymentServiceType paymentServiceType, decimal amount, string transactionId)
	{
		bool refundSuccess = false;
		PaymentBase payment = PaymentFactory.GetPaymentService(paymentServiceType);
		if ((payment as PayPalPayment) != null)
		{
			((PayPalPayment)payment).AccountName = "Andras";
			((PayPalPayment)payment).Password = "Passw0rd";
		}
		else if ((payment as WorldPayPayment) != null)
		{
			((WorldPayPayment)payment).AccountName = "Andras";
			((WorldPayPayment)payment).Password = "Passw0rd";
			((WorldPayPayment)payment).ProductId = "ABC";
		}

		string serviceResponse = payment.Refund(amount, transactionId);

		if (serviceResponse.Contains("Auth") || serviceResponse.Contains("Success"))
		{
			refundSuccess = true;
		}

		return refundSuccess;
	}
}

We get the payment type using the factory. We then immediately need to check its type in order to be able to assign values to the the different properties in it. There are multiple problems with the current implementation:

  • We cannot simply take the payment object returned by the factory, we need to check its type – therefore we cannot substitute the subtype for its base type, hence we break LSP. Such if-else statements where you branch your logic based on some object’s type are telling signs of LSP violation
  • We need to extend the if-else statements as soon as a new provider is implemented, which also violates the Open-Closed Principle
  • We need to extend the serviceResponse.Contains bit as well if a new payment provider returns a different response, such as “OK”
  • The client, i.e. the RefundService object needs to intimately know about the different types of payment providers and their internal setup which greatly increases coupling
  • The client needs to know how to interpret the string responses from the services and that is not the correct approach – the individual services should be the only ones that can do that

The goal is to be able to take the payment object returned by the factory and call its Refund method without worrying about its exact type.

First of all let’s introduce a constructor in each Payment class that force the clients to provide all the necessary parameters:

public class PayPalPayment : PaymentBase
	{
		public PayPalPayment(string accountName, string password)
		{
			AccountName = accountName;
			Password = password;
		}

		public string AccountName { get; set; }
		public string Password { get; set; }

		public override string Refund(decimal amount, string transactionId)
		{
			PayPalWebService payPalWebService = new PayPalWebService();
			string token = payPalWebService.GetTransactionToken(AccountName, Password);
			string response = payPalWebService.MakeRefund(amount, transactionId, token);
			return response;
		}
	}
public class WorldPayPayment : PaymentBase
	{
		public WorldPayPayment(string accountId, string password, string productId)
		{
			AccountName = accountId;
			Password = password;
			ProductId = productId;
		}

		public string AccountName { get; set; }
		public string Password { get; set; }
		public string ProductId { get; set; }

		public override string Refund(decimal amount, string transactionId)
		{
			WorldPayWebService worldPayWebService = new WorldPayWebService();
			string response = worldPayWebService.MakeRefund(amount, transactionId, AccountName, Password, ProductId);
			return response;
		}
	}

We need to update the factory accordingly:

public class PaymentFactory
	{
		public static PaymentBase GetPaymentService(PaymentServiceType serviceType)
		{
			switch (serviceType)
			{
				case PaymentServiceType.PayPal:
					return new PayPalPayment("Andras", "Passw0rd");
				case PaymentServiceType.WorldPay:
					return new WorldPayPayment("Andras", "Passw0rd", "ABC");
				default:
					throw new NotImplementedException("No such service.");
			}
		}
	}

The input parameters are hard-coded to keep things simple. In reality these can be read from a configuration file or sent in as parameters to the GetPaymentService method. We can now improve the RefundService class as follows:

public class RefundService
{
	public bool Refund(PaymentServiceType paymentServiceType, decimal amount, string transactionId)
	{
		bool refundSuccess = false;
		PaymentBase payment = PaymentFactory.GetPaymentService(paymentServiceType);			

		string serviceResponse = payment.Refund(amount, transactionId);

		if (serviceResponse.Contains("Auth") || serviceResponse.Contains("Success"))
		{
			refundSuccess = true;
		}

		return refundSuccess;
	}
}

We got rid of the downcasting issue. We now need to do something about the need to inspect the strings in the Contains method. This if statement still has to be extended if we introduce a new payment service and the client still has to know what “Success” means. If you think about it then ONLY the payment service objects should be concerned with this type of logic. The Refund method returns a string from the payment service but instead the string should be evaluated within the payment service itself, right? Let’s update the return type of the PaymentBase object:

public abstract class PaymentBase
{
	public abstract bool Refund(decimal amount, string transactionId);
}

We can transfer the response interpretation logic to the respective Payment objects:

public class WorldPayPayment : PaymentBase
{
	public WorldPayPayment(string accountId, string password, string productId)
	{
		AccountName = accountId;
		Password = password;
		ProductId = productId;
	}

	public string AccountName { get; set; }
	public string Password { get; set; }
	public string ProductId { get; set; }

	public override bool Refund(decimal amount, string transactionId)
	{
		WorldPayWebService worldPayWebService = new WorldPayWebService();
		string response = worldPayWebService.MakeRefund(amount, transactionId, AccountName, Password, ProductId);
		if (response.Contains("Success"))
			return true;
		return false;
	}
}
public class PayPalPayment : PaymentBase
{
	public PayPalPayment(string accountName, string password)
	{
		AccountName = accountName;
		Password = password;
	}

	public string AccountName { get; set; }
	public string Password { get; set; }

	public override bool Refund(decimal amount, string transactionId)
	{
		PayPalWebService payPalWebService = new PayPalWebService();
		string token = payPalWebService.GetTransactionToken(AccountName, Password);
		string response = payPalWebService.MakeRefund(amount, transactionId, token);
		if (response.Contains("Auth"))
			return true;
		return false;
	}
}

The RefundService has been greatly simplified:

public class RefundService
{
	public bool Refund(PaymentServiceType paymentServiceType, decimal amount, string transactionId)
	{
		PaymentBase payment = PaymentFactory.GetPaymentService(paymentServiceType);
		return payment.Refund(amount, transactionId);
	}
}

There’s no need to downcast anything or to extend this method if a new service is introduced. Strict proponents of the Single Responsibility Principle may argue that the Payment classes are now bloated, they should not know how to process the string response from the web services. However, I think it’s well worth refactoring the initial code this way. It eliminates the drawbacks we started out with. Also, in a Domain Driven Design approach it’s perfectly reasonable to include the logic belonging to a single object within that object and not anywhere else.

A related principle is called ‘Tell, Don’t Ask‘. We violated this principle in the initial solution where we asked the Payment object about its exact type: if you see that you need to interrogate an object about its internal state in order to branch your code then it may be a candidate for refactoring. Move that logic into the object itself within a method and simply call that method. Meaning don’t ask an object about its state, instead tell it to perform what you want it do.

View the list of posts on Architecture and Patterns here.

SOLID design principles in .NET: the Single Responsibility Principle

The SOLID design principles are a collection of best practices for object oriented software design. The abbreviation comes from the first letter of each of the following 5 constituents:

  • Single responsibility principle (SRP)
  • Open-Closed principle (OCP)
  • Liskov substitution principle (LSP)
  • Interface segregation principle (ISP)
  • Dependency inversion principle (DIP)

Each of these terms are meant to make your code base easier to understand and maintain. They also ensure that your code does not become a mess with a large degree of interdependency that nobody wants to debug and extend. Of course you can write functioning software without adhering to these guidelines but they are a good investment in the future development of your product especially as far as maintainability and extensibility are concerned. Also, by following these points your code will become more object oriented instead of employing a more procedural style of coding with a lot of magic strings and enumerations and other primitives.

However, the principles do not replace the need for maintaining and refactoring your code so that it doesn’t get stale. They are a good set of tools to make your future work with your code easier. We will look at each of these in this series.

You can view these principles as guidelines. You should write code with these guidelines in mind and should aim to get as far as possible to reach each of them. You won’t always succeed of course, but even a bit of SOLID is more than the total lack of it.

SRP introduction

The Single Responsibility Principle states that every object should only have one reason to change and a single focus of responsibility. In other words every object should perform one thing only. You can apply this idea at different levels of your software: a method should only carry out one action; a domain object should only represent one domain within your business; the presentation layer should only be responsible for presenting your data; etc. This principle aims to achieve the following goals:

  • Short and concise objects: avoid the problem of a monolithic class design that is the software equivalent of a Swiss army knife
  • Testability: if a method carries out multiple tasks then it’s difficult to write a test for it
  • Readability: reading short and concise code is certainly easier than finding your way through some spaghetti code
  • Easier maintenance

A responsibility of a class usually represents a feature or a domain in your application. If you assign many responsibilities to a class or bloat your domain object then there’s a greater chance that you’ll need to change that class later. These responsibilities will be coupled together in the class making each individual responsibility more difficult to change without introducing errors in another. We can also call a responsibility a “reason to change”.

SRP is strongly related to what is called Separation of Concerns (SoC). SoC means dissecting a piece of software into distinct features that encapsulate unique behaviour and data that can be used by other classes. Here the term ‘concern’ represents a feature or behaviour of a class. Separating a programme into small and discrete ‘ingredients’ significantly increases code reuse, maintenance and testability.

Other related terms include the following:

  • Cohesion: how strongly related and focused the various responsibilities of a module are
  • Coupling: the degree to which each programme module relies on each one of the other modules

In a good software design we are striving for a high level of cohesion and a low level of coupling. A high level of coupling, also called tight coupling, usually means a lot of concrete dependency among the various elements of your software. This leads to a situation where changing the design of one class leads to the need of changing other classes that are dependent on the class you’ve just changed. Also, with tight coupling changing the design of one class can introduce errors in the dependent classes.

One last related technique is Test Driven Design or Test Driven Development (TDD). If you apply the test first approach of TDD and write your tests carefully then it will help you fulfil SRP, or at least it is a good way to ensure that you’re not too far from SRP. If you don’t know what TDD is then you can read about it here.

Demo

In the demo we’ll simulate an e-commerce application. We’ll first deliberately introduce a bloated Order object with a lot of responsibilities. We’ll then refactor the code to get closer to SRP.

Open Visual Studio and create a new console application. Insert a new folder called Model and insert a couple of basic models into it:

public class OrderItem
{
	public string Identifier { get; set; }
	public int Quantity { get; set; }
}
public class ShoppingCart
{
	public decimal TotalAmount { get; set; }
	public IEnumerable<OrderItem> Items { get; set; }
	public string CustomerEmail { get; set; }
}
public enum PaymentMethod
{
	CreditCard
	, Cheque
}
public class PaymentDetails
{
	public PaymentMethod PaymentMethod { get; set; }
	public string CreditCardNumber { get; set; }
	public DateTime ExpiryDate { get; set; }
	public string CardholderName { get; set; }
}

This is all pretty simple up this point I believe. Now comes the most important domain object, Order, which has quite many areas of responsibility:

public class Order
{
	public void Checkout(ShoppingCart shoppingCart, PaymentDetails paymentDetails, bool notifyCustomer)
	{
		if (paymentDetails.PaymentMethod == PaymentMethod.CreditCard)
		{
			ChargeCard(paymentDetails, shoppingCart);
		}

		ReserveInventory(shoppingCart);

		if (notifyCustomer)
		{
			NotifyCustomer(shoppingCart);
		}
	}

	public void NotifyCustomer(ShoppingCart cart)
	{
		string customerEmail = cart.CustomerEmail;
		if (!String.IsNullOrEmpty(customerEmail))
		{
			try
			{
				//construct the email message and send it, implementation ignored
			}
			catch (Exception ex)
			{
				//log the emailing error, implementation ignored
			}
		}
	}

	public void ReserveInventory(ShoppingCart cart)
	{
		foreach (OrderItem item in cart.Items)
		{
			try
			{
				InventoryService inventoryService = new InventoryService();
				inventoryService.Reserve(item.Identifier, item.Quantity);

			}
			catch (InsufficientInventoryException ex)
			{
				throw new OrderException("Insufficient inventory for item " + item.Sku, ex);
			}
			catch (Exception ex)
			{
				throw new OrderException("Problem reserving inventory", ex);
			}
		}
	}

	public void ChargeCard(PaymentDetails paymentDetails, ShoppingCart cart)
	{
		PaymentService paymentService = new PaymentService();

		try
		{
			paymentService.Credentials = "Credentials";
			paymentService.CardNumber = paymentDetails.CreditCardNumber;
			paymentService.ExpiryDate = paymentDetails.ExpiryDate;
			paymentService.NameOnCard = paymentDetails.CardholderName;
			paymentService.AmountToCharge = cart.TotalAmount;

			paymentService.Charge();
		}
		catch (AccountBalanceMismatchException ex)
		{
			throw new OrderException("The card gateway rejected the card based on the address provided.", ex);
		}
		catch (Exception ex)
		{
			throw new OrderException("There was a problem with your card.", ex);
		}

	}
}

public class OrderException : Exception
{
	public OrderException(string message, Exception innerException)
		: base(message, innerException)
	{
	}
}

The Order class won’t compile yet, so add a new folder called Services with the following objects representing the Inventory and Payment services:

public class InventoryService
{
	public void Reserve(string identifier, int quantity)
	{
		throw new InsufficientInventoryException();
	}
}

public class InsufficientInventoryException : Exception
{
}
public class PaymentService
{
	public string CardNumber { get; set; }
	public string Credentials { get; set; }
	public DateTime ExpiryDate { get; set; }
	public string NameOnCard { get; set; }
	public decimal AmountToCharge { get; set; }
	public void Charge()
	{
		throw new AccountBalanceMismatchException();
	}
}

public class AccountBalanceMismatchException : Exception
{
}

These are two very simple services with no real implementation that only throw exceptions.

Looking at the Order class we see that it performs a lot of stuff: checking out after the customer has placed an order, sending emails, logging exceptions, charging the credit card etc. Probably the most important method here is Checkout which calls upon the other methods in the class.

What is the problem with this design? After all it works well, customers can place orders, they get notified etc.

I think first and foremost the greatest flaw is a conceptual one actually. What has the Order domain object got to do with sending emails? What does it have to do with checking the inventory, logging exceptions or charging the credit card? These are all concepts that simply do not belong in an Order domain.

Imagine that the Order object can be used by different platforms: an e-commerce website with credit card payments or a physical shop where you pick your own goods from the shelf and pay by cash. Which leads to several other issues as well:

  • Cheque payments don’t need card processing: cards are only charged in the Checkout method if the customer is paying by card – in any other case we should not involve the idea of card processing at all
  • Inventory reservations should be carried out by a separate service in case we’re buying in a physical shop
  • The customer will probably only need an email notification if they use the web platform of the business – otherwise the customer won’t even provide an email address. After all, why would you want to be notified by email if you buy the goods in person in a shop?

The problem here is that no matter what platform consumes the Order object it will need to know about the concepts of inventory management, credit card processing and emails. So any change in these concepts will affect not only the Order object but all others that depend on it.

Let’s refactor to a better design. The key is to regroup the responsibilities of the Checkout method into smaller units. Add a new folder called SRP to the project so that you’ll have access to the objects before and after the refactoring.

We know that we can process several types of Order: an online order, a cash order, a cheque order and possibly other types of Order that we haven’t thought of. This calls for an abstract Order object:

public abstract class Order
{
	private readonly ShoppingCart _shoppingCart;

	public Order(ShoppingCart shoppingCart)
	{
		_shoppingCart = shoppingCart;
	}

        public ShoppingCart ShoppingCart
	{
		get
		{
			return _shoppingCart;
		}
	}

	public virtual void Checkout()
	{
		//add common functionality to all Checkout operations
	}
}

We’ll separate out the responsibilities of the original Checkout method into interfaces:

public interface IReservationService
{
	void ReserveInventory(IEnumerable<OrderItem> items);
}
public interface IPaymentService
{
	void ProcessCreditCard(PaymentDetails paymentDetails, decimal moneyAmount);
}
public interface INotificationService
{
	void NotifyCustomerOrderCreated(ShoppingCart cart);
}

So we separated out the inventory management, customer notification and payment services into their respective interfaces. We can now create some concrete Order objects. The simplest case is when you go to a shop, place your goods into a real shopping cart and pay at the cashier. There’s no credit card process and no email notification. Also, the inventory has probably been reduced when the goods were placed on the shelf, there’s no need to reduce the inventory further when the actual purchase happens:

class CashOrder : Order
{
	public CashOrder(ShoppingCart shoppingCart)
		: base(shoppingCart)
	{ }
}

That’s all for the cash order which represents an immediate purchase in a shop where the customer pays by cash. You can of course pay by credit card in a shop so let’s create another order type:

public class CreditCardOrder : Order
{
	private readonly PaymentDetails _paymentDetails;
	private readonly IPaymentService _paymentService;

	public CreditCardOrder(ShoppingCart shoppingCart
		, PaymentDetails paymentDetails, IPaymentService paymentService) : base(shoppingCart)
	{
		_paymentDetails = paymentDetails;
		_paymentService = paymentService;
	}

	public override void Checkout()
	{
		_paymentService.ProcessCreditCard(_paymentDetails, ShoppingCart.TotalAmount);
		base.Checkout();
	}
}

The credit card payment must be processed hence we’ll need a Payment service to take care of that. We call upon its ProcessCreditCard method in the overridden Checkout method. Here the consumer platform can provide some concrete implementation of the IPaymentService interface, it doesn’t matter to the Order object.

Lastly we can have an online order with inventory management, payment service and email notifications:

public class OnlineOrder : Order
{
	private readonly INotificationService _notificationService;
	private readonly PaymentDetails _paymentDetails;
	private readonly IPaymentService _paymentService;
	private readonly IReservationService _reservationService;

	public OnlineOrder(ShoppingCart shoppingCart,
		PaymentDetails paymentDetails, INotificationService notificationService
		, IPaymentService paymentService, IReservationService reservationService)
		: base(shoppingCart)
	{
		_paymentDetails = paymentDetails;
		_paymentService = paymentService;
		_reservationService = reservationService;
		_notificationService = notificationService;
	}

	public override void Checkout()
	{
		_paymentService.ProcessCreditCard(_paymentDetails, ShoppingCart.TotalAmount);
		_reservationService.ReserveInventory(ShoppingCart.Items);
		_notificationService.NotifyCustomerOrderCreated(ShoppingCart);
		base.Checkout();
	}
}

The consumer application will provide concrete implementations for the notification, inventory management and payment services. The OnlineOrder object will not care what those implementations look like and will not be affected at all if you make a change in those implementations or send in a different concrete implementation. As you can see these are the responsibilities that are likely to change over time. However, the Order object and its concrete implementations won’t care any more.

Furthermore, a web platform will only concern itself with online orders now and not with point-of-sale ones such as CreditOrder and CashOrder. The platform that a cashier uses in the shop will probably use CashOrder and CreditOrder objects depending on the payment method of the customer. The web and point-of-sale platforms will no longer be affected by changes made to the inventory management, email notification and payment processing logic.

Also, note that we separated out the responsibilities into individual smaller interfaces and not a single large one with all responsibilities. This follows the letter ‘I’ in solid, the Interface Segregation Principle, that we’ll look at in a future post.

We are done with the refactoring, at least as far as SRP is concerned. We can still take up other areas of improvement such as making the Order domain object cleaner by creating application services that will take care of the Checkout process. It may not be correct to put all these services in a single domain object, but it depends on the philosophy you follow in your domain design. That leads us to discussions on DDD (Domain Driven Design) which is not the scope of this post.

View the list of posts on Architecture and Patterns here.

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.

%d bloggers like this: