60288347

Back to Basics – Design Patterns – Part 2

In the previous post, we discussed design patterns, their structure and usage. Then we discussed the three fundamental types and started off with the first one – Creational Patterns.

Continuing with creational patterns we will now discuss Abstract Factory pattern, which is considered to be a super set of Factory Method.

Abstract Factory

In the Factory method, we discussed how it targets a single family of subclasses using a corresponding set of factory method classes, or a single factory method class via parametrised/ static factory method. But if we target families of related classes (multiple abstractions having their own subclasses) and need to interact with them using a single abstraction then factory method will not work.

A good example could be the creation of doors and windows for a room. A room could offer a combination of wooden door, sliding door etc. and wooden window, glass window etc. The client machine will however, interact with a single abstraction (abstract factory) to create the desired door and window combination based on selection/ configuration. This could be a good candidate for an Abstract Factory.

So abstract factory allows initiation of families (plural) of related classes using a single interface (abstract factory) independent of the underline concrete classes.

Reasons

When a system needs to use families of related or dependent classes, it might need to instantiate several subclasses. This will lead to code duplication and complexities. Taking the above example of a room, the client machine will need to instantiate classes for doors and windows for one combination and then do the same for others, one by one. This will break the abstraction of those classes, exposes their encapsulation, and put the instantiation complexity on the client. Even if we use a factory method for every single family of classes this will still require several factory methods, unrelated to each other. Thereby managing them to make combination offerings (rooms) will be code cluttering.

We will use abstract factory when:

–          A system is using families of related or dependent objects without any knowledge of their concrete types.

–          The client does not need to know the instantiation details of subclasses.

–          The client does not need to use subclasses in a concrete way.

Components

There are four components of this pattern.

–          Abstract Factory

The abstraction client interacts with, to create door and window combinations. This is the core factory that provide interfaces for individual factories to implement.

–          Concrete Factories

These are the concrete factories (CombinationFactoryA, CobinationFactoryB) that create concrete products (doors and windows).

–          Abstract Products

These are the abstract products that will be visible to the client (AbstractDoor & AbstractWindow).

–          Concrete Products

The concrete implementations of products offered. WoodenDoor, WoodenWindow etc.

 

drawing1

 

Sample code

Using the above example, our implementation would be:

    public interface Door

{

double GetPrice();

}

class WoodenDoor : Door

{

public double GetPrice()

{

//return price;

}

}

class GlassDoor : Door

{

public double GetPrice()

{

//return price

}

}

public interface Window

{

double GetPrice();

}

class WoodenWindow : Window

{

public double GetPrice()

{

//return price

}

}

class GlassWindow : Window

{

public double GetPrice()

{

//return price

}

}

The concrete classes and factories should ideally have protected or private constructors and should have appropriate access modifiers. e.g.

    protected WoodenWindow()

{

}

The factories would be like:

    public interface AbstractFactory

{

Door GetDoor();

Window GetWindow();

}

class CombinationA : AbstractFactory

{

public Door GetDoor()

{

return new WoodenDoor();

}

public Window GetWindow()

{

return new WoodenWindow();

}

}

class CombinationB : AbstractFactory

{

public Door GetDoor()

{

return new GlassDoor();

}

public Window GetWindow()

{

return new GlassWindow();

}

}

And the client:

    public class Room

{

Door _door;

Window _window;

public Room(AbstractFactory factory)

{

_door = factory.GetDoor();

_window = factory.GetWindow();

}

public double GetPrice()

{

return this._door.GetPrice() + this._window.GetPrice();

}

}

            AbstractFactory woodFactory = new CombinationA();

Room room1 = new Room(woodFactory);

Console.Write(room1.GetPrice());

AbstractFactory glassFactory = new CombinationB();

Room room2 = new Room(glassFactory);

Console.Write(room2.GetPrice());

The above showcases how abstract factory could be utilised to instantiate and use related or dependent families of classes via their respective abstractions without having to know or understand the corresponding concrete classes.

The Room class only knows about Door and Window abstractions and let the configuration/ client code input dictate which combination to use, at runtime.

Sometimes abstract factory also uses Factory Method or Static Factory Method for factory configurations:

    public static class FactoryMaker

{

public static AbstractFactory GetFactory(string type)   //some configuration

{

//configuration switches

if (type == “wood”)

return new CombinationA();

else if (type == “glass”)

return new CombinationB();

else   //default or fault config

return null;

}

}

Which changes the client:

AbstractFactory factory = FactoryMaker.GetFactory(“wood”);//configurations or inputs

Room room1 = new Room(factory);

As can be seen, polymorphic behaviours are the core of these factories as well as the usage of related families of classes.

Advantages

Creational patterns, particularly Factory can work along with other creational patterns; Abstract factory

–          Isolation of the creation mechanics from its usage for related families of classes.

–          Adding new products/ concrete types does not affect the client code rather the configuration/ factory code.

–          Provide way for the client to work with abstractions instead of concrete types. This gives flexibility to the client code to the related use cases.

–          Usage of abstractions reduce dependencies across components and increases maintainability.

–          Design often starts with Factory method and evolves towards Abstract factory (or other creational patterns) as the families of classes expends and their relationships develops.

Drawbacks

Abstract factory does introduce some disadvantages in the system.

–          It has fairly complex implementation and as the families of classes grows, so does the complexity.

–          Relying heavily on polymorphism does require expertise for debugging and testing.

–          It introduces factory classes, which can be seen as added workload without having any direct purpose except for instantiation of other classes, particularly in bigger systems.

–          Factory structures are tightly coupled with the relationships of the families of classes. This introduces maintainability issues and rigid design.

For example, adding a new type of window or door in the above example would not be as easy. Adding another family of classes, like Carpet and its sub types would be even more complex, but this does not affect the client code.

Conclusion

Abstract factory is a widely used creational pattern, particularly because of its ability to handle the instantiation mechanism of several families of related classes. This is helpful in real-world solutions where entities are often interrelated and work in a blend in a variety of use cases.

Abstract factory ensures the simplification of design targeting business processes by eliminating the concrete types and replacing them with abstractions while maintaining their encapsulation and removing the added complexity of object creation. This also reduces a lot of duplicate code at the client side making business processes testable, robust and independent of the underline concrete types.

In the third part of creational patterns, we will discuss a pattern slightly similar to Abstract factory, the Builder. Sometimes the two could be competitors in design decisions but differs in real-world applications.

 

Further reading

 

http://www.dofactory.com/net/abstract-factory-design-pattern

http://www.oodesign.com/abstract-factory-pattern.html

http://www.oodesign.com/abstract-factory-pattern.html

Back to Basics – Design Patterns – Part 1

Design Patterns

Design patterns are reusable solutions to recurring problems of software design and engineering in the real-world. Patterns makes it easier to reuse proven techniques to resolve design and architectural complications and then communicating and documenting them with better understanding, making them more accessible to developers in an abstract way.

60288347

Design patterns enhance the classic techniques of object oriented programming by encouraging the reusability and communication of the solutions of common problems at abstract levels and improves the maintainability of the code as a by-product at implementation levels.

The “Y” in Design Patterns

Apart from the obvious advantage of providing better techniques to map real-world into programming models, a prime objective of OOP is design and code reusability. However, this is easier said than done. In reality, designing reusable classes is hard and takes time. In the real-world, less than few devs write code with long-term reusability in mind. This becomes obvious when dealing with recurring problems in design and implementation. This is where design patterns come in to the picture, when dealing with problems that seems to appear again and again. Any proven technique that provides a solution of a recurring problem in an abstract, reusable way, independent of the implementation barriers like programming language details and data structures, is categorised as design pattern.

The design patterns:

  • help analysing common problems in a more abstract way.
  • provides proven solutions to those problems.
  • help decreasing the overall code time at the implementation level.
  • encourages the code reusability by providing common solutions.
  • increases code lifetime and maintainability by enhancing the capacity of change.
  • Increases the understanding of the solutions of recurring problems.

A pattern will describe a problem, provide its solution at an abstract level, and elaborate the result.

Problem

The problem part of a pattern describes the issue(s) a program/ piece of code is facing along with its context. It might highlight a class structure to be inflexible, or issues related to the usage of an object, particularly at runtime.

Solution

A solution is always defined as a template, an abstract design that will describe its element(s), their relationships, and responsibilities and will detail out how this abstract design will address the problem at hand. A pattern never provides any concrete implementation of the solution, enhancing its reusability and flexibility. The actual implementation of a pattern might vary in different programming languages.

Understanding software design patterns requires respectable knowledge of object oriented programming concepts like abstraction, inheritance, and polymorphic behaviour.

Types of Design Patterns

Design patterns are often divided into three fundamental types.

  • Creational – deals with the creation/ instantiation of objects specific to business use cases. Polymorphic concepts, along with inheritance, are the core of these patterns.
  • Structural – targets the structure and composition of classes. Heavily relies upon the inheritance and composition concepts of OOP.
  • Behavioural – underlines the interaction between classes, separation and delegation of responsibilities.

let-us-understand-design-pattern-9-638

Creational Patterns

Often the implementation and usage of a class, or a group of classes is tightly coupled with the way objects of those classes are created. This decreases the flexibility of those classes, particularly at runtime. For example, if we have a group of cars providing a functionality of driving. Then the creation of each car will require a piece of code; new constructor in common modern languages. This will infuse the creation of cars with its usage:

Holden car1 = new Holden();

car1.Drive();

Mazda car2 = new Mazda();

car2.Drive();

Even if we use base type;

Car car1 = new Holden();

car1.Drive();

Car car2 = new Mazda();

car2.Drive();

If you look at the above examples, you will notice that the actual class being instantiated is selected at compile-time. This creates problems when designing common functionality and forces hardwired code into the usage based on concrete types. This also exposes the constructors of the classes which penetrates the encapsulation.

Creational patterns provide the means of creating, and using objects of related classes without having to identify their concrete types or exposing their creational mechanism. This gives move flexibility at the usage of the instantiated objects at runtime without worrying about their types. This also results in less code and eliminates the creational complexity at the usage, allowing the code to focus on what to do then what to create.

CarFactory[] factories = <Create factories>;

foreach (CarFactory factory in factories) {

               Car car = factory.CreateCar();

               car.Drive();

}

The above code removes the creational logic and dedicates it to subclasses and factories. This gives flexibility on usage of classes independent of its creation and let the runtime dictates the instantiated types while making the code independent of the number of concrete types (cars) to be used. This code will work regardless of the number concrete types, enhancing the reusability and separation of creation from its usage. We will discuss the above example in details in Factory Method pattern.

The two common trades of creational patterns are:

  • Encapsulation of concrete types and exposure using common abstractions.
  • Encapsulation of instantiation and encouraging polymorphic behaviour.

The system leveraging creational patterns does not need to know, or understand concrete types; it handles abstractions only (interfaces, abstract classes). This gives flexibility in configuring a set of related classes at runtime, based on use cases and requirements without having to alter the code.

There are five fundamental creational patterns:

  • Factory method
  • Abstract factory
  • Prototype
  • Singleton
  • Builder

Factory Method

This pattern specifies a way of creating instances of related classes but let the subclasses decide which concrete type to instantiate at runtime, also called Virtual Construction. The pattern encourages the use of interfaces and abstract classes over concrete types. The decision is based upon the input supplied by either the client code or configuration.

Reasons

When client code instantiates a class, it knows the concrete type of that class. This breaks through the polymorphic abstraction when dealing with a family of classes. We may use factory method when:

  • Client code don’t know the concrete types of subclasses to create.
  • The instantiation needs to be deferred to subclasses.
  • The job needs to be delegated to subclasses and client code does not need to know which subclass is doing the job.

Components

factorymethod1

Abstract <Product> (Car)

The interface/ abstraction the client code understands. This describes the family of subclasses to be instantiated.

<Product> (Holden, Mazda, …)

This implements the abstract <product>. The subclass(es) that needs to be created.

Abstract Factory (CarFactory)

This provides the interface/ abstraction for the creation of abstract product, called factory method. This might also use configuration for creating a default product.

ConcreteFactory (HoldenFactory, MazdaFactory, …)

This provides the instantiation of the concrete subclass/ product by implementing the factory method.

Sample code

Going back to our example of cars earlier, we will provide detail implementation of the factory method.

public abstract class Car //could be an interface instead, if no default behaviour is required

    {

        public virtual void Drive()

        {

            Console.Write(“Driving a car”);

        }

    }

    public class Holden : Car

    {

        public override void Drive()

        {

            Console.Write(“Driving Holder”);

        }

    }

    public class Mazda : Car

    {

        public override void Drive()

        {

            Console.Write(“Driving Mazda”);

        }

    }

   public interface ICarFactory //This will be a class/ abstract if there is a default factory implementation.

    {

        Car CreateCar();

    }

    public class HoldenFactory : CarFactory

    {

        public Car CreateCar()

        {

            return new Holden();

        }

    }

    public class MazdaFactory : CarFactory

    {

        public Car CreateCar()

        {

            return new Mazda();

        }

    }

Now the client code could be:

var factories = new CarFactory[2];

factories[0] = new HoldenFactory();

factories[1] = new MazdaFactory();

foreach (var factory in factories)

{

var car = factory.CreateCar();

       car.Drive();

}

 

Now we can keep introducing new Car types and the client code will behave the same way for this use case. The creation of factories could further be abstracted by using parametrised factory method. This will modify the CarFactory interface.

 

    public class CarFactory

    {

        public virtual Car CreateCar(string type) //any configuration or input from client code.

        {

     /////switches based on the configuration or input from client code

            if (type == “holden”)

                return new Holden();

            else if (type == “mazda”)

                return new Mazda();

//…

            else    ////default instantiation/ fault condition etc.

                return null; //default/ throw etc.

        }

    }

 

Which will change the client code:

 

CarFactory factory = new CarFactory();

Car car1 = factory.CreateCar(“holdern”); //Configuration/ input etc.

Car car2 = factory.CreateCar(“mazda”); //Configuration/ input etc.

 

The above code shows the flexibility of the factory method, particularly the Factory class.

Advantages

Factory method is the simplest of the creational patterns that targets the creation of a family of classes.

  • It separates the client code and a family of classes by weakening the coupling and abstracting the concrete subclasses.
  • It reduces the changes in client code due to changes in concrete types.
  • Provides configuration mechanism for subclasses by removing their instantiation from the client code and into the factory method(s).
  • The default constructors of the subclasses could be marked protected/ private to shield direct creation.

Drawbacks

There are some disadvantages that should be considered before applying factory method:

  • Factory demands individual implementations of a factory method for every subclass in the family. This might introduce unnecessary complexity.
  • Concrete parametrised factory leverages the switch conditions to identify the concrete type to be instantiated. This introduces cluttered and hardwired code in the factory. Any changes in the configuration/ client code input or implementation changes of the concrete types demands a review of the factory method.
  • The subtypes must be of the same base type. Factory method cannot handle subtypes of different base types. That will require complex creational patterns.

Conclusion

Factory method is simple to understand and implement in a variety of languages. The most important consideration is to look for many subclasses of the same base type/ interface and being handled at that abstract level in a system. Conditions like below could warrant a factory method implementation.

Car car1 = new Holder();

car1.GetDiscount();

Car car2 = new Mazda();

car2.GetDiscount();

. . .

 

On the other hand, if you have some concrete usage of subclasses like.

 

if (car.GetType() == typeof(Holden))

      ((Holden)car).GetHoldenDiscount();

 

Then factory method might not be the answer and, perhaps reconsider the class hierarchy.

In part 2, we will discuss the next Creational Pattern, that is considered a superset of factory method, Abstract Factory.

 

Further Reading

https://msdn.microsoft.com/en-us/library/orm-9780596527730-01-05.aspx

http://www.oodesign.com/abstract-factory-pattern.html

http://www.dofactory.com/net/factory-method-design-pattern

 

Microservices – An Agile Architecture Introduction

In the ever evolving and dynamic world of software architecture, you will hear new buzz words every other month. Microservices is the latest of them, though not as new as it appears, it has been around for some time now in different forms.

Microservices – The micro of SOA?

        “… the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.” that Fowler guy.

So, to break it all down, microservices is a form of fine-grained service oriented architecture (SOA) implementation that could be used to build independent, flexible, scalable, and reusable software applications in a decoupled manner. This relies heavily on separately deployable and maintainable sub systems/ processes that can communicate over a network using technology-agnostic protocols. That in turns, pave way for DevOps and Continuous Deployment pipelines.

Principia Microservices – nutshell

You would not find a defined set of characteristics of a microservices based system. A formal definition is still missing, though we can outline the basic and mostly mentioned pointer.

–          The services are small fine-grained representation of a single business function.

–          Designed and maintained around capabilities.

–          Flexible, robust, replaceable, and independent of each other in nature.

–          Designed to embrace faults and failures. An unavailable service cannot bring the system down. Emphasis on monitoring and logging.

–          Advocates the practices of continuous improvement, continuous integration and deployment.

Services as Components

Defining software systems as a set of smaller, independently maintainable components has always been a craving of well-define architectures. The current programming languages lack the mechanism of explicit boundary definitions for components and often, it’s just documentation and published best practices/ code reviews that stops a developer in mixing logical components in a monolithically designed application.

This differs a bit from the idea of libraries. Libraries are in-process components of an application that, though logically separate, cannot be deployed and maintained independently.

In microservices, components are explicitly defined as independent and autonomously deployable services. This enables continuous processes (CI & CD) and enhances maintainability of individual components, increases reusability and overall robustness of the system. It also enables a better realization of business processes into the application.

feature02-figure02

 

Built for Business

conways-law

Most of the time, organisations looking to build a decoupled system focuses on technical capabilities. This leads to teams of UI devs, backend devs, DB devs etc. This leads to siloed architectures and applications.

Microservices does things differently. The organisation splits teams as per the business capabilities. This results in cross-functional, dynamic and independent teams with full technical capabilities.

03-conwayslawenabler

 

Decentralized

A consequence of a monolithic design is central management and support of the whole system. This create problems in scalability and reusability. These systems tend to favour a single set of tools and technologies.

Microservices advocates “you build it, you run it” approach. The teams are designed to take end-to-end responsibility of the product. This disperse the capabilities across the teams and helps tie up the services with business capabilities and functions. This also enables selection of underlying technologies based on needs and availabilities.

team_monolithic_vs_microservice

 

Designed for Failure

A failure in monolithic design could be a catastrophe, if not dealt with gracefully and with a fall-back approach. Microservices, however, are designed for failure from the beginning. Because of their independent and granular nature, the overall user experience in case of a failure tends to be manageable. Unavailability of one service does not bring the whole system down. It is also easier to drill down in microservices to identify the root cause because of their agility and explicit boundaries. Real-time monitoring and logging and other cross-cutting concerns are easier to implement and are heavily emphasized.

      “If we look at the characteristics of an agile software architecture, we tend to think of something that is built using a collection of small, loosely coupled components/services that collaborate together to satisfy an end-goal. This style of architecture provides agility in several ways. Small, loosely coupled components/services can be built, modified and tested in isolation, or even ripped out and replaced depending on how requirements change. This style of architecture also lends itself well to a very flexible and adaptable deployment model, since new components/services can be added and scaled if needed.” — Simon Brown

Microservices architecture tends to result in independent products/ services designed and implemented using different languages, databases, and hardware and software environments, as per the capabilities and requirements. They are granular, with explicit boundaries, autonomously developed, independently deployable, decentralized and built and released with automated processes.

Issues – Architecture of the wise

However, there are certain drawbacks of microservices as well; like higher cost of communication because of network latency, runtime overhead (message processing) as oppose to in-process calls, and blurry definitions of boundaries between services. A poorly designed application based on microservices could yield more complexity since the complexity will only be shifted onto the communication protocols, particularly in distributed transactional systems.   

“You can move it about but it’s still there” — Robert Annett: Where is the complexity?

Decentralized management, especially for databases has some implications related to updates and patches, apart from transactional issues. This might lead to inconsistent databases and need well defined processes for management, updates, and transactional data consistency.

issues

Overall system performance often demand serious considerations. Since microservices targets distributed applications in isolated environments; the communication cost between components tends to be higher. This leads to lower overall system performance if not designed carefully. Netflix is a leading example of how a distributed system based on microservices could outperform some of the best monolithic systems in the world.

Microservices tends to be small and stateless; still business processes are often state-full and transitional in nature so dividing business processes and data modelling could be challenging. Poorly parted business processes create blurry boundaries and responsibility issues.

Potential of failure and unavailability rises significantly with distributed systems based on isolated components communicating over networks. Microservices could suffer with the same because of high dependence on isolated components/ services. Systems with little or no attention to Design for Failure could lead to higher running cost and unavailability issues.

Coping with issues of distributed systems could lead to complexities in implementation details. Less skilled teams in this case will suffer greatly, especially when handling with performance and reliability issues. Therefore, microservices is the architecture of the wise. Often building a monolithic system and then migrating to a more distributed system using microservices works best. This also gives the teams more insights about business processes and experience of handling existing complexities which comes handy in segregating processes into services with clearer boundaries.

When we have multiple isolated components working together in a system, version control becomes a problem, as with all the distributed systems. Services dependencies upon each other create issues when incorporating changes. This tends to get bigger as the system grows. Microservices emphasises on simpler interfaces and handshakes between services and advocates immutable designs to resolve versioning issues. This still requires managing and supporting multiple services at times.

Last words

There is no zero-one choice between monolithic and distributed systems. Both have their advantages and shortcomings. The choice of an architecture heavily depends upon the business structure, team capabilities and skill set, and the dispersed knowledge of the business models. Microservices does solve a lot of problems classical one package systems face but it does come up with a cost. More than the architectural choices, it is the culture of the team and the mindset of people that makes the difference between success and failure – there is no holy grail.

 

Further reading

https://martinfowler.com/articles/microservices.html

https://smartbear.com/learn/api-design/what-are-microservices/

Google 🙂