Reactive systems - a change for business analysts?

Business-analyst interaction with developer

In recent years, we have seen the emergence of reactive architectures that introduce the idea of eventual consistency. This particular architectural pattern is one that needs to be communicated to requirement gatherers.

The semantics of web-application architecture have remained constant over the past twenty years, with new, more advanced frameworks appearing, but largely based around the same CRUD-style topology. This has inherently given requirements-gatherers a fixed notion of how systems should behave in certain circumstances. More recently, some architecture patterns have moved away from this behaviour in order to better facilitate the scaling of systems under heavy load. This has implications for the upstream consumers of these systems.

Reactive Systems

The reactive manifesto was published in 2014, and since then, we have witnessed the adoption of reactive systems.

Reactive architecture traits
Reactive architecture traits, credit: The reactive manifesto

Without delving into detail about what a reactive system is, the basic premise is that systems should be responsive and resilient even in the face of large spikes in incoming traffic. The mechanism by which this is achieved is to ensure communication between components is done in an asynchronous way, through messaging. But making communication asynchronous can have implications for the end user, and therefore for requirement-gatherers. Let's take a somewhat contrived example for the purpose of illustration:

Event-driven checkout process
A checkout process in a reactive system

The example depicts an online checkout process, where, following a successful payment, an order is processed. There are many different systems involved in this flow, and a large part of the flow uses messaging to communicate between components.

The key thing to note is that, immediately after step 5 in the process, control is returned to the user before the order has actually been created. So the obvious question is, what do we return to the user? Some options might be:

  • Create the order ID up front, and hand it over to the order creation process while at the same time returning it to the user.
  • Create an interim ID, something akin to a UUID, and periodically poll a separate /order-status/{uuid} endpoint, displaying some sort of waiting spinner to the user.
  • Keep a socket open between the client and the server and notify the client when the order is created.

The second two options resolve the asynchronous problem, but introduce either more network traffic or longer connections to the server.

Up-front Order ID

If we choose to proceed with the first option, we need to produce a unique identifier before processing the order. This approach provides a superior user experience, because, from the end user's point of view, the order gets processed very quickly. We need to be aware of eventual consistency however. If there is a requirement to immediately retrieve a submitted order for example, this may not be available for a few seconds. Therefore, the user experience will have to be managed appropriately. We also need to ensure that the order is created, and that it is assigned the identifier that has user has already received.

Theoretically, we have all the information we need from the user, so the onus is on the organization to process the order to completion. The technical challenges involved with potential failure are not something new to development teams familiar with distributed environments (retries, dead-letter queues etc) but can lead to operational concerns. In rare cases, orders may require manual intervention, and emails may need to be sent to various teams after an order has failed a number of times. This is something that needs to be organized by the business.

The key point here is that, it is not merely implementation detail, and that the architecture decisions can have consequences for the user client flow and experience. In the example above, it is assumed that architectural direction has been driven by the business, specifically, by improving the responsiveness of the system. In this instance, it is immensely useful to include business analysts and product owners in the architectural direction. If an eventually-consistent experience is deemed unacceptable, then we have no option but to choose one of the other two options above to give the illusion of synchronous communication. However, when business analysts and product owners understand the driving force behind the decisions, they are often more than happy to accommodate the eventual consistency model in their requirements.

Conclusion

With novel paradigms emerging in software architecture, existing assumptions about certain use cases can no longer be held. Requirements should always be driven by business, but sometimes we need to reconcile business requirements with business-driven technical requirements. In this situation it is useful to inform other stakeholders about the architectural direction. Business analysts can then accommodate these patterns in cases where doing so will not affect the business process in a negative way.

Architecture is about trade-offs, and so, in cases where we really need to go against the architecture, we will do so by choosing another path.