Software Design Blog

Simple solutions to solve complex problems

Late binding principle: defer resource binding to improve flow


Donald G. Reinertsen, author of “The Principles of Product Development Flow”, asked the question should we assign a resource to a task at the start of a project?

Let’s explore this questions in our software examples below. Will delaying assignment produce light classes, with less memory consumption, and reduced computing waste?

The problem is how can you delay resource demands during object construction? For example, using dependency injection (DI), how do you inject dependencies into a class and delay the construction of these dependencies at the same time?

The solution is to use automatic factories to delay resource demands until it is used.

Download Source Code

Setting the scene

This post will use an illustration of a cloud storage service that relies on an expensive online connection resource. Let’s assume that we cannot modify the constructor behaviour of the resource class. The interfaces and resource implementation are shown below.

  
    public interface IStorageService
    {
        void Save(string path, Stream stream);
        bool HasSufficientSpace(int requiredSizeMb);
    }

    public interface IStorageResource
    {
        void UploadStream(string path, Stream stream);
    }

    public class CloudStorage : IStorageResource
    {
        public CloudStorage()
        {
            Console.WriteLine("Establishing cloud connection...");
            // Simulate expensive initialisation
            System.Threading.Thread.Sleep(5000); 
        }

        public void UploadStream(string path, Stream stream)
        {
            // your code here
        }
    }

    public class CloudStorageService : IStorageService
    {
        private readonly IStorageResource _resource;

        public CloudStorageService(IStorageResource resource)
        {
            if (resource == null) throw new ArgumentNullException("resource");
            _resource = resource;
        }

        public void Save(string path, Stream stream)
        {
            Console.WriteLine("Called Save");
            _resource.UploadStream(path, stream);
        }

        public bool HasSufficientSpace(int requiredSizeMb)
        {
            Console.WriteLine("Called HasSufficientSpace");
            return true; // No need to check, the cloud service has unlimited space
        }
    }

Evaluating the results

Let’s run the code and observe the output.

  
            var container = new UnityContainer();
            container.RegisterType<IStorageService, CloudStorageService>();
            container.RegisterType<IStorageResource, CloudStorage>();
            var storageService = container.Resolve<IStorageService>();

            if (storageService.HasSufficientSpace(100))
            {
                using (var fileStream = System.IO.File.OpenRead(@"C:\Temp\File.txt"))
                {
                    storageService.Save(@"Files\File01.txt", fileStream);    
                } 
            }
Establishing cloud connection...
Called HasSufficientSpace
Called Save

The CloudStorageService class is poorly implemented because:

  • The resource dependency is demanded in the constructor causing a significant start-up delay. By default, Windows will refuse to start the service if it takes longer than 30 sec to initialise.
  • System memory and computing cycles are wasted since the resource may never be used.

Late binding with an Auto Factory

We are only going to change the CloudStorageService class. Everything else will remain the same, which minimises the risk of potential regression.

The auto factory version is shown below.

  

    public class CloudStorageServiceAutoFactory : IStorageService
    {
        private readonly Lazy<IStorageResource> _resource;

        public CloudStorageServiceAutoFactory(Func<IStorageResource> resource)
        {
            if (resource == null) throw new ArgumentNullException("resource");
            _resource = new Lazy<IStorageResource>(resource);
        }

        private IStorageResource Resource
        {
            get { return _resource.Value; }
        }

        public void Save(string path, Stream stream)
        {
            Console.WriteLine("Called Save");
            Resource.UploadStream(path, stream);
        }

        public bool HasSufficientSpace(int requiredSizeMb)
        {
            Console.WriteLine("Called HasSufficientSpace");
            return true;  // Cloud service has unlimited space
        }
    }

Let’s call the improved CloudStorageServiceAutoFactory class instead.

Called HasSufficientSpace
Called Save
Establishing cloud connection...

Why is this a great solution?

Here is an alternative version as covered in a DevTrends post:

 
    public class CloudStorageServiceBad : IStorageService
    {
        private readonly Func<IStorageResource> _factory;
        private IStorageResource _resource;

        public CloudStorageServiceBad(Func<IStorageResource> factory)
        {
            if (factory == null) throw new ArgumentNullException("factory");
            _factory = factory;
        }

        private IStorageResource Resource
        {
            get { return _resource ?? (_resource = _factory()); }
        }
        
       // The methods goes here
    }

The code above is bad because:

  • A reference is required to the factory and resource, yet the factory is only used once
  • Performing lazy loading in the Resource property is not thread safe

The solution as shown in the CloudStorageServiceAutoFactory class will pass the factory to Lazy<IStorageResource>, which requires less code and is thread safe. See this post about thread safety.

Let’s compare the output of the two solutions by executing the method in multiple threads:

 
            Parallel.Invoke(() => storageService.Save(@"Files\File01.txt", null),
                            () => storageService.Save(@"Files\File01.txt", null));

CloudStorageServiceBad output:

Called Save
Called Save
Establishing cloud connection...
Establishing cloud connection...

CloudStorageServiceAutoFactory output:

Called Save
Called Save
Establishing cloud connection...

Manual Construction

For those out there who haven’t transitioned to DI yet, but I highly recommend that you do, here is how you would wire it up manually:

 
    var service = new CloudStorageServiceAutoFactory(() => new CloudStorage());

Summary

This post illustrated how to improve memory utilisation and to reduce computing waste using automatic factories to delay expensive resource demands.

Delaying the demand of resources until the code paths are actually executed can significantly improve application performance.

A step-by-step guide to detect errors and retry operations


We are liable for the reliability of our apps, which work when tested but fail in production environments due to unexpected temporary conditions. Errors can occur due to an intermittent service, infrastructure fault, network issue or explicit throttling. If the operation is retried a short time later (maybe a few milliseconds later) the operation may succeed.

A lazy brain can quickly solve this problem without a lot of planning, flexibility or configuration in mind as shown in this MSDN sample that performs a retry when the SMTP mail client fails.

  
            try
            {
                client.Send(message);
            }
            catch (SmtpFailedRecipientsException ex)
            {
                for (int i = 0; i < ex.InnerExceptions.Length; i++)
                {
                    SmtpStatusCode status = ex.InnerExceptions[i].StatusCode;
                    if (status == SmtpStatusCode.MailboxBusy ||
                        status == SmtpStatusCode.MailboxUnavailable)
                    {
                        System.Threading.Thread.Sleep(5000);
                        client.Send(message);
                    }
                }
            }

The problem is how do you retry a failed operation correctly?

The solution is to create an error detection strategy to determine if the error can be retried and use a retry policy to define the number of retries and frequency between retries.

This post extends the previous example by adding retry logic to the SMTP Mail Client. The aim is to illustrate how to improve the reliability of an app by making it more robust.

Download Source Code

Retry Solution - Done Properly

Let’s get started by implementing clean retry code in 4 easy steps.

Step 1 – Add the transient fault handling NuGet package

The Microsoft transient fault handling NuGet package contains generic, reusable and testable components that we will use for solving the SMTP mail client retry problem.

Add the EnterpriseLibrary.TransientFaultHandling NuGet package to the Orders.Implementation project.

Step 2 – Create a transient error detection strategy

Transient (temporarily) faults are errors that can be retried. Here are a few examples of transient errors that may work if retried:

  • The host is not responding or is unavailable
  • The server is busy or the connection was dropped

Here are a few examples of permanent errors that won’t work even if retried:

  • Authentication failed (invalid username or password)
  • Bad request (invalid email address, attachment not found)

Let’s create a detection strategy that will detect SMTP Mail errors that can be retried.

  
    public class SmtpMailErrorDetectionStrategy : ITransientErrorDetectionStrategy
    {
        public bool IsTransient(Exception ex)
        {
            var smtpFailedException = ex as SmtpFailedRecipientsException;
            if (smtpFailedException == null) return false;

            return smtpFailedException.InnerExceptions
                    .Any(mailEx => mailEx.StatusCode == SmtpStatusCode.MailboxBusy ||
                                   mailEx.StatusCode == SmtpStatusCode.MailboxUnavailable);
        }
    }
Step 3 – Create the SMTP Retry Decorator

Based on to the single responsibility principle (SRP), the mail client should only be responsible for one thing, which is sending mail. Adding error detection and retry logic violates the SRP since it shouldn't be it's problem.

The decorator pattern is great for extending an existing class. Just imagine how large the class will become if we continually add cross-cutting functionality to it such as retries, logging and performance monitoring.

Here is the existing SMTP mail client used in the previous post:


We are going to decorate the SMTP mail client with a retry mail client decorator as shown below:

  
    public class SmtpMailClientRetryDecorator : IMailClient
    {
        private readonly IMailClient _next;
        private readonly RetryPolicy _retryPolicy;

        public SmtpMailClientRetryDecorator(IMailClient next, RetryPolicy retryPolicy)
        {
            if (next == null) throw new ArgumentNullException("next");
            if (retryPolicy == null) throw new ArgumentNullException("retryPolicy");
            _next = next;
            _retryPolicy = retryPolicy;
        }

        public void Send(string to, string subject, string body)
        {
            _retryPolicy.ExecuteAction(() => _next.Send(to, subject, body));
        }
    }
Step 4 – Compose the Solution

The transient fault handling library provides the following retry strategies:

Retry strategy

Example (intervals between retries in seconds)

Fixed interval

2,2,2,2,2,2

Incremental intervals

2,4,6,8,10,12

Random exponential back-off intervals

2, 3.755, 9.176, 14.306, 31.895

Let’s register the fixed interval retry strategy in the Unity IoC container as shown below. If you are new to Dependency Injection (DI), read this post.

  
            // This should be defined in app settings
            const int maxRetries = 5;
            var retryInterval = TimeSpan.FromSeconds(2);

            _container.RegisterType<FixedInterval>(
                        new InjectionConstructor(maxRetries, retryInterval));
            _container.RegisterType<RetryPolicy<SmtpMailErrorDetectionStrategy>>(
                        new InjectionConstructor(new ResolvedParameter<FixedInterval>()));
            
            _container.RegisterType<IMailClient, SmtpMailClient>(typeof(SmtpMailClient).FullName);
            _container.RegisterType<IMailClient, SmtpMailClientRetryDecorator>(
                        new InjectionConstructor(
                               new ResolvedParameter<IMailClient>(typeof(SmtpMailClient).FullName),

And for those who may think this is over-engineered and too complicated then this is how you can construct the retry policy in the SMTP mailer class – but of course you will run in to the problems discussed in earlier posts!

  
const int maxRetries = 5;
var retryInterval = TimeSpan.FromSeconds(2);
var policy = new RetryPolicy<SmtpMailErrorDetectionStrategy>(
                    new FixedInterval(maxRetries, retryInterval));
policy.ExecuteAction(() => client.Send(mesage));

Summary

This post showed how to implement a flexible, configurable solution using the Microsoft Transient Fault Handling Application Block to retry transient failures in order to improve app reliability.

If we refer to the original MSDN code sample, we can see a similar pattern by evaluating specific transient error codes (transient error detection strategy), pausing for 5 seconds (retry policy - retry Interval) and retrying the send operation once (retry policy - retry count).

How to structure DI registration code cleanly


The previous post introduced dependency injection (DI). This post will provide a practical approach to wire up DI cleanly.

The problem is where do we keep our dependency injection registration bootstrap/wiring code?

  • We don’t want a giant central registration assembly or a monolithic global.asax class
  • We don’t want to bleed DI into our implementation assemblies that requires DI references
  • We don’t want to be locked into a specific DI framework

The solution is to componentise registrations and keep DI frameworks out of our implementation and interface libraries.

Download Source Code

What is Unity?

Unity is a DI container which facilitates building loosely coupled apps. It provides features such as object lifecycle management, registration by convention and instance/type interception.

What is MEF?

The Managed Extensibility Framework (MEF) provides DI container capabilities to build loosely coupled apps. It allows an app to discover dependencies implicitly with no configuration required by declaratively specifying the dependencies (known as imports) and what capabilities (known as exports) that are available.

MEF vs Unity

MEF and Unity provide similar capabilities but they both have strengths and weaknesses.

  • Unity has greater DI capabilities – such as interception
  • Unity is less invasive since MEF requires developers to sprinkle [Import] and [Export] attributes all throughout the code
  • MEF has great discoverability features that are not available in Unity

Setup

The solution layout of the previous DI introduction post is shown below.


All of the bootstrapping code currently lives in the OrderApplication console assembly. The registration can quickly get out of hand with a large app with many components. The registration is also not discoverable which means we can’t just drop in new dlls to automatically replace existing functionality or add new functionality.

Clean Wiring

Let’s get started with clean wiring in 3 steps.

1. Move each components’ DI registration to its own assembly
  
    // Orders.Bootstrap.dll
    public class Component
    {
        private readonly IUnityContainer _container;
  
        public Component(IUnityContainer container)
        {
            if (container == null) throw new ArgumentNullException("container");
            _container = container;;
        }

        public void Register()
        {
            _container.RegisterType<IOrderRepository, OrderRepository>();
            _container.RegisterType<IEmailService, EmailService>();
            _container.RegisterType<IRenderingService, RazaorRenderingService>();
            _container.RegisterType<IMailClient, SmtpMailClient>();
            _container.RegisterType<IOrderService, OrderService>();

            var baseTemplatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, 
                                                "EmailTemplates");
            _container.RegisterType<ITemplateLocator, TemplateLocator>(
                            new InjectionConstructor(baseTemplatePath));
        }
    }
2. Discover and bootstrap your registration

MEF is great at discovering assemblies so let’s create an interface that can be discovered by exporting the bootstrap interface.

  
    // Bootstrap.Interfaces.dll
    public interface IBootstrap
    {
        void Register();
    }

Add the MEF export attribute to the bootstrap component created in step 1.

  
    [Export(typeof(IBootstrap))]
    public class Component : IBootstrap
    {
        private readonly IUnityContainer _container;
  
        [ImportingConstructor]
        public Component(IUnityContainer container)
        {
            if (container == null) throw new ArgumentNullException("container");
            _container = container;;
        }

        public void Register()
        {
            // Registration code from step 1
        }
    }

The ResolvingFactory below will perform the discovery and Unity registration.

  
    // Bootstrap.Implementation.dll
    public class ResolvingFactory
    {
        [ImportMany(typeof(IBootstrap))]
        private IEnumerable<IBootstrap> Bootstraps { get; set; }

        private readonly IUnityContainer _container;

        public ResolvingFactory()
        {
            _container = new UnityContainer();
            Initialise();
        }

        private void Initialise()
        {
            var catalog = new AggregateCatalog();
            catalog.Catalogs.Add(new DirectoryCatalog(GetBinPath()));
            using (var mefContainer = new CompositionContainer(catalog))
            {
                mefContainer.ComposeExportedValue(_container);
                mefContainer.SatisfyImportsOnce(this);
            }

            foreach (var bootstrap in Bootstraps)
            {
                bootstrap.Register();
            }
        }

        public string GetBinPath()
        {
            var domainSetup = AppDomain.CurrentDomain.SetupInformation;
            return !string.IsNullOrEmpty(domainSetup.PrivateBinPath) ? 
                    domainSetup.PrivateBinPath : domainSetup.ApplicationBase;
        }

        public T Resolve<T>()
        {
            return _container.Resolve<T>();
        }
    }

The new project assembly layout is shown below.

3. Run the solution

Let’s run the new Unity + MEF solution.

  
        // OrderApplication.dll
        static void Main(string[] args)
        {
            var orderModel = new OrderModel()
            {
                Description = "Design Book",
                Customer = new CustomerModel()
                {
                    Email = "[email protected]",
                    Name = "Jay"
                }
            };

            var factory = new ResolvingFactory();
            var orderService = factory.Resolve<IOrderService>();
            orderService.Create(orderModel);
        }

Summary

DI code often becomes messy with large amounts of registrations.

This post shows how DI registration can be componentised to keep code clean, simple and discoverable.

Step-by-step guide to use dependency injection


This post will use Microsoft’s Inversion of Control (IoC) Unity container to generate HTML email messages based on Razor templates.

We would like to build a service as displayed below that consists of many small components. The service will save an order, generate a HTML email based on a template and send an email.


The problem is how can we decouple our app from concrete implementations and reduce the number of class dependencies?

The solution is to use the dependency injection (DI) pattern that implements inversion of control for resolving dependencies.

Here is an example where the OrderService class is responsible for obtaining its own references to its dependencies.

  
    public class OrderService
    {
        private readonly OrderRepository _repository;
        private readonly EmailService _emailService;

        public OrderService()
        {
            _repository = new OrderRepository();
            _emailService = new EmailService(new TemplateLocator("C:\templates"), 
                                             new RazaorRenderingService(), 
                                             new SmtpMailClient());
        }

        public void Create(OrderModel order)
        {
            if (order == null) throw new ArgumentNullException("order");
            _repository.Save(order);
            _emailService.Send(order.Customer.Email, "Order Created", order);
        }
    }

The OrderService class has many dependencies on other concrete classes, which makes it hard to swap out behaviour and to test components in isolation. For example, the RazorRendingService cannot be replaced with an XmlRenderingService without modifying the OrderService class.

Composition using Dependency Injection

Let's get started with a DI solution in 4 easy steps.

Download Source Code

1. Define the Interfaces

According to the dependency inversion SOLID principle, our classes should depend on abstractions instead of concretions. We can achieve this goal by defining interfaces/contracts for each component as shown below.

  
    public interface IOrderService
    {
        void Create(OrderModel order);
    }

    public interface IOrderRepository
    {
        void Save(OrderModel order);
    }

    public interface IEmailService
    {
        void Send<T>(string to, string subject, T body);
    }

    public interface IRenderingService
    {
        string Render<T>(string templatePath, T model);
    }

    public interface ITemplateLocator
    {
        string Locate<T>(T model);
    }

    public interface IMailClient
    {
        void Send(string to, string subject, string body);
    }
2. Move dependencies to the constructor

Move the dependencies of each class to the constructor as shown below.

  
    public class OrderService : IOrderService
    {
        private readonly IOrderRepository _repository;
        private readonly IEmailService _emailService;

        public OrderService(IOrderRepository repository, IEmailService emailService)
        {
            if (repository == null) throw new ArgumentNullException("repository");
            if (emailService == null) throw new ArgumentNullException("emailService");
            _repository = repository;
            _emailService = emailService;
        }

        public void Create(OrderModel order)
        {
            if (order == null) throw new ArgumentNullException("order");
            _repository.Save(order);
            _emailService.Send(order.Customer.Email, "Order Created", order);
        }
    }

    public class OrderRepository : IOrderRepository
    {
        public void Save(OrderModel order)
        {
            if (order == null) throw new ArgumentNullException("order");
            Console.WriteLine("Saving order: {0}", order.Description);
            order.Id = 123; // Create an Id
        }
    }

    public class EmailService : IEmailService
    {
        private readonly ITemplateLocator _templateFinder;
        private readonly IRenderingService _renderService;
        private readonly IMailClient _mailClient;

        public EmailService(ITemplateLocator templateFinder, 
                            IRenderingService renderService, 
                            IMailClient mailClient)
        {
            if (templateFinder == null) throw new ArgumentNullException("templateFinder");
            if (renderService == null) throw new ArgumentNullException("renderService");
            if (mailClient == null) throw new ArgumentNullException("mailClient");
            _templateFinder = templateFinder;
            _renderService = renderService;
            _mailClient = mailClient;
        }

        public void Send<T>(string to, string subject, T body)
        {
            var template = _templateFinder.Locate(body);
            var htmlBody = _renderingService.Render(template, body);
            _mailClient.Send(to, subject, htmlBody);
        }
    }

    public class TemplateLocator : ITemplateLocator
    {
        private readonly string _basePath;

        public TemplateLocator(string basePath)
        {
            if (basePath == null) throw new ArgumentNullException("basePath");
            _basePath = basePath;
        }

        public string Locate<T>(T model)
        {
            var templateName = string.Format("{0}.cshtml", model.GetType().Name);
            return Path.Combine(_basePath, templateName);
        }
    }

    public class RazaorRenderingService : IRenderingService
    {
        public string Render<T>(string templatePath, T model)
        {
            using (var templateService = new TemplateService())
            {
                return templateService.Parse(File.ReadAllText(templatePath), 
                                             model, null, null);                
            }
        }
    }

    public class SmtpMailClient : IMailClient
    {
        public void Send(string to, string subject, string body)
        {
            using (var mesage = new MailMessage())
            {
                mesage.Subject = subject;
                mesage.Body = body;
                mesage.IsBodyHtml = true;
                mesage.To.Add(new MailAddress(to));

                using (var client = new SmtpClient())
                {
                    client.Send(mesage);
                }
            }
        }
    }
Constructor injection is preferred because:
  • All dependencies are located together - easily identify class dependencies
  • The number of dependencies are exposed - the fewer dependencies the better
  • Classes are instantiated with all dependencies - reduce the risk of invalid configurations
3. Composing the solution using DI

Let's wire it all up using a DI container as shown below.

  
            var container = new UnityContainer();
            container.RegisterType<IOrderRepository, OrderRepository>();
            container.RegisterType<IEmailService, EmailService>();
            container.RegisterType<IRenderingService, RazaorRenderingService>();
            container.RegisterType<IMailClient, SmtpMailClient>();
            container.RegisterType<IOrderService, OrderService>();

            var baseTemplatePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, 
                                                "EmailTemplates");
            container.RegisterType<ITemplateLocator, TemplateLocator>(
                                  new InjectionConstructor(baseTemplatePath));
4. Run the solution

The razor template is shown below.

 
@model Orders.Interfaces.Models.OrderModel

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>Order</title>
</head>
<body>
    <p>Hi @Model.Customer.Name,</p>
    <p>Thanks for placing the order.</p>
    <p>Your order number is: @Model.Id</p>
</body>
</html>

The App.config is configured to write the emails to C:\temp.

 
      <smtp deliveryMethod="SpecifiedPickupDirectory" from="[email protected]"
        <specifiedPickupDirectory pickupDirectoryLocation="C:\temp"  />
      </smtp>

Let’s create an order and get the OrderService to process it.

  
            var orderModel = new OrderModel()
            {
                Description = "Design Book",
                Customer = new CustomerModel() { Email = "[email protected]", Name = "Jay" }
            };

            var orderService = container.Resolve<IOrderService>();
            orderService.Create(orderModel);

The email output is shown below.


Summary

In this post we have described the process of using the DI pattern to provide inversion of control for resolving dependencies with Unity.

The advantages of DI is:
  • Testing is simplified since we can write unit tests per component/class
  • Mocking is simplified since we can mock/stub out behaviour
  • Small, well tested classes that only do one thing are often easy to understand
  • Coupling is reduced since classes often rely on interface abstractions instead of concretions
  • Works well with patterns such as decorators and interception
The disadvantages of DI is:
  • It may feel like you are writing a lot more code – but the code quality is better due to the reasons above
  • Wiring can become complicated which makes debugging trickier

Next: How to structure DI registrations cleanly

Kill the switch with the strategy pattern

Chain of Responsibility

The previous post described the challenge of validating credit card numbers based on the credit card type such as visa or master card. Many if conditional checks were performed which was improved using the switch statement.

Why was the switch statement bad?

Let's say you have 5 cases and 10 lines each.

  • What if we had to add, remove or modify a case? The class has 7 reasons to change, which violates the open/close principle.
  • At least 5 tests are required to test each case. The class does 5 things, so it violates the single responsibility principle.
  • The class is at least 50 lines long without the possibility of reusing anything.

This post will provide an illustration of using the strategy design pattern with table control flow to replace the switch statement.

The problem is how we can define a family of algorithms (credit card validators), encapsulate each one, and make them interchangeable?

The solution is to use the strategy design pattern that allows the algorithm to vary independently from clients that use it.

Download Source Code

Setup

The following classes from the previous post will be reused.
  
    public class CreditCard
    {
        public string Type { get; set; }
        public string Name { get; set; }
        public string Number { get; set; }
        public string Expiry { get; set; }
    }

    public interface ICreditCardValidator
    {
        void Validate(CreditCard creditCard);
    }

Strategy Pattern

Let's get started with the strategy pattern in 5 easy steps.

1. Specify the signature for the algorithm in an interface

We need to validate a credit card number so we need a method that takes a number as shown below.

  
    public interface ICreditCardNumberValidator
    {
        void Validate(string number);
    }
2. Bury the algorithm implementation details in derived classes

Each credit card validator implementation can be different. In this example, all credit card validators will use a regular expression so we only need one class.

  
    public class RegExCreditCardNumberValidator : ICreditCardNumberValidator
    {
        private readonly Regex _regex;

        public RegExCreditCardNumberValidator(Regex regex)
        {
            if (regex == null) throw new ArgumentNullException("regex");
            _regex = regex;
        }

        public void Validate(string number)
        {
            if (!_regex.IsMatch(number)) throw new InvalidCreditCardException();
        }
    }

A new instance of the class will be created for each credit card type. For example:

  
  var visaRegEx = new Regex("^4[0-9]{6,}$", RegexOptions.Compiled);
  var visaValidator = new RegExCreditCardNumberValidator(visaRegEx);
3. Identify an algorithm that the client would prefer to access

The credit card validation algorithm is based on the credit card type. The credit card type is supplied in the credit card model/DTO. Therefore, we can perform an algorithm lookup based on the credit card type.

A dictionary is great way to perform a lookup, where the key represents the credit card type and the value represents the validator.

  
  var strategies = new Dictionary<string, ICreditCardNumberValidator>
                         (StringComparer.OrdinalIgnoreCase);

The strategy validator is shown below.

  
    public class CreditCardValidatorStrategy : ICreditCardValidator
    {
        private readonly IDictionary<string, ICreditCardNumberValidator> _strategies;

        public CreditCardValidatorStrategy(
                        IDictionary<string, ICreditCardNumberValidator> strategies)
        {
            if (strategies == null) throw new ArgumentNullException("strategies");
            _strategies = strategies;
        }

        public void Validate(CreditCard creditCard)
        {
            if (creditCard == null) throw new ArgumentNullException("creditCard");
            if (string.IsNullOrWhiteSpace(creditCard.Type)) 
               throw new ArgumentException(Resource.MissingCreditCardType);
            if (!_strategies.ContainsKey(creditCard.Type)) 
               throw new InvalidCardException(
                   string.Format(Resource.UnsupportedCreditCard, creditCard.Type));
            _strategies[creditCard.Type].Validate(creditCard.Number);
        }
    }
4. Building the table control lookup

We can build the dictionary lookup table based on a repository such as a database or a configuration file.

The credit card types and regular expressions are defined in the App.config as shown below.

 
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="creditcardnumberexpressions" 
             type="System.Configuration.DictionarySectionHandler" />
  </configSections>  
  <creditcardnumberexpressions>
      <add key="visa" value="^4[0-9]{6,}$" />
      <add key="mastercard" value="^5[1-5][0-9]{5,}$" />
  </creditcardnumberexpressions>
</configuration>

We can compose the dictionary of strategies from the App.config as shown below.

  
    public class ConfigDictionaryLoader : ISettingsLoader
    {
        private readonly string _sectionName;

        public ConfigDictionaryLoader(string sectionName)
        {
            if (sectionName == null) throw new ArgumentNullException("sectionName");
            _sectionName = sectionName;
        }

        public IDictionary<string, string> Load()
        {
            var settings = ConfigurationManager.GetSection(_sectionName) as Hashtable;
            if (settings == null) {
               throw new Exception(string.Format(Resource.MissingConfig, _sectionName));
            }
            return settings.Cast<DictionaryEntry>()
                           .ToDictionary(n => n.Key.ToString(), n => n.Value.ToString());
        } 
    }

    public class CreditCardValidatorFactory : ICreditCardValidatorFactory
    {
        private readonly ISettingsLoader _loader;

        public CreditCardValidatorFactory(ISettingsLoader loader)
        {
            if (loader == null) throw new ArgumentNullException("loader");
            _loader = loader;
        }

        public IDictionary<string, ICreditCardNumberValidator> CreateStrategies()
        {
            var cardPairs = _loader.Load();
            var strategies = new Dictionary<string, ICreditCardNumberValidator>
                                   (StringComparer.OrdinalIgnoreCase);
            foreach (var pair in cardPairs)
            {
                var regEx = new Regex(pair.Value, RegexOptions.Compiled);
                strategies[pair.Key] = new RegExCreditCardNumberValidator(regEx);
            }
            return strategies;
        }
    }
5. Running the solution
The entire solution is wired up as shown below.
 
            var configLoader = new ConfigDictionaryLoader("creditcardnumberexpressions");
            var creditCardFactory = new CreditCardValidatorFactory(configLoader);
            var strategies = creditCardFactory.CreateStrategies();
            var validator = new CreditCardValidatorStrategy(strategies);
           
            var creditCard = new CreditCard()
            {
                Type = "ViSa",
                Number = "4111111111111111"
            };

            validator.Validate(creditCard);

Summary

The strategy pattern provides a great alternative to the switch statement.

The advantages of the strategy design pattern are:

  • Reduces long lists of conditions such as If and Switch statements
  • Avoids duplicate code
  • Changes in one class does not require changes in other classes
  • The Open-close principle is achieved since the class is open for extension but closed for modification
  • The Single responsibility principle is achieved since the complexity is encapsulated per strategy
  • Unit testing is simplified since each strategy can be tested in isolation

Problem solving beyond the basics

Chain of Responsibility

Part of my role is to review code and to coach developers.

Reviewing code provides insight into a range of techniques to solve problems. Like many developers, we often steal each other’s ideas. To become a good thief, you really need to be able to identify what is valuable so that you don’t steal someone else’s rubbish code.

Whilst coaching developers, I often take the code submitted for a code review and ask the person I’m coaching to review it. This technique helps to assess the fidelity of a developer to identify good and bad code. It also exposes new potential skills that can be coached or helps with confirming that a developer has mastered a skill.

The aim of this post is to show a working solution and discuss potential problems. A follow up post will provide an alternative that will solve these problems.

Setup

The problem we are trying to solve is to validate a credit card number based on the credit card type. The credit card context model / data transfer object (DTO) is shown below.

  
    public class CreditCard
    {
        public string Type { get; set; }
        public string Name { get; set; }
        public string Number { get; set; }
        public string Expiry { get; set; }
    }

    public interface ICreditCardValidator
    {
        void Validate(CreditCard creditCard);
    }

Code Review

The solution that was submitted for a code review is shown below.

  
    public class CreditCardValidator : ICreditCardValidator
    {
        public void Validate(CreditCard creditCard)
        {
            if (creditCard.Type.ToLower() == "visa")
            {
                var visaRegEx = new Regex("^4[0-9]{6,}$");
                if (!visaRegEx.IsMatch(creditCard.Number)) 
                      throw new Exception("Invalid card");
            }
            else if (creditCard.Type.ToLower() == "mastercard")
            {
                var masterCardRegEx = new Regex("^5[1-5][0-9]{5,}$");
                if (!masterCardRegEx.IsMatch(creditCard.Number)) 
                      throw new Exception("Invalid card");
            }
            else
            {
                throw new Exception(string.Format("Card type {0} is unsupported.", 
                                                  creditCard.Type));
            }
        }
    }

Code Smells

Let's run through a standard set of heuristics to identify code smells.

  • Duplicate code – both If statements uses a fairly similar pattern but it doesn’t appear to justify refactoring
  • Long method – the method length appears to be acceptable
  • Large class – the class fits on one screen and it doesn’t appear to be too large
  • Too many parameters – it only has one parameter so that's fine
  • Overuse of inheritance – no inheritance at all
  • Not testable – the class implements an interface which suggests that clients rely on a contract instead of a concrete implementation which promotes mocking and the class appears to be easily testable

Code Problems

Even though the code doesn't appear to have code smells, the code is not great. Here is a list of problems with the code:

  1. Guard Exception – an ArgumentNullException should be thrown before line 5 when the client calls the validator with a null credit card instance
  2. NullReferenceException – the client will receive an “object reference not set to an instance of an object” exception on line 5 when the card type is null
  3. Throwing Exceptions – throwing custom exceptions such as InvalidCreditCardNumberException is better than throwing a generic Exception which is harder to catch and bubble up
  4. Immutable String Comparison – at least the code is case insensitive using .ToLower() although strings are immutable so the .ToLower() comparison will create a new copy of the string for each if statement. We could just use the string comparison function such as creditCard.Type.Equals("visa", StringComparison.OrdinalIgnoreCase)
  5. Constants – we should avoid using magic strings and numbers in code and use constants instead for names such as credit card names. A CreditCardType Enum could be an alternative if the credit card types are fixed.
  6. Readability – as the number of supported credit cards grows, readability can be improved with a switch statement
  7. Globalisation – error messages can be placed in resource files to provide multilingual support
  8. Performance – the regular expression is created for every credit card number that is validated which can be changed to a singleton. We can use the RegEx compile parameter to improve the execution time.
An alternative solution using a switch statement is shown below.
  
    public class CreditCardValidator : ICreditCardValidator
    {
        private static readonly Regex VisaRegEx = 
                   new Regex("^4[0-9]{6,}$", RegexOptions.Compiled);
        private static readonly Regex MasterCardRegEx = 
                   new Regex("^5[1-5][0-9]{5,}$", RegexOptions.Compiled);

        public void Validate(CreditCard creditCard)
        {
            if (creditCard == null) throw new ArgumentNullException("creditCard");
            if (string.IsNullOrWhiteSpace(creditCard.Type)) 
                   throw new ArgumentException("The card type must be specified.");

            switch (creditCard.Type.ToLower())
            {
                case "visa":
                    if (!VisaRegEx.IsMatch(creditCard.Number)) 
                         throw new InvalidCardException("Invalid card");
                    break;
                case "mastercard":
                    if (!MasterCardRegEx.IsMatch(creditCard.Number)) 
                         throw new InvalidCardException("Invalid card");
                    break;
                default:
                    throw new InvalidCardException(
                         string.Format("Card type {0} is unsupported.", creditCard.Type));
            }
        }
    }

Even though the code was improved, the design is still poor and breaks SOLID principals.

  1. Open/Closed Principal - The class might be small but is hard to extend by supporting additional credit cards without modifying the code
  2. Single Responsibility Principle - The class knows too much about various credit card types and how to validate them

Summary

The post identified issues with a working solution and discussed fundamental coding practices.

If you can spot more issues, please let me know. If you know how to solve the problem then I’d love you hear from you too.

The next post will discuss how the design can be improved by applying a design pattern.