Reactive systems are all the rage. Frances Buontempo compares them with a proactive approach.
Having just moved house, I am writing this with a pen on a bit of paper. My PC is not yet set up, and I broke my desk, so have solid excuse for not writing an editorial this time. Having ordered a new desk, we noticed we have no door bell, so spent a day hovering by the front door, keeping our eyes open for a delivery van. In the end, it turned out that next day delivery meant the day after the company were ready, not the day after the customer placed the order. We ordered a door bell, which did turn up and I do now have a desk. Some internet may follow shortly.
We discovered the temporary lack of doorbell could be worked round with a note along with our mobile numbers explaining the predicament. A genius idea that took a couple of days to think of. In order to communicate, whether between people or computers, something like a doorbell or understood protocol is required. If the doorbell rings, you know someone is at the door. The cat thinks the world is about to end and he must run somewhere, anywhere, away from the noise. The same message will be handled differently, depending on the audience. The communication is the bing-bong and the response is up to the listener.
Even a single machine, running a single multithreaded process or several processes may need to communicate. For threaded code with shared mutable state, synchronisation points are required. More like a door, or gate, than a doorbell, to be honest; however, in order to deal with writers writing when readers may be trying to read, action must be taken. Barriers must be in place. Locks must be acquired. Deadlocks must be avoided. In contrast to this seemingly old-school approach, various Reactive frameworks are now taking hold. Our regular writer Sergey Ignatchenko has also written about Actors on various occasions [ Ignatchenko18 ] [ Ignatchenko16 ]. At a high level, this approach involves registering observers for specific messages, for example a doorbell ringing. A producer will announce its news, and any interested parties will act accordingly; for example, the cat will leg it. You could argue the low-level approach with locks and so on, is proactive, putting things in place in advance to cover various eventualities, while Actors/Reactive is just that: reactive. Code reacts when things happen, rather than setting things up to stop things happening. Is one approach better than the other? It depends.
A surprising number of setups I have used make it hard to unsubscribe, including an events/delegates methodology, emails, phone calls from my network service provider insisting I need to buy a new tablet with SIM card, and similar. Attempting to poll my emails from my phone, while awaiting proper internet, makes me realise how much nonsense I get. I am sure I had previously attempted to unsubscribe from many of them. A few are periodically interesting, when I have time to look, but I don’t want to be cornered into an immediate response, or get further emails reminding me I have an email, and the offer ends at midnight. Which time zone? Or Google assist reminding me about deadlines for conference submissions I don’t have time to submit to. In fact, on many occasions an unsubscribe event generates further emails, asking, “Are you sure?”, “We miss you already!” I am sure you have similar experiences.
To be honest, unsubscribing from an event in .Net has proved difficult, at least for me [ Skeet15 ]. I’ve only recently tried using the .Net Reactive framework [ Github ], so haven’t fully explored how it works yet. I may find unsubscribing easier here once I’ve investigated more. Most of the time, I tend to have a listener listening for the lifetime of the program, so it doesn’t really matter. However, it is something that I expect to be possible. I expect symmetry. What starts can stop. What subscribes can unsubscribe. Each action has an equal and opposite reaction. However, defining opposite and equal can be difficult [ Love11 ]. Furthermore, expectations tend to be based on experience.
Most of my experience does come from the more old-school ‘proactive’ approach. I wonder if people’s lives tend to fall into one of these two camps. Some ‘fly by the seat of their pants’, as it were, not planning much and managing to respond or react as things happen. Others might try to plan an itinerary or todo list, and include backup plans for several scenarios. When I behave like this, I can dream up worst case scenarios better than most. It isn’t always helpful to spend so long plotting for every ‘What if’ you can think of. In code, as in life, it can come to the point where simply reporting what happened and stopping is more sensible than trying to dig your way out of a hole. You cannot handle every exceptional circumstance [ Sutter19 ].
Now, if you are trying to write robust software, you do want to throw every scenario you can think of at the system. This can be in a logical, ordered fashion, or via a formal proofs’ methodology, such as Z, for specification, development and verification [ Wikipedia-1 ]. It could also be powered by a bit of randomness, such as fuzzers, property-based testing, mutation testing or something akin to Netflix’s Chaos Monkey [ Netflix ]. Either approach can flush out problems and increase confidence that the code works as intended. Furthermore, seeing what happens if things go wrong gives you practice operating the system you built. You can see if the logs and error messages make any sense. You can try out turning everything off and on again, and see if the order matters or not. You will discover what happens if people disobey instructions, which is usually good to know. This is exactly why larger offices have fire drills. Proactively training participants, just in case, so people don’t respond in a panic if something bad does happen. It is worth planning for some outcomes. It’s worth discussing an escape plan if there’s a fire in your own home, but you might not need to practise fire drills every Wednesday morning. You don’t need to plan every single thing in meticulous detail. Some things can be figured out on the spot, and therefore spending time panicking about unlikely outcomes is a waste of time, and can lead to some very unhealthy states of mind. Some kind of sense is required. Be proactive, and organised, to a point.
Perhaps something similar goes for project management. Certainly, a waterfall approach compared to an agile approach might at first glance seem to be proactive, detailed forward planning as opposed to a just-in-time, reactive method. This is not entirely accurate. An agile method will have some kind of backlog of work. Some forethought about things that need to be done will happen. They may get fleshed out in more detail later on, rather than up front, but it’s not all purely reactive. A just-in-time Kanban [ Wikipedia-2 ] scheme in a manufacturing setting will be more reactive: when parts are needed the system reacts and orders them, instead of planning at the start of a production run, and ordering everything up front, thereby needing storage space for all the components ordered in advance. Furthermore, a waterfall project will end up moving around blocks of work on the Gantt chart or project plan, and everyone expects this to happen. We used a Kanban board for our house move. It was useful to have the TODO list in one place, and be able to find updates without having to search through mountains of emails. We did end up with four columns: to do, doing, done, can’t be bothered any more. Much more sensible that some Kanban boards I’ve seen, that sprawl into something more like a tree structure.
The trouble with planning things out in detail in advance is the unexpected things that happen. Or don’t happen. If the builders need some scaffolding, but the scaffolders forget to put it up on both sides of the house, delays happen. The order in which work happens needs to be re-ordered. If the completion date for the house buying ends up beyond the original estimate, you might need to find a new removal firm who are free at the time. In many ways, moving home is like project management. A mixture of forward planning and being agile enough to react as things changed got us through. Having packed important things in an overnight bag meant we didn’t have to rake through boxes for coffee, wine or other important elements. Reacting to the contents of the boxes as we opened them was another matter. And that was ok. A note on each box in marker pen indicating which room items had come from helped. Who knew we had so many coats? Yes, we have lots of books and cables, but coats?!
This is all a matter of pipelining and logistics. The same is true for communicating processes or threads. In fact, Communicating Sequential Processes (CSP) offer an alternative, or at least different slant to Actors and Reactive approaches. CSP is a formal language for describing patterns of interaction in concurrent systems, according to Wikipedia [ Wikipedia-3 ]. CSP’s design suited the transputer, with its pipeline processor. CSP allows modelling and analysis nearer formal proofs that can find errors testing may miss. It is built from primitives, defined as events and processes, and an algebra, think adding up – making new primitives, choosing, interleaving and hiding (according to Wikipedia). Now, some say [ Vernon15 ] sequential processes will be a bottleneck, so Actors are much better. Specifically, it says “ Sequential processes can’t create other sequential processes ” (page 11), going on to suggest that Actors are powerful than sequential approaches. However, the Wikipedia article claims
the ‘Sequential’ part of the CSP name is now something of a misnomer, since modern CSP allows component processes to be defined both as sequential processes, and as the parallel composition of more primitive processes
Now, CSP are similar to Actors but made “ fundamentally different choices with regard to the primitives they provide ”:
- CSP processes are anonymous, while actors have identities.
- CSP uses explicit channels for message passing, whereas actor systems transmit messages to named destination actors.
- CSP message-passing fundamentally involves a rendezvous between the processes involved in sending and receiving the message, while message-passing in actor systems is fundamentally asynchronous.
Each approach has different pros and cons, but all deal with things happening in an unknown order. Different languages may use different words, for example ‘yield’ for coroutines in Python [ Ramalho15 ], or rendezvous in Ada [ Miranda04 ]. In .Net, adding ‘async’ to circumspect places in code moves from proactive to reactive. The original CSP paper [ Hoare78 ] talks about solving various problems including how to communicate, how to synchronise, and how to choose between synchronisation methods. How ever you approach code, or life, you will need to communicate, meetup, and decide a suitable method for each. You need to make a decision, and whatever you choose may work well some of the time, and be more difficult other times. There is no One True Way. Sometimes, proactive planning helps, but you need to be able to react on the spot too. Sometimes a deadlock can be solved by a sleep. If anyone wants to write up different ways of communicating or synchronising, do get in touch. I suspect most of you have tried at least one of the many approaches. Tell us about it.
References
[Github] Rx.Net: https://github.com/dotnet/reactive
[Hoare78] C.A.R. Hoare (1978) ‘Communicating Sequential Processes’ in Communications of the ACM 21:8 on pages 666– 677, available at https://www.cs.cmu.edu/~crary/819-f09/Hoare78.pdf
[Ignatchenko16] Sergey Ignatchenko ‘On Zero-Side-Effect Interactive Programming, Actors, and FSMs’ Overload 131 pages 9–12, February 2016, available at https://accu.org/index.php/journals/2199
[Ignatchenko18] Sergey Ignatchenko, Dmytro Ivanchykhin and Marcos Bracco ‘(Re)Actor Allocation at 15 CPU Cycles’ Overload 146 pages 14–19, August 2018, available at https://accu.org/index.php/journals/2533
[Love11] Steve Love and Roger Orr ‘Some Objects Are More Equal Than Others’ Overload 103 pages 4–9, June 2011, available at https://accu.org/index.php/journals/1971
[Miranda04] Javier Miranda and Edmond Schonberg (2004) ‘The Rendezvous’ in GNAT: The GNU Ada Compiler , online at https://www2.adacore.com/gap-static/GNAT_Book/html/node22.htm
[Netflix] Chaos Monkey: https://netflix.github.io/chaosmonkey/
[Ramalho15] Luciano Ramalho (2015) Fluent Python: Clear, Conise and Effective Programming published by O’Reilly, Aug 2015
[Skeet15] Jon Skeet ‘Clean Event Handler winvocation with C# 6’ https://codeblog.jonskeet.uk/2015/01/30/clean-event-handlers-invocation-with-c-6/
[Sutter19] Herb Sutter ‘De-fragmenting C++: Making exceptions more affordable and usable’ at ACCU19: https://www.youtube.com/watch?v=os7cqJ5qlzo
[Vernon15] Vaughn Vernon (2015) Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka published by Addison-Wesley Professional, August 2015
[Wikipedia-1] ‘Formal methods’: https://en.wikipedia.org/wiki/Formal_methods
[Wikipedia-2] ‘Kanban’: https://en.wikipedia.org/wiki/Kanban
[Wikipedia-3] ‘Communicating sequential processes’: https://en.wikipedia.org/wiki/Communicating_sequential_processes
has a BA in Maths + Philosophy, an MSc in Pure Maths and a PhD technically in Chemical Engineering, but mainly programming and learning about AI and data mining. She has been a programmer since the 90s, and learnt to program by reading the manual for her Dad’s BBC model B machine.