As I mentioned earlier in the series of articles there were a couple of projects where we implemented the API Gateway pattern which I wanted to discuss. The 2nd project was a one where we also used Azure Service Bus and that introduced what I thought were some interesting new things. As mentioned in Martin Fowlers Microservices articles some people will often use a messaging capability along with their services and I wanted to discuss how we evolved the architecture here.
In this project we were working with 3 other businesses within the global group of companies. One of the things I was trying to do was to roll out consistent architecture and development patterns for integration things which were built across the company and introduce some of the approaches which had worked well so far but extend them to fit this new and in some ways very different initiative. We also wanted to try and address some of the mistakes of the past too.
The vision for this project was to create an API capability which would allow external partners and applications to integrate with our internal systems, but also to bridge multiple companies so that they can appear and operate as a single entity to these outsider parties without having to completely replace large parts of their IT.
At a high level the vision of what we were trying to achieve is outlined in the diagram below.
Please note that this is a conceptual diagram showing capabilities and definitely not showing logical or physical components. Its really just the vision.
Flawed Enterprise Architecture View
One of the organisational challenges we often had was around this huge disconnect between ivory tower architecture and development. Often made worse by the agile transformation empowering in experienced teams to make unchecked decisions on route. The vision for this project had gone through multiple iterations of solutioning before it got to the technical architecture area and a diagram like below was being touted.
The problem here is that the diagram is presented in a way that makes it look not that complex The diagram isnt clearly a physical, logical or conceptual view of the architecture but instead is a hybrid taking some bits from each kind of view. Enough physical stuff to make it sound deliverable but enough logical and conceptual stuff to gloss over some of the physical challenges.
The 2nd problem was that it was looking to propose a recreation of all of the things that went wrong in the previous project where our light weight API components had turned into big monolithic beasts. The problem was that this time we are talking about having a beast in each country and also a beast in the cloud which is tightly coupled to each beast on premise.
Any one who has walked the walk before knows that the way this kind of diagram was being used is a big warning flag.
The Problem with the Architecture
To just recap some of the problems that were clear in the above proposal were:
- Big monolithic API in the cloud
- Big Monolithic Integration Services Layer in each business
- Tight coupling between each of them and resulting very complex dependency management requirements
- Fragile architecture
- Limited options for async processing or throttling which the cloud could require
- Every change would have a potentially big impact in terms of dependency management and regression testing
- We would lose lots of the agility we had with small lightweight components
When we went through the detail of this architecture, one of the best things we could do was to stop the use of VPN from the cloud to each business in this architecture which then require some rethinking and re-engineering to get us back to thinking about the services architecture again. We changed to use Azure Service Bus messaging in place of VPN and this immediately created a big decoupling between the assets in the cloud and then assets on premise in each country. Next let us take a look at some more detail in how we changed and implemented the architecture.
Cloud API Physical View
Once we had refactored the architecture in line with what we had been trying to achieve with our API & services approach we had a plan which was similar to the original vision in the last article but extended to cover other things in this project. To look at this revised architecture lets look at the below diagram which outlays the Cloud API part of the architecture at a lower level. For the sake of simplicity over the coming sections I have continued this approach of breaking down to look at the architecture in specific sections.
In this diagram we have reverted from the monolithic Integration Services Layer in the cloud at a logical and physical level. We still could argue we have this at a conceptual level because in Azure we would have a bunch of API/Integration and Services stuff there all working together, but instead of one big complex beast component we would have a set of smaller components working together. To begin with we have the light weight API Gateway components again. These are using the Service Container we talked about earlier but this time it is adapted slightly to host as an Azure Website or an Azure Web Role. We have ones for each group of consumers. In this case we have an API Gateway for B2B partners. This contains services aimed at our default average business partner and their capabilities. It would adapt the under the hood services to a traditional SOAP API which fits the capabilities of 80% of our partners and uses a key based security pattern. Down the line we also had in mind to build an API Gateway aimed at a mobile application for members which would have used the gateway to adapt the services to better fit a mobile consumer. Maybe with a REST based interface.
In Azure we knew that we would have the capability to compliment the API Gateway with services such as caching by using the Azure platform to our advantage.
Again one of the benefits of small light weight API Gateways was re-emphisised when we had a requirement in the pipeline for exposing some services to a partner which are based on REST. Now this brings up some really interesting architectural discussion points and reminds me of an article I wrote a few years ago. Some of the discussions points that came up were:
- Just add REST endpoints to the existing API Gateway for these other partners.
- Make the partners use the SOAP one we already have
- Just get on and deliver what the customer wants
All of these points have some merit and if you think back to the article I referenced earlier, what I was saying was that the API approach you use here doesnt entirely depend on technical factors, in the real world it tends to depend on the power relationship between the API consumer and API provider. If the power resides completely with the provider then they can say “we are doing it this was and you just need to live with it”. This is a scenario like Twitter or one of the big internet API providers. There has been a couple of times they have introduced a breaking change to their API and app vendors have just had to change or stop working. Many companies are in a very different situation and in ours it was the case that if the partner doesnt have a great API experience then they will potentially use someone else. We needed to support the approach that keeps their costs down, but find a balance or comprimise so that we can keep them happy but without having to write a load of custom stuff just to support them. Based on this the API Gateway pattern would fit well here.
The final part of the cloud API section was the Azure Service Bus. One of the good things we could do to our architecture was to include an asynchronous messaging capability and in this particular part of it there were some significant benefits here. These include:
- Service Bus would create (and force) a clear decoupling between the cloud and each business unit.
- Service Bus would give us a global pub/sub capability which took complexity away from the API Gateway in distributing messages across the various regions
- New countries could be added in a plug and play fashion without having to make changes to the API Gateway
Country 1 Physical View
If we now take a look at the physical view of the desired architecture for country 1 we can see that it is very similar to the services vision from the previous project.
This time we have a component which would act as a listener on premise to the Azure Service Bus. The desire was then to have a Service Virtualization capability so that as the we can have some monitoring of on premise services and also decouple those services and implement on premise routing between them. Although we still didnt have an appropriate product for this we knew that with the Generic Endpoints approach we could still use our custom approach and then very easily change this later and the rest of the architecture in country 1 was exactly the same as before. The key difference this time is that the API Gateway is seperated from the core application services by the Azure Service Bus meaning it is less likely that we would end up with a huge Gateway. Richer services could be built as on premise Composite Services if required.
Country 2 Physical View
In country 2 we expected that the architecture would be similar to country 1 except that the application estate was a lot smaller and simpler. Again they did not have a mature established integration capability so we followed a smaller version of the pattern we would implement in country 1. The below diagram illustrates this.
With country 2 because they only had a simple set of applications containing all of the required data we could create just a few application services and composite services to achieve what was required, We used the services framework and approach that we had created so that they all had the same Generic Endpoint and all of the other stuff that had been successful so far. If country 2 needed to add any more applications to the architecture to fulfill the requirements then they could also be “plugged in” in this on premise set up.
Country 3 Physical View
In country 3 we had a company with an existing and mature integration set up. They had an established ESB implementation which had many of their applications connected to it. Now having an existing ESB does not automatically mean you get all of the same benefits that you get with the Microservices(ish) approach we had in country 1 and 2. There are some definite pro’s and con’s to each. The key thing was that in country 3 we were prepared to sacrifice a few things that we had elsewhere to reuse the existing integration infrastructure because this was the right thing to do. The diagram below shows this part of the architecture.
One thing you may be thinking when looking at this diagram is that it is similar to the previous project in the last article where there was a monolithic “Integration Services Layer” on premise. They are both represented by a bigger green box that is true but there is a difference. In the previous project the Gateway come Integration Services Layer was supposed to be a simple WCF Service which became a big beast of a WCF Service. In this case the existing ESB is an entire product (as it happens a non-Microsoft product) and you have a platform upon which to operate multiple services. I dont view these as the same thing really.
The intention for country 3 was to minimize the requirement to change the way they do things because they have an established and successful approach and only when they are doing stuff that is new would we look to take opportunities to make their approach consistent with the rest of the architecture.
For country 3 they were able to hook into the Azure Service Bus using an AMQP transport and then to implement routing, workflow, etc to connect up their applications to the messaging and services infrastructure.
Im hoping at this point in the article you can see how we evolved the good things we had developed in our services approach and used them to deliver a more complex project using things like the Azure cloud which were now available to create a Global API. One of the biggest changes however was the introduction of the Azure Service Bus into the architecture this time. This helped us to address some of the problems that crept into the architecture of the previous project by forcing a decoupling between the API Gateway and downstream services. This was a big help in trying to ensure the API Gateway didnt grow in complexity more than what it should because it was difficult for it to become a dumping ground for functionality which no one knew where it should go.
In addition to this using Azure Web Roles and Websites as a hosting platform when you need a component hosted in the cloud it takes away a lot of the challenges around where to deploy new component instances so the overhead in terms of deployment and politics around introducing a new component to the architecture was reduced again and we even had opportunities to host some composite services in the cloud if they were country agnostic.
Finally just to reiterate that we were not specifically trying to build an SOA or a Microservices architecture neither of which were particularly hot topics at the time, but we were trying to use the underlying principles which are common to successful implementations of these things. I hope this example illustrates how in a complex project the idea of small, discreet components with relatively specific purposes that work effectively with other similar components can be used in a building block style to create an architecture which can be very dynamic and successful.