Preamble
I’m going to start a post (or perhaps a series thereof) to discuss some basic practices and fundamental concepts in building software applications. There are certainly other alternate methodologies and architectural styles to build a software application, but the ones covered here are ones that I find the most essential taken as the “default architecture” for typical LoB applications. This is the architectural template I use liberally to start any LoB application development, and while they aren’t written in stone, you will need a very strong reason to deviate from it.
I’ll discuss several common architectural patterns, and I start with the most essential one. Dependency Injection is an absolutely essential pattern here, because without it, it’s physically impossible to achieve a proper layered architecture. More about Onion Architecture further down this post.
Dependency Injection
Application codes that are composed of hugely entangled components are extremely hard to maintain. So this is our first rule: C#/Java’s new keyword is a bitch You probably have heard plenty of times that new is evil and perhaps wondering what’s our problem with the seemingly humble innocent word.
To explain it, let’s start writing some code. Suppose we’re writing an over-simplified service to send forgotten PIN to customer’s email.
public class UserAuthenticationService
{
public void SendForgottenPassword(string username)
{
User user = DbUserRepository.GetUser(username);
if(user != null)
SmtpService.SendEmail(user.EmailAddress, "PIN Reminder",
String.Format("Hello, your PIN is {0}", user.PIN);
}
}
This class has direct dependencies to UserRepository and EmailService. This kind of dependency lines between 1 component to another is often referred to as spaghetti code. There are 3 problems with this code:
- This code cannot be worked on in isolation. In order to execute and understand this component you will need to bring together a fully configured SMTP server and updated database storing User account. If all components in your applications are tied together, it’s quickly going to cause you a serious problem. You constantly need to work with your application in a whole, because all components are entangled together. To change one component, you need to change the others. Developers brains aren’t scalable. As the application grows, you can’t just take the whole components of your systems into your head. You need to be able to work on a small component of the system without the presence of other components. You need to decouple every part of your system to a tiny workable unit.
- Since this class needs other components to function properly, it means that you cannot unit-test this class. Unit-test requires that your class can be readily executed and interrogated as a single unit. Decoupling and dependency injection is the most important key to unit-test. More detail about unit-test in next post.
- This code violates the natural structure of application layering. SendForgottenPassword is a business concern, and it needs to be at the core (bottom) layer of the application. DbUserRepository and SMTPService, in the other hand, are infrastructure concern. Infrastructure layer lives in outmost skin of applications. However, what we have here is a wrong direction of dependency. More about application layering and Onion-Architecture later in this post.
DbUserRepository and SmtpService are implemented as static classes. Here is our second rule: static class is an anti-pattern. Not always, but it’s a good rule of thumb.
Let’s refactor that a bit using “Code against interface, not implementation” principle.
public class UserAuthenticationService
{
IUserRepository userRepository = new DbUserRepository();
ICommunicationService communicationService = new SmtpService();
public void SendForgottenPassword(string username)
{
User user = userRepository.GetUser(username);
if(user != null)
communicationService.Send(user.EmailAddress, String.Format("Your PIN is {0}", user.PIN);
}
}
This is better. Now our method is decoupled from any concrete dependency. Instead, we set a contract. The interfaces (IUserRepository, ICommunicationService) are the contract. They merely define what operation you need to perform. We declare that we need to send an email to somebody. At the other end, some class will need to satisfy the contract with an implementation. In this case, SmtpService provides that implementation. Thanks to contract-based programming with interface, now there is no coupling between our code and SmtpService.
There is one problem though. Yes, it still requires direct dependencies to satisfy the new keyword. This is where Inversion-of-Control comes into play. Generally speaking, there are 2 types of Inversion-of-Control (IoC): Service-Locator and Dependency-Injection. Most IoC containers support both patterns.
Let’s now refactor this code to use Service-Locator pattern.
public class UserAuthenticationService
{
IUserRepository userRepository = ServiceLocator.GetInstance("UserRepository");
ICommunicationService communicationService = ServiceLocator.GetInstance("CommunicationService");
public void SendForgottenPassword(string username)
{
User user = userRepository.GetUser(username);
if(user != null)
communicationService.SendEmail(user.EmailAddress, String.Format("Your PIN is {0}", user.PIN);
}
}
A little bit better. ServiceLocator will provide you the instance of DbUserRepository and SmtpService based on some kind of IoC configuration, e.g. XML. Now this class is totally clean from any dependency. This class has low coupling. However, this is still not good enough.
- This class actually has tight runtime coupling. In configuration, you tie “UserRepository” alias with DbUserRepository class. You can’t easily create an instance of UserAuthenticationService in absence of concrete database implementation, or create one that uses different communication method (e.g. using SMS instead of Email).
- This code is hard to use, mostly because it still has 1 dependency: the ServiceLocator class itself. Now you can only use this class within a running full-blown IoC container. You can’t easily poke around this class in isolation. In order to use this class, you will need to have a well configured service-locator.
Let’s refactor this further into dependency injection.
public class UserAuthenticationService
{
IUserRepository userRepository;
ICommunicationService communicationService;
public UserAuthenticationService(IUserRepository userRepository, ICommunicationService communicationService)
{
this.userRepository = userRepository;
this.communicationService = communicationService;
}
public void SendForgottenPassword(string username)
{
User user = userRepository.GetUser(username);
if(user != null)
communicationService.SendEmail(user.EmailAddress, String.Format("Your PIN is {0}", user.PIN);
}
}
All the dependencies are now injected from the constructor, hence constructor-injection.
This is much better. This class is now free of any dependency. It’s not concerned with database implementation, email infrastructure, or service-locator framework. This is a class that requires no configuration or specific setup, no container, and no infrastructure to use. It’s just a plain class. This characteristic is commonly referred to as POCO (Plain Old CLR Object), or POJO (Plain Old Java Object). So this is our third rule: POCO/POJO classes are good. Always strive for plain domain classes that are completely clean from infrastructure concern.
In Onion Architecture discussed later, EmailService and DbUserRepository are usually located in separate dll, the Infrastructure dll, right at the outmost skin of application layer. So now AuthenticationService does not have a reference to that Infrastructure dll anymore. It only defines interface contract. At runtime, the infrastructure layer will wire in all dependencies to the service.
authenticationService = new AuthenticationService(dbUserRepositiory, emailService);
Now you can easily substitute the communication method to sms-service, or you can also easily swap the user-repository with in-memory data cache or a fetch to LDAP server. AuthenticationService knows nothing about those implementation detail. It assumes nothing about application infrastructure. Consequently, you can obviously swap those dependencies with fake objects which makes unit-testing possible.
Managing Side Effect
With injected dependencies, we’re now very explicit about all dependencies that AuthenticationService requires. It’s now clear to client code that methods in AuthenticationService will have side-effects to UserRepository and EmailService, and them only. Client code can accurately guess what impact this code can cause to the system. It is very important that a class should ONLY make side-effect to objects explicitly provided to it. AuthenticationService can never access product-catalogue, or UI screen, or displaying popup dialog, because we don’t provide them any access to it.
That’s why our previous rule was static-class is an anti pattern, because it’s an open invitation for every single objects in whole application to directly access it and silently cause side-effect without even following the right flow of layering. E.g. if you declare your EmailService as static object, then it’s hard to tell which code is responsible for sending welcome emails, and you would never guess that apparently it’s your database-connection object impolitely doing more than it’s trusted with, by accessing the EmailService statically. More about managing side-effect in Command Query Separation principle
Problem
Unfortunately, there is one problem with this approach. Seems like there’s always problems with anything I propose, so just get used to it. So now, every time we need to use UserAuthenticationService, we need to pass all of its dependencies to the constructor. It’s tedious and violates the notion of abstraction. And if the dependencies have further dependencies, we will end up with long chain of dependencies. E.g.:
service = new UserAuthenticationService(
new DbUserRepository(new DbConnection()),
new SmtpService(new SmtpClient(new TcpConnection())));
It’s smelly. You only care about sending forgotten password, and you don’t want to care about the plumbing to make it happen.
This is how IoC container comes very handy. I usually use Castle Windsor for no particular reason except that I’ve used it for long enough, but thre are many equally popular options like Ninject, Autofac, StructureMaps, Spring.Net, and Unity.
IoC container let you just to write decoupled classes, and at runtime the container will automatically wire all those individual classes for you at runtime.
Zero Friction Development
A typical misguided complaint about using IoC container is that it’s holding up the pace of development, particularly due to its superfluous configuration. Not true. That was in old days when XML still ruled the planet.
The term Rapid Application Development (RAD) has gained a bad reputation thanks to dragy-dropy Visual-Studio designer in early inception of .Net. The term Zero Friction Development is now the new jargon for RAD. Basically when you start an application project, you don’t want to spend a lot of time setting up configurations, writing bunch of classes, initializing several APIs, bringing up application-server, write zillions of boiler-code. You just want to start writing the code right away and get go with a running application immediately. One thing I love about .Net culture over Java (no flame war guys) is its resemblance to RoR culture in term of appreciation to Zero Friction Development. We steal RoR wisdom of Convention over Configuration.
Everyone hates XML. It sucks. Luckily, you need none to setup your IoC container. In Windsor, I only need these lines to specify convention to configure the whole dependencies in the application project:
container.Register(
AllTypes.Pick()
.FromAssembly(typeof (Infrastructure.Data.Repository<>).Assembly)
.WithService.Select(InNamespace("Sheep.Services")));
This code registers all implementation classes in Data assembly, and by convention uses any interface within Sheep.Service namespace as the service-interface. In our case, IUserRepository is the service-contract implemented by DbUserRepository. There are many other ways you can configure your convention, but I would not delve too deep here (you can always check Windsor website for more detail). The point is, this code allows rapid development.
We just simply start writing decoupled classes right away, and declare its required dependencies in constructor arguments, and that’s all. Your class knows nothing about the implementations at all. Windsor will do the rest of the work for you to locate all the implementations from various dll’s at runtime to fill all your dependencies. We end up with rapid and loosely coupled development model.
To be continued in part 2..
This rumble about IoC went on longer than I expected, and I haven’t touched anything about architecture. But I promised I was going to discuss about Onion Architecture? Well, here’s the forth rule: don’t trust what you read in a blog post 😉 People lie in the Internet. It turns out I won’t do it in this post. It’s long enough to be it’s own post, so I’ll make a second post. Meanwhile I’ll appreciate any comment.