0

I'm in the process of redesigning our entire process control system (a daunting task, really!), and want to make the right decisions to how each system in the ecosystem communicates with each other.

In particular, I want to control how systems trigger actions in separate systems.

Some background: In our current implementation, most actions are triggered through an event flag system. When System A wants to call Process 1 from System B, System A raises an event Event Foo in a shared memory section. System B sees Event Foo, knows to call Process 1, does so and continues on. Multiple systems can raise an event, multiple systems can consume an event, and a system can perform multiple actions from one event. What this results in is a complete lack of traceability; it is extremely to difficult to know when an event occurs, who consumed an event, and who raised the event.

Off the bat, I can think of a few improvements to our current system: in the metadata for an event, include the caller system name; keep track of receiver system names; write a logger for the event handling to keep track of timing, callers, and receivers. Additionally, instead of checking shared memory, I would use a managed interface with publishers and subscribers, which would allow me to keep track of all systems involved in an event. From here on out, I will refer to this as a "publish" architecture. This would make debugging easier and is most similar to what we have now, but is not really possible with the current system as it is a closed source, black box process.

But I can also think of an entirely separate way of handling this: have each caller make a direct request to the process it intends to affect. Using my initial example, when System A wants to call Process 1 from System B, System A pushes a request to System B with metadata stating the process and caller ID. To me, this has the advantage of being explicit code - any programmer looking at the call knows who the receiver is and what process is executed. Likewise, a code search for a process and receiver can find the corresponding caller, allowing for backwards traceability as well.

I can think of some pros and cons to each.

  • With Pushing, code is more explicit. Receiving processes are directly visible.
  • With Publishing, code is more implicit. Receivers/callers are not specified at the publish call, and processes can change without the caller knowing.
  • With Pushing, code can become WET (repetitive). Multiple process calls would require multiple pushes. Multiple callers would require copying push commands to multiple places, possibly presenting maintenance concerns when the receiving processing changes.
  • With Publishing, code is DRY (succinct). Multiple process calls can be achieved with a single publish. Changing receivers can occur without modifying callers.
  • Pushing allows for synchronous operation. Pushes can occur and wait for a processes to complete before proceeding to the next operation.
  • Publishing requires mostly asynchronous operation. Without knowing what processes are affected, execution order can't be controlled and would require additional framework to wait for completion.

To recap, I'm considering two options: a publish architecture where any number of callers publish events and and any number of receivers consume events, and a push architecture where a single caller directly interacts with a single receiver. Is one considerably better than the other, and when should I decide to use each?

1
  • Before drastically changing the architecture of an existing system (in this case from Publish to Push), see if you can find out why the current architecture is based around the Publish paradigm and check if any of those reasons are still valid/good. Commented Apr 4, 2022 at 7:16

1 Answer 1

4

Sounds like you are going backwards.

The benefit of the pub sub architecture is that System A doesn't call System B, it doesn't know about and therefor isn't coupled to other systems.

This enables loosely coupled micro services and scalability.

Yes you have an orchestration problem when things break, but you can solve that by moving from your shared memory implementation to a proper message queue where you can see the relationships and metrics.

If you move back to a coupled architecture where system A calls system B and if you want system C to also do something you have to edit A and put more code in, you move away from that and towards a monolith.

Now monoliths have their apologists, but not having the logging you want seems a bad reason to move back to one when an off the shelf message queue might solve your issues.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.