That’s the Strategy! Strategy Design Pattern :)

While working on a project, it is crucial to remember that you do not want to reinvent the wheel. If a solution for a problem is proved to be effective, reusing it will save you tons of time and a few headaches. In case of system architecture dilemmas, we have developed some patterns to ease a design process.

What is a design pattern?

A design pattern is a conceptual model that helps you solve design problems in various contexts. It is like a reusable template you can apply to a structuring code. The thing is, design patterns are well-documented, well-proven and commonly known. In other words, use a proper design pattern and be sure that other design pattern insiders (aka your coworkers) will get the hang of your ideas smoothly.

Eager to learn? Here comes the Strategy Design Pattern.

The strategy design pattern:

– defines a family of algorithms,

– implements each of the algorithms as a separate entity,

– allows each of the algorithms to be used interchangeably in a given context.

Real life example? Authentication

In one of our apps we have implemented a few strategies for authenticating requests. We allow authentication with cookies, JWT tokens and API keys. Sounds like a family of algorithms to me.

Let’s have a look at a sample implementation.

We have our family of authentication algorithms divided into three separate classes. Each class defines the concrete behavior; it is where all the implementation details go:

module AuthenticationStrategies
  class CookiesAuthentication
    def self.authenticate_request(request)
      puts "I implement a cookie authentication algorithm"
    end
  end
class JWTAuthentication
    def self.authenticate_request(request)
      puts "I implement a jwt authentication algorithm"
    end
  end
class ApiKeyAuthentication
    def self.authenticate_request(request)
      puts "I implement an api key authentication algorithm"
    end
  end
end

Then, we have a context/client class:

class Authentication
  def self.authenticate(authentication_strategy, request)
    authentication_strategy.authenticate_request(request)
  end
end
request = "I pretend to be a request"
Authentication.authenticate(AuthenticationStrategies::CookiesAuthentication, request)
Authentication.authenticate(AuthenticationStrategies::JWTAuthentication, request)
Authentication.authenticate(AuthenticationStrategies::ApiKeyAuthentication, request)

The above script outputs:

I implement a cookie authentication algorithm
I implement a jwt authentication algorithm
I implement an api key authentication algorithm

Summing it up

– design patterns are useful tools for solving architectural problems,

– knowledge of design patterns improves communication on system architecture with other developers,

– the Strategy Design Pattern suits your needs if you have a bunch of algorithms that can be used interchangeably in a given context.