Strategy Design Pattern

A different strategy but same interface.

Brief Overview of The Strategy Pattern

The Strategy or Policy Pattern is one of the behavioral design patterns from the gang of four design patterns book. It is primarily used when the specific implementation or algorithm cannot be determined until runtime.

When To Implement

There are several common software design problems that are easily solved by implementing the strategy pattern:

  • There are a number of classes that have the same attributes but vary in a specific method implementation. By implementing the strategy pattern a single method call can now have many behaviors.
  • There is one action that can be implemented in various ways.  The strategy pattern will allow for the correct implementation to be chosen at runtime.
  • There is a class that has many different behaviors that are being determined by multiple if statements. The strategy pattern helps here by moving the related conditional branches into their own classes.

Strategy Pattern Components

The strategy pattern is typically comprised of three components and a client. The first component is the context which is used to return the correct concrete strategy at runtime.  The second component is a class that acts as the base strategy which is typically a parent class that has the strategy method implemented as an abstract method (the whole class is abstract). The third component is the concrete strategies which inherit from the parent strategy class and have specific implementations of the abstract method.  The client will have a context and the context will have a reference to the strategy object and using polymorphism will be configured with the correct concrete strategy at runtime.

Implementation of the Strategy Pattern

This implementation uses the basic structure of the design pattern.

The Context

The context is essentially used to determine which concrete strategy is needed by passing in some condition, for this example the temperature to convert from, and then instantiating it and allowing the client to interact with it using the sub class’s concrete implementation of the abstract method.


class TempConvertInterfaceContext

   #the initialize methods figures out the concrete strategy and then assigns it
   #to the convert strategy instance variable.  Typically this would be an if
   #statement in some implementations but ruby allows us to do a little meta
   #programming.

   def initialize(convert_from)
     @convert_strategy =
     Object.const_get("#{convert_from.capitalize}Strategy").new
   end

   def convert_temperature(convert_to, temperature)
     @convert_strategy.convert_temperature(convert_to, temperature)
   end

end

Abstract Interface For Concrete Strategies

All concrete instances of the strategy should inherit from this class and implement the abstract method so the context and client do not have to care about the implementation. The point of the interface is to define a method that must be implemented in all sub classes.


class StrategyInterface

  #In ruby we really don't need this interface at all.  Ruby will throw
  #a NoMethod error if a method doesn't exist which is essentially what
  #I am doing here. For sake of sticking to the GOF implementation I will
  #use this class and method as an interface.
  def convert_temperature(convert_to, temperature)
    raise "Must implement this method."
  end

end

Concrete Implementations of Strategy Interface

Each of these classes inherits from the StrategyInterface class and implements the abstract convert_temperature method.

class KelvinStrategy < StrategyInterface

  def convert_temperature(convert_to, temperature)
    case convert_to
    when 'celsius'
      temperature - 273.15
    when 'fahrenheit'
      temperature * 9.0 / 5.0 - 459.67
    when 'kelvin'
      temperature
    else
      raise "This Scale is currently not supported"
    end
  end

end
class FahrenheitStrategy < StrategyInterface

  def convert_temperature(convert_to, temperature)
    base_calculation = (temperature - 32) * 5.0 / 9.0
    case convert_to
    when 'celsius'
      base_calculation
    when 'kelvin'
       base_calculation + 273.15
    when 'fahrenheit'
       temperature
    else
       raise "This Scale is currently not supported"
    end
  end
end
class CelsiusStrategy < StrategyInterface

  def convert_temperature(convert_to, temperature)
    case convert_to
    when 'fahrenheit'
      temperature * 9.0 /5.0 + 32
    when 'kelvin'
      temperature + 273.15
    when 'celsius'
      temperature
    else
      raise "This Scale is currently not supported"
    end
  end

end

The Client

The client is essentially the driving mechanism that needs to use the strategy but doesn’t know which of the strategies it will need until runtime.


class Client
  # The client has a context which is used to determine the
  # specific concrete strategy and then return that strategy back to the client.
  # The values in this array are different concrete strategies that
  # will be chosen at runtime to implement.
  ['fahrenheit_to_celsius', 'fahrenheit_to_kelvin', 'celsius_to_fahrenheit',
  'celsius_to_kelvin', 'kelvin_to_celsius', 'kelvin_to_fahrenheit'].each do | temperature_scale_conversion_direction |
      #Parsing the string into the two temperature scales.
      convert_from, convert_to = temperature_scale_conversion_direction.split(/_to_/)
      #This instantiates the context with the
      #specific concrete strategy and returns the concrete strategy.
      temp_converter = TempConvertInterfaceContext.new(convert_from)
      #Printing the converted temperature.
      puts temp_converter.convert_temperature(convert_to, 0)
    end
end

Get the Code

Here is the Github repository for the code. You will notice I also made another version more idiomatic to ruby using Procs.

Final Thoughts

The Strategy Pattern is extremely handy to use when you need to check the type of something and then perform an action on it. If the type is not known until runtime, using the context to return the correct strategy removes the burden from the client, who in all honesty should not care about the implementation at all.

Ruby Gem

I created a ruby gem from this post it can be found here.  The source code for the gem can be located here.

Minimizing Scope When Changing Existing Codebases

Take time to think about all the changes to a codebase while implementing a feature or a bug fix.

The Problem

When asked to make changes to an existing codebase , software developers tend to only focus on accomplishing the task and less on preserving the integrity of the existing codebase.  Whether this assignment is a small feature or bug fix, a developer is often asked to accomplish it by a deadline.  For an experienced developer, this is business as usual, and they have learned enough lessons for this not to be a problem. However, for an inexperienced developer, they will often neglect to consider something very important while implementing the software solution: the scope or effects of their changes in relation to the existing codebase.

The Example

After I had been at my first job in the industry for a month or so I had done nothing but bug fixes.  One day the head of the IT department called me into his office and asked me if I wanted to put a small feature in a legacy Rails 1.X application. Naturally I jumped at this opportunity to prove to him I was capable of more than just bug fixes.

The Failure

Initial Success

The task was nothing terribly complicated and I finished the majority of it without much trouble. When I was done I told the lead developer on the application and was instructed to test all of my changes manually (no testing suite for an application this old) for all the browser versions we supported.

Internet Explorer 7

When I was implementing this feature, one thing that I had never done before was a rounded border on HTML blocking elements.  Implementing rounded borders was rather easy after a little research (googling).  However, when I went to the page with the rounded borders using the test environment that emulated Internet Explorer 7 (IE7) my rounded borders were square.  I was determined to match the mockups given to me by the graphic designers and be deemed worthy of being given more complicated features. So I did even more research to figure out rounded borders in IE7 and I came across the answer. To save you a click, it is stated that if this line <meta http-equiv="X-UA-Compatible" content="IE=7" /> is present rounded borders will not work in IE &.  I quickly went to the root of the layout of the application and there it was, BINGO!  I changed the meta tag to  <meta http-equiv="X-UA-Compatible" content="IE=9" /> and voila, it worked!

The Fire

With testing complete and functionality completely on par with the specifications, I told my lead developer that I was done.  My code was pushed to production about noon that day and I headed to lunch.  When I got back from lunch the account manager that handles that application came to my desk right away.  She was telling me how users of the application couldn’t log a metric they needed to do daily (a very big deal). Immediately I thought to myself that I had never altered any of the code that dealt with metric logging so this is not my fault at all. Thankfully, I did not tell the account manager that and I told her I would be happy to investigate.

The Investigation

I quickly spun up the application locally and started to try to replicate the bug.  Sure enough, I could not log the metric either.  Thing is that I wasn’t getting any errors in the browser console or in the server log.  So, I started my normal bug fixing procedures and pursued that while constantly updating the account manager about the lack of progress I was having.  Quickly I began to panic and just as I was about to ask the lead developer to help me investigate, I did a quick check of the commits I made for that feature.  In my mind I thought all of the changes were in new files and so they shouldn’t be affecting functionality from existing files, right?  Well I was wrong about ALL of my changes being in existing files. I did make the one change to the root layout of the application which the whole application used.

The Fix

I stared at the line for about two minutes in complete shock.  Could me have changing this single meta tag have caused this huge inconvenience to the user base?  In the end, I changed the line back and tested the logging.  It worked and all was well again. The users could log the metric they needed to, and after speaking with the lead developer I realized that the lack of rounded borders in that application was known and expected.

The Lesson

The lesson to me now seems pretty obvious: the scope of feature should be the only place code changes occur.  What I mean by that is, say you are working on feature A and it involves files A, B, and C and while you are implementing your feature you run into a problem with a value being set in a variable in file D.  Your first inclination may be to change the value being set so your feature works.  Well I am here to tell you, you SHOULD NOT change the value in file D.  Instead you should look at how you designed your feature or bug fix and make it work with the value set in file D.  This might mean a quick redesign of a function or even starting implementation from scratch.  However the alternative is to risk breaking user space (which is a no no) and then having a fire to extinguish.

Post Mortem

After all of this I did a little introspection on how and why this happened.  After much thought, I came to the conclusion that it was because of one reason.  This reason was because I was too eager to prove myself and never once took a step back to ask, is this change outside of the feature I am working on?  Now, a little more seasoned from failure, I make sure before I contemplate making a change to a file that is out of scope of the feature to seriously consider all ramifications of the change.  Unsurprisingly, 10 out of 10 times I find a way to redesign my code to work without making those changes.

Singleton: One is the Loneliest Number

Being single can be fun just ask the singleton.

What is a Singleton?

A singleton is a creational design pattern in which a class is responsible for the creation and management of its sole instance and it provides a way for the instance to be accessed from the global namespace.

For more information on the singleton pattern I highly recommend Source Making’s explanation.

The Singleton and Me

Currently I use a custom logging mechanism that is implemented using the singleton pattern and a more basic version of this will be what I use in the code example. The logger needs to behave differently based on the environment in which it is executed (development, testing, or production). Loggers in general are typically designed as a singleton.  Subclassing a singleton is not different logistically as it would be with any other class. The trick is to make sure that proper instance is available when requested.  For this purpose I used a registry of singletons.

Let’s Get to the Code

The code below is written in ruby and is one of the many ways to create a singleton along with its registry in this language.  It is composed of the Logger class and two of its children, the ProductionLogger and the DevelopmentLogger.

The Logger Class

class Logger

  @@instance = new

  def initialize *args, &block
    populate_registry
  end

  def self.instance
    Logger.singleton_registry_look_up ENV['DEVELOPMENT_ENVIRONMENT']
  end

  #using a mutex for thread safety
  def self.mutex
    @mutex ||= Mutex.new
  end

  def self.registry
    @registry ||= {}
  end

  #force all children to implement log so there is a common interface
  def log information
    raise "Must Implement Log Method"
  end

  def close
    @log.nil? ? (raise "Must Declare Log Variable as @log") : @log.close
  end

  def self.singleton_registry_look_up singleton_name
    self.registry[singleton_name.to_sym]
  end

  private

  def register singleton_name, logger_type
    self.class.registry[singleton_name.to_sym] = logger_type
  end 

  #major drawback of using static variables is that all subclasses have to be
  #instantiated so that they can be registered
  def populate_registry
    ["DevelopmentLogger", "ProductionLogger"].each do |logger_type|
       register logger_type, Object.const_get(logger_type).send(:new)
    end
  end

  def logger_mutex
    self.class.mutex.synchronize { yield }
  end

  private_class_method :new
end
What Makes Logger Class a Singleton

Making the Logger.new method private keeps new Logger instances from being created, the only Logger instance belongs in the @@instance class variable.

Setting Up the Registry of Singletons

When the new method is called and assigned to the @@instance variable it performs new’s normal duties which involves calling the private method initialize . The initialize method on the Logger class starts a chain of events that create the registry and then populates it.

The registry itself, a hash, holds the name of the classes (keys) and also an instance of the class (values). The point of the registry of singletons is to provide the correct instance when an instance is requested. This is done via the Logger.singleton_registry_look_up which takes the string name of the class and returns an instance. I prefer to read the string from the environment but there are other ways to do this as well.

The DevelopmentLogger Class

class DevelopmentLogger < Logger

  def initialize *args, &block
    @log = File.open('log/development.log', 'a')
  end

  def log information
    #development log does not need to redact any information
    logger_mutex { @log.puts information }
  end

end

This class inherits from the Logger class and overwrites the initialize method to assign the proper log file to the class variable called @log . It also implements the log method which is abstracted in the parent.  The log method literally just appends the argument to the file assigned to the @log variable.

The ProductionLogger Class

class ProductionLogger < Logger

  def initialize *args, &block
    @log = File.open('log/production.log', 'a')
  end

  def log information
    #the actual password should be redacted in production log
    logger_mutex { @log.puts information.gsub(/(?<=password:\s).*/im, "FILTERED") }
  end
end

This class also overwrites the initialize method and opens the correct log for production.  The ProductionLogger’s log implementation filters out any potential passwords that meet the regular expression from the log file.

Using the Logger Class

#inject into the application
load './logger.rb'

#access the instance
LOGGER = Logger.instance

#write to log
LOGGER.log "Hello Log!"

Using load to inject the Logger into your application executes the @@instance assignment.  Assigning the Logger.instance to a constant ensure reassignment won’t happen later.

The Singleton and Its Registry

There are plenty of reasons people do not use the singleton design pattern. Furthermore using a registry can cause further implementation problems. One implementation choice I struggled with was when and how to register subclasses in the registry. I came to the conclusion that it varies on language and needs. Even though the singleton does have drawbacks in my opinion there are valid use cases for them. For instance a logger being implemented as a singleton alleviates the probability of several different objects trying to access the same resource (usually a file) at the same time. If you throw in some thread safety you can be confident the log file has optimal integrity.

Find the Code

Singleton With Registry Repo

* For the sake of this tutorial I did not use ruby’s multiton or singleton modules, however the same effect could have been achieved with them.