Flexing Service-Oriented Architecture on the small scale
Date: Friday, March 2, 2018
Service-oriented Architecture (SOA) is a growing trend in software development, and it means advocating for lots of small components, normally across distributed systems, which each do one function of the system and do it well. These small components are often called 'Microservices' and the distributed framework where processes can run on disparate hardware, particularly in the cloud, is referred to as 'Serverless'.
(Pedants point out that code can't truly be 'serverless' because it has to run on some server, but really the term means that the running code has no server affinity - it can run on multiple instances on multiple racks serving multiple guests and completely change all of those variables from minute to minute without a drop in service.)
But does SOA offer any real engineering advantages, outside of the distributed cloud context?
Flexible engineering in a hospitality scenario
Recently we were called upon to write a piece of software which would allow users to read barcodes and RFID tags, and would apply business logic to the scanned values before writing the results to a third party hospitality system, let's call it '3PHS'. The solution will run on on-premises hardware; just a regular old pedestal server in the back office.
Imagine you write a monolithic program to solve this problem. Maybe it's a few separate assemblies but it functions as one entity, start/stop ScanAndProcessGoods.exe.
What happens if the client introduces more sources of scanned data, other than the existing scanner fleet? That's a big structural change to the monolith. What if we want to add an additional data pipe which intercepts the scanned data and sends it to a BI data warehouse? Big change to the monolith. In fact any significant change to the business domain will require sweeping changes to the monolith.
Wouldn't it be better to write these as independent components?
Now, interestingly, we must connect to 3PHS using a COM API which only works with older version of the .Net Framework. Meanwhile, the scanning hardware is Bluetooth Low Energy (BLE) and its API is only exposed to Windows 10 Universal Apps.
Even with the judicial application of .Net Standard common libraries, these two .Net framework flavours cannot communicate. As such, a bridge was needed.
Structuring a solution as services
The Universal Windows Platform (UWP) app which we wrote to connect to the BLE devices can currently connect to a single device. It handles the workflow of a scanner, listens to anything the hardware scans, and writes that data in a minimal JSON format to a local queue service (on the server).
Another process, a .Net Fx app, listens to this queue, applies business logic, and writes the results to the 3PHS COM interface.
For a transport, we needed a local queue service which could receive JSON signals from UWP to be processed by the listener. Your first thought might be to write such a thing with:
- A REST API
- SQL Express or file system backing
- FIFO, Push, Pop and Peek features
Well, why write it when it already exists? In fact, the Azure Storage Emulator has all of these features and is - I dare say - better tested and certainly more mature than anything we could hope to write in a week.
So we selected ASE to provide a queue for interop. Our deployment task installs the latest ASE version on the pedestal server running the solution.
Back to our change scenarios from the top. If we need to handle more scanners or more various inputs, we can write a technology-agnostic app which writes to the ASE queue. No changes to the rest of the system. Likewise for double-processing the data; a BI pipeline could peek at the packets anytime before they are removed from the queue. This might take a small tweak to the primary listener to make sure that data is not eagerly deleted, but no big changes.
We intend to modify our scanner app to handle multiple Bluetooth clients, but if that turns out to be painful technically, it's no problem; we'll just spin more instances of the existing single-client scanner app! This would have been a game-ending problem if the app was a monolith.
So using Service Oriented Architecture, even on a single box for a small solution, has made the solution both more flexible and more maintainable.