How To Build Future Proof Applications?
Programming Python Using Design Patterns
This article aims to explain how we can implement an application in Python that is future proof, scalable, easier to update, support and maintain.
But Python is just a Prototype language; we hear many people say! The reality is far from it. You can take Python application to your Production environment as long as it is implemented and has followed the right software principles.
I want to elaborate on how we can use well-tested design patterns to implement a Python application.
What Is A Design Pattern?
Design pattern is a set of design steps which can be followed to solve reoccurring problems that the software experts have resolved in the past.
There are three categories of design patterns:

Design patterns encourage clean, easy to understand and testable code.
Use Design Patterns To Implement An Application With Long Life
I will be explaining following design patterns with real-life FinTech use cases:
- Builder
- Template
- Strategy
- Decorator
I will be presenting the real-life FinTech problems that the design patterns can solve.
1. Let’s Understand Builder Design Pattern
1.1 What Is The Builder Design Pattern?
- Builder design pattern is used to build complex objects (usually a composite).
- It separates the construction of a complex object from its representation.
- It is one of the most used creational design patterns.
- It encourages developers to create a domain specific language.
- Furthermore, it helps developers learn business terminology faster.
If your object has a number of mandatory and optional properties and its creation is complex then use builder design pattern instead of creating many constructors, or a
constructor with many optional parameters
1.2 Builder Design Pattern Use cases
Use builder design pattern if:
- Your application can have multiple representations of a complex object
- You want to construct a complex object in steps
- You want a developer friendly API to construct a complex object
- You want to build an object in an order and only want to use the object once it is finished building
- If you intend to write domain driven programming
- If you want to write code that’s easier to read and understand
- If you want to avoid multiple constructors with optional parameters
1.3 Builder Design Pattern Example
This is a hypothetical example to illustrate how builder pattern works:
Let’s consider:
- We are implementing a trade entry application for a hedge fund. Traders are planning to use the application to manage bond trades.
- We implement a Bond class to represent a bond trade in our system.
- Each bond object has a large number of properties; a mix of mandatory and optional properties.
- Let’s assume that the following properties are mandatory, implying that a bond trade is incomplete without these 5 properties:
- Maturity Date
- Start Date
- Coupon
- Yield Rate
- Notional
Additionally, following properties of a bond class are optional:
- Bond Holder name
- Bond Issuer Name
1.4 Scenario
We are required to create following 3 bonds:
- Bond A — with only mandatory properties
- Bond B — with all mandatory properties + issuer name property populated
- Bond C — with all mandatory properties + both optional issuer and holder name properties populated
Instead of passing all mandatory and optional properties via constructor every where in the code, use builder design pattern.
Question: How Should We Implement It?
Use Builder Design Pattern
1.4 Implementation Steps
1.4 A. Create Bond Class
- Create a constructor in bond class which sets the five mandatory properties:
class Bond:
def __init__(self, MaturityDate, StartDate, Coupon, YieldRate, Notional):
self.__MaturityDate = MaturityDate
self.__StartDate = StartDate
self.__Coupon = Coupon
self.__YieldRate = YieldRate
self.__Notional = Notional
self.__BondHolderName = None
self.__BondIssuerName = None1.4 B. Create a Bond Builder class: The sole responsibility of your bond builder class is to build a bond object in the right order by:
- Initializing bond with all of its mandatory properties
- Allowing callers to set the bond’s optional properties
- Finally build_bond() method needs to return a completely built bond object.
Each method of BondBuilder class should return self (The Bond Builder Class). This will then provide us with a FluentApi feel.
The build_bond() method should return the actual fully built bond object.
You can only instantiate bond class in BondBuilder’s build_bond() method once all required properties are set.
class BondBuilder:
def initialise_bond(self, MaturityDate, StartDate, Coupon, YieldRate, Notional):
self.__my_bond = Bond(MaturityDate, StartDate, Coupon, YieldRate, Notional)
return self
def set_issuer_name(self, Isser_Name):
self.__my_bond.__Isser_Name = Isser_Name
return self
def set_bond_holder_name(self, BondHolderName):
self.__my_bond.__BondHolderName = BondHolderName
return self
def build_bond():
#validate if self.__my_bond is NONE then raise error
return self.__my_bondThe code below illustrates how we can build different variations of bonds using builder pattern to meet the goal we set for ourselves above.
The fluent API makes the code readable.
BondA = BondBuilder()
.initialise_bond(MaturityDate, StartDate, Coupon, YieldRate, Notional)
.build_bond()BondB = BondBuilder()
.initialise_bond(MaturityDate, StartDate, Coupon, YieldRate, Notional)
.set_bond_holder_name(BondHolderName)
.build_bond()BondC = BondBuilder()
.initialise_bond(MaturityDate, StartDate, Coupon, YieldRate, Notional)
.set_bond_holder_name(BondHolderName)
.set_issuer_name(Isser_Name)
.build_bond()If we need to create different variations of bond with more optional or mandatory properties then we can simple extend our bond builder class.
1.5 Builder Pattern Summary
- Builder pattern makes your code easier to test, maintain and understand.
- We can use builder pattern to make code thread-safe. To elaborate, if we make bond class immutable by ensuring all properties are read-only and can only be set via constructor then we can use Builder design pattern to ensure that the state of bond object cannot be changed.
- We can then share bond objects in our application without facing any race-conditions due to bond objects.
- It gives you a nice to use fluent API that can help you understand domain better.
If you want to understand what bond financial product is then please read:
2. Let’s Understand Template Design Pattern
2.1 What Is The Template Design Pattern?
Template design pattern is one of the most used patterns in software applications.
Template design pattern is:
- A common behavioral software development pattern.
- It ensures your program follows a prescribed behavior.
- If we want to implement an algorithm that contains a number of steps/instructions then we can use template software design pattern.
If the behaviour of steps within an algorithm can vary yet we want to enforce that the steps of the algorithm are executed in a sequence then use template design pattern.
2.2 Template Design Pattern Use cases
- Template design pattern is used to encourage clean design and code re-usability.
- The template base class outlines steps of an algorithm.
- It ensures that the steps are executed in the right order.
- The steps are hidden from the outside caller.
Template pattern ensures that the code is clean, follows SOLID principles as each class has a single responsibility and can be easily tested.
2.3 Scenario
Let’s assume we are working in a FinTech data science application. We are required to use the test statistics algorithm to validate our hypothesis. These algorithms contain following sequence of steps:
- State Your Expected Claim
- Determine Your Significance Level
- Calculate Observed Results
- Calculate Test Statistic
- State Actual Claim.
There are different variations of test statistics algorithm. As an instance, one can perform T-Test or Z-Test on a hypothesis.
The task is to implement T and Z Test algorithm and ensure that all of the steps are identical, except Step 4 Calculate Test Statistic.
Question: How Should We Implement It?
Use Template Design Pattern
- We are going to code test statistics algorithm using template design pattern.
- We will code two variations of the algorithm to demonstrate that the template design pattern is a suitable candidate for this problem.
- To avoid duplication of code, we are going to implement a skeleton of steps in the right order in an abstract class.
2.4 Implementation Steps
In this section, I will outline basic structure of template design pattern and then I will further explain the concepts via examples:
- Base class: Template or skeleton of an algorithm is defined in an abstract base class. The skeleton outlines steps of an algorithm. Base class is implemented to prevent duplication of code and it encourages code re-usability.
- Sub-classes: Variations of algorithm are implemented in the sub-classes. The sub-classes override steps of the algorithm and provide their own functionality.
Common code is implemented in the base class. Caller invokes the method that then executes the steps within the template in a sequence. Variations of the algorithm are implemented in sub-classes that override the required template methods.
- An Abstract Class: BaseTestStatisticProcess class will implement Calculate() method. This method will define template of algorithm which will execute primitive operations. The base class will also contain a protected abstract CalculateTestStatistic() method that the sub-classes will need to override.
- Two Concrete Classes: ZTestStatiticProcess and TTestStatisticProcess will be two sub classes. These sub-classes will implement the primitive operations: CalculateTestStatistic().
- Each subclass will provide its own implementation of the test statistic.
Coding
This is a sample code to illustrate how template pattern works:
#Template class
import abc
class BaseTestStatisticProcess(metaclass=abc.ABCMeta):
def StateYourExpectedClaim(self):
#..put logic here
pass
def DetermineYourSignificanceLevel(self):
#..put logic here
pass
def CalculateObservedResults(self):
#..put logic here
pass @abc.abstractmethod
def CalculateTestStatistic(self):
#..put logic here
pass
def StateActualClaim(self):
#we are going to override it
pass
#main method
def Calculate(self):
self.StateYourExpectedClaim()
self.DetermineYourSignificanceLevel()
self.CalculateTestStatistic()
self.StateActualClaim
#Sub classes
class ZTestStatiticProcess(BaseTestStatisticProcess):
def CalculateTestStatistic(self):
#..put specific logic here
pass
class TTestStatiticProcess(BaseTestStatisticProcess):
def CalculateTestStatistic(self):
#..put specific logic here
passCalculateTestStatistic is an abstract method and any subclass that implements the abstract class needs to provide implementation for it. This is our template.
The sub classes will automatically execute all of the steps in the right order once the Calculate() method is executed:
ZTestStatiticProcess().Calculate()
TTestStatiticProcess().Calculate()2.5 Template Pattern Summary
- Implementing algorithms in code is a common task of a software developer.
- Algorithms are instructions or steps which need to be performed in specific order to achieve desired results.
- We can use Template Software Design Pattern to implement algorithms.
- Template design pattern is used to encourage clean design and code re-usability.
- The template base class outlines steps of an algorithm. It ensures that the steps are executed in the right order.
- The steps are hidden from the outside caller.
- Template pattern ensures that the code is clean, follows SOLID principles as each class has a single responsibility and can be easily tested.
If you want to understand how test statistics work, please read:
3. Let’s Understand Strategy Design Pattern
3.1 What Is The Strategy Design Pattern?
Strategy design pattern is one of the simplest design patterns to understand. It is one of the most famous behavioral software design patterns.
When you have a family of algorithms, all providing common behaviour and you want to change the algorithm without impacting the client code that calls it then you can use strategy pattern.
3.3 Strategy Design Pattern Use cases
- A strategy is essentially an algorithm (instructions in code) that is implemented to achieve a specific goal.
- If there are a number of methodologies (strategies) available to solve a problem then strategy design pattern can be implemented.
- It enables us to switch implementations for different situations.
- It also allows us to add new strategies without re-coding and testing all parts of the system.
3.3 Strategy Design Pattern Example
An interest rate swap is a financial product. It can be priced using two strategies: FRA or Bond strategy.
Let’s assume we are implementing a trade pricer application for a Hedge Fund and we are required to price an interest rate swap trade. The analysts have provided us with two strategies and now we need to be in a place to change them interchangeably.
3.4 Implementation Steps
There are essentially 3 steps of strategy implementation:
- Implement a contract for your algorithm. This will be the interface e.g. ISwapPricer. Interface can contain a public method which you want external callers to execute e.g. PriceSwap(…)
- Implement your algorithms in concrete classes. We can implement the two IRS pricing methodologies in the two classes e.g. SwapPricerBondStrategy and SwapPricerFRAStrategy can be the two classes.
- Ensure the derived classes implement ISwapPricer interface.
- Client of the application can choose and execute appropriate algorithm.
- Create an Interest Rate Swap class that will hold all deal specific properties. Pass it to the PriceSwap method of the strategy.
import abc
class ISwapPricer(metaclass=abc.ABCMeta): @abc.abstractmethod
def PriceSwap(trade):
pass
class SwapPricerBondStrategy(ISwapPricer):
def PriceSwap(trade):
#__price swap how we price two bondsclass SwapPricerFRAStrategy(ISwapPricer):
def PriceSwap(trade):
#__price swap how we price FrasIn the future, we can implement more strategies of ISwapPricer without changing the client code.
class Client:
trade = TradeBuilder.BuildSwapTrade()
pricers = [SwapPricerBondStrategy(), SwapPricerFRAStrategy()] #we can easily switch the algorithms
for pricer in pricers:
price = pricer.PriceSwap(trade)The client code simply gets the pricer to price a swap. Each pricer has its own strategy which has the algorithm that knows how it can price the trade.
3.5 Strategy Pattern Summary
- The section explained that we can price an IRS using bond or FRA strategy. This can be accomplished via strategy design pattern.
- Client code can interchange strategies without changing all of the code.
- Makes code easy to test, understand and follows SOLID principles
If you want to understand what an interest rate swap is then please read:
4. Let’s Understand Decorator Design Pattern
4.1 What Is The Decorator Design Pattern?
Decorator design pattern is used to decorate or extend an object’s responsibilities at run time or statically without changing its structure.
Decorator pattern is a widely used structural software design pattern.
4.2 Decorator Design Pattern Use cases
- Decorator pattern is an important tool for Open-Closed Principle.
- Decorator pattern can be used to add functionality to an object without changing itself or other objects.
- You can use decorator pattern if you want to extend an object without creating a large number of sub classes.
- Decorator pattern is an alternative to implementing inheritance tree structure.
4.3 Decorator Design Pattern Example
Let’s assume we are implementing a trading platform. An option trader groups a number of option trades and implements a strategy. Sometimes the option strategies are combined to create a new strategy. Each option strategy has its own way of calculating the pay off.
- We are required to implement a software application where we can model the new strategies.
- Let’s assume we are required to implement a strategy, known as Strangle strategy. This strategy requires the trader to compose options with different strike price.
- We are then asked to implement another strategy, which is known as Horizon strategy. This strategy is composed of options with different maturity dates.
- Now the trader has requested us to extend the program where he/she could combine any of these two option strategies to create his/her own custom strategy.
- Furthermore, we have been informed that the number of strategies and their combinations will grow in the future.
- Each strategy has its own way of computing the pay off.
Question: How Should We Implement It?
Use Decorator Design Pattern
4.4 Implementation Steps
- Create a base class: Strategy; with method: CalculatePayOff()
- Create strategy concrete class: StrangleStrategy that provides its own functionality for CalculatePayOff()
- HorizonStrategyDecorator class inherits from StrategyDecorator base class and provides its own functionality for CalculatePayOff().
The key to note is that the CalculatePayOff() function of the HorizonStrategyDecorator decorates the pay off and then executes the strategy’s pay off. It is injected with a Strategy in its constructor.
import abcclass Strategy(metaclass=abc.ABCMeta):
@abc.abstractmethod
def CalculatePayOff(self):
print('Inside Strategy.CalculatePayOff')
passclass StrangleStrategy(Strategy):
def CalculatePayOff(self):
print('Take StrangleStrategy.CalculatePayOff')
passclass StrategyDecorator(Strategy):
def __init__(self,strategy_to_decorate):
self.strategy_to_decorate = strategy_to_decorate
def CalculatePayOff(self):
return self.strategy_to_decorate.CalculatePayOff()
class HorizonStrategyDecorator(StrategyDecorator):
def __init__(self,strategy_to_decorate):
StrategyDecorator.__init__(self,strategy_to_decorate)
def CalculatePayOff(self):
print('Take HorizonStrategy.CalculatePayOff')
return self.strategy_to_decorate.CalculatePayOff()The decorator class has a constructor that takes Strategy object as an argument. The class can now decorate the strategy.
Let’s assume that the trader approaches us today and tells us about a new strategy, named Butterfly strategy. Therefore, we implement a decorator for it.
class ButterflyStrategyDecorator(StrategyDecorator):
def __init__(self,strategy_to_decorate):
StrategyDecorator.__init__(self,strategy_to_decorate)
def CalculatePayOff(self):
print('Take Butterfly.CalculatePayOff')
return self.strategy_to_decorate.CalculatePayOff()The trader then informs us that we are now assigned to create a strategy that is a combination of Strangle, Horizon and Butterfly strategies.
We don’t need to create new classes. We can simply assemble the decorators together.
We can now easily decorate the strategies without creating any new classes:
Strangle = StrangleStrategy()
StrangleHorizon = HorizonStrategyDecorator(Strangle)
ButterflyHorizonStrangleHorizon = ButterflyStrategyDecorator(StrangleHorizon)
ButterflyHorizonStrangleHorizon.CalculatePayOff()As you can see in the snippet above, we have implemented new strategies and added dynamic functionalities without creating new classes.
This will print:
Take Butterfly.CalculatePayOff
Take HorizonStrategy.CalculatePayOff
Take StrangleStrategy.CalculatePayOff4.5 Decorator Pattern Summary
- Decorator pattern saved us from creating a large number of classes each time we want to add new functionality into our system.
- We can see that with decorator pattern, we added additional behavior to an object without creating new objects or changing existing objects.
- We created a combination of strategies without creating any new class.
- Decorator pattern is an alternative to implementing inheritance tree structure. Additionally, decorator pattern prevents code from growing exponentially with every new requirement.
If you want read up on option strategies, please read:
Article Summary
This article aimed to outline one of the key concepts in a programmer’s life — to use appropriate design patterns. In particular, I wanted to concentrate on Python programming language due to its ease and popularity.
Get to know these design patterns as these are common patterns in the programming world.
I have explained these populate design patterns along with real-life FinTech use cases:
- Builder
- Template
- Strategy
- Decorator
Hope it helps






