Stuff about Software Engineering

Tag: Pattern

Software Architecture Patterns

Introduction

The following is an subset of software architecture patterns, which tend to be referenced when academic discussions around patterns arise. The following are my comments.

Patterns

Application Architecture

Microservice

The microservice pattern comes from domain-driven design where in particular the concept of bounded context came to be the decoupling of services. The post Microservices by Martin Fowler also played a large part in naming this pattern.

Drivers:

  • Loosely coupled with other services – enables a team to work independently the majority of time on their service(s) without being impacted by changes to other services and without affecting other services
  • Independently deployable – enables a team to deploy their service without having to coordinate with other teams
  • Capable of being developed by a small team – essential for high productivity by avoiding the high communication head of large teams
  • The application must be easy to understand and modify
  • You must run multiple instances of the application on multiple machines in order to satisfy scalability and availability requirements
  • You want to take advantage of emerging technologies (frameworks, programming languages, etc)

Problems:

  • Managing dependencies
  • Deployments of the entire system may become complex
  • Developers must implement the inter-service communication mechanism and deal with partial failure
  • Implementing requests that span multiple services is more difficult
  • Testing the interactions between services is more difficult
  • Implementing requests that span multiple services requires careful coordination between the teams

Database

Database per Service

This pattern is basically the natural follow-on to choosing the microservice application architecture pattern, where if a service is to become independant, then it must have it’s own independant data layer.

Drivers:

  • Services must be loosely coupled so that they can be developed, deployed and scaled independently
  • Databases must sometimes be replicated in order to scale
  • Different services have different data storage requirements, like relational database or NoSQL

Problems:

  • How to manage consistency across services
  • Who owns (masters) data?

Messaging

Messaging is a communications pattern which uses asynchronous messaging to replace the synchronous style of request/response used in most REST-style APIs. Most common styles of asynchronous messaging are:

  • Notifications – a sender sends a message a recipient but does not expect a reply. Nor is one sent.
  • Request/asynchronous response – a service sends a request message to a recipient and expects to receive a reply message eventually
  • Publish/subscribe – a service publishes a message to zero or more recipients
  • Publish/asynchronous response – a service publishes a request to one or recipients, some of whom send back a reply

In the following there’s no differentiation between “event”-driven and “data”-driven, as a message will always contain the full message body.

Event Driven with full Messages

Drivers:

  • The complete body of the message must be sent in each event
  • The broker may or may not allow for queries against the messages
  • Extreme loose coupling as the sender is completely decoupled from the receiver

Problems:

  • Subscriber/consumer overload which requires buffering so that events are not lost
  • The broker/mediator must always be available
  • Almost always creates mixed messaging styles with events for downstream and request/response across and upstream which requires carefull planning

Broker

Event driven messaging with a broker implies that all messages are delivered through a central broker but that there’s no processing control flow and messages are delivered using a publish/subscribe pattern.

Drivers:

  • Scalability

Problems:

  • How to handle orchestration? With “normal” synchronous request/response messaging services orchestrate business processes in the order that they are called – with broker driven messaging everybody potentially could get the same message at the same time, so who orchestrates the overall process?

Mediater

A mediater expands on the broker with support for business process workflows usually with support for BPEL.

Drivers:

  • Business processes change often
  • Traceability and governance is important

Problems:

  • Management and governance of platform takes time
  • Requires turnkey solutions from major vendors
  • Not really available as a cloud solution

Event Driven with Notifications

Drivers:

  • You don’t know how many subscribers/consumers of your events there will be, so you must preserve bandwidth
  • The size of the payload in the event is limited
  • A subset of the events doesn’t require the complete body of the message to be sent
  • Subscribers explicitly want to chose which message bodies they want to pull

Problems:

  • Requires a two-step dance where the consumer of an event must issue a request to the central broker and ask for the full body of the message

Requirements Engineering

Imagine that the sum of the business requirements for a system can be represented by the surface area of a square where the length of the side is 1 meter. Then the surface area is 1 square meter (m2).

Now image also that the shape of the system that can solve those business requirements is a circle and that we have to construct a circle with the surface area of 1 m2. Knowing that the area of a circle is Pi * r^2 then the radius is the square root of 1/Pi which is approximately 0.564 making the diameter 1.128. So we can draw the square and circle as follows:

Notice that when the figures are overlapped one doesn’t cover the other even if they have the same surface area.

So the implementation of the system which can solve the business requirements – but in a slightly different way. To turn the circle into a square custom implementations will have to be done and they are a lot more costly than a standard system.

I don’t have any statistical evidence but in my experience you can usually get 80% of the way with a standard system, but getting to 100% will cost you a lot more.

The Four Tenets of SOA

The SOA tenets originally appeared back in 2004 when  Don Box published an article on MSDN called “A Guide to developing and Running Connected Systems with Indigo” (Indigo is what’s known today as Windows Communication Foundation or WCF for short). Don Box wrote that WCF is based on SOA principles and that unlike other approaches, specifically object orientation, SOA requires a different set of assumptions:

In Indigo, a service is simply a program that one interacts with via message exchanges. A set of deployed services is a system. Individual services are built to last—the availability and stability of a given service is critical. The aggregate system of services is built to allow for change—the system must adapt to the presence of new services that appear a long time after the original services and clients have been deployed, and these must not break functionality.

Although Microsoft have pledged to keep the MSDN Magazine online at the time of writing the article linked above is not available.

Service-oriented development is based on the four fundamental tenets that follow:

  • Boundaries are explicit 
  • Services are autonomous
  • Services share schema and contract, not class
  • Service compatibility is determined based on policy 

Let’s go over what that means in terms of modern REST services.

Four Tenets

Boundaries are explicit

Services interact by sending messages across boundaries. These boundaries are formal and explicit. No assumptions are made about what is behind boundaries, and this preserves flexibility in how services are implemented and deployed.

This means that:

  • You must treat all services as external to you
  • Internal (private) implementation details should not be leaked outside of a service boundary
  • Avoid RPC interfaces because this can lead to an overuse of calls – accessing a service is not the same as accessing a local object

Services are autonomous

Services are not subservient to other code: a service reacts to a message – how that message was created and what will happen to any response the service creates is immaterial to the action that this service will take.

This means that:

  • Deploy and version services independently from the clients
  • Design contracts with the assumption that once published, they can’t be modified

Services share schema and contract, not class

Only messages pass from service to service, code does not.

This means that:

  • Contracts should be designed to be as explicit as possible to minimize misinterpretation
  • A service must be able to convert its native data types to and from some technology-neutral representation
  • The contract must be versioned using semantic versioning

Service compatibility is determined based on policy

A service must be able to express in a standard representation of policy what it does and how clients should communicate with it.

This means that:

  • The policy must be exposed using an Open API Specification

© 2024 Peter Birkholm-Buch

Theme by Anders NorenUp ↑