The Architect´s Napkin

Software Architecture on the Back of a Napkin
posts - 69 , comments - 229 , trackbacks - 0

My Links

News

Archives

Actors in a IODA Architecture by Example

The IODA Architecture is supposed to make software design easier and improve code readability for about any problem domain. I’ve tried to show an example of that in my previous article. It was a larger scenario than the usual code kata, but still it was a problem to be solved by synchronous programming.

In this article I want to move beyond that and tackle a problem where multiple threads need to be employed. Here’s the challenge:

Write an application to work as an alarm clock. It displays the current time and the user can set a wakeup time. Once the wakeup time is reached the application sounds an alarm.

Requirements analysis

This scenario needs some user interface design. How should the user interact with the program’s body? How about this:

image

When the user switches the alarm on, the remaining time until the wakeup time will be displayed. Both current time and remaining time will constantly (every second) be updated.

The user can switch off the count down at any time. The remaining time will then disappear.

When the wakeup time is reached a WAV or MP3 file should be played by the application.

Trying to bridge the requirements-logic-gap I see there is just a single dialog to this application, and within the dialog there are two interactions. Let’s call them “switch on” and “switch off”.

However… behavior is not only triggered by a user putting the switch left or right. The application is supposed to also behave in some way on the tick of a clock. So there is another “invisible user” interacting with the application. It’s the system clock.

From this I derive a picture of the whole application.

image

The system-environment diagram shows very application specific behavioral aspects separated into their own modules. I don’t know yet how those modules will be working together, but it’s clear to me at least these modules should be present. The portals and the provider each encapsulate an API. And the domain is the home of the very alarm clock logic.

Although “module” sounds technical this to me is still analysis. Because these aspects can readily be found in the requirements. They are so tangible I could and should talk about them with a customer.

But please note: According to the IODA Architecture these behavioral modules are not related to each other in any way. There are no functional dependencies between them whatsoever.

Finally one last step in the requirements analysis phase: finding features. Interaction behavior usually is not monolithic. So what behavioral aspects can be found in each interaction?

  • System clock tick
    • Update display of current time
    • Update display of remaining time while alarm is switched on
    • Check if wakeup time has been reached
    • Sound alarm is wakeup time has been reached
    • Switch off checking for wakeup time if wakeup time has been reached
  • Switch on the alarm
    • Switch on checking for the wakeup time
  • Switch off the alarm
    • Switch off checking for the wakeup time

To me Agile Architecture means, such increments have a 1:1 correspondence to programming language structures. Dialogs become classes, interactions become functions, and features also become functions. So what the analysis phase has brought me is a first rough sketch of my code. It will consist of at least 4 classes (dialog portal, system clock portal, alarm bell provider, domain). And there will be at least 3+7=10 functions for all the interactions and features.

I guess, this is all I need to enter the next phase: designing the solution, i.e. describing the behavior visible on the outside by building it from smaller behaviors in a declarative way.

Solution design

My initial sketch of the data flows in the application looks like this:

image

It took only maybe 5 minutes to come up with it. I like to draw flow designs with pen and paper. It’s flexible and simple. No other tools needed.

But I’d understand if you have a hard time deciphering my handwriting ;-) So let me go through the parts step by step and redraw them in a legible way.

Let’s start with the most interesting interaction: the system clock tick.

image

For every tick of the system clock it is checked, if the wakeup time has been reached. Of course this check is only done while the alarm is switched on (see status).

Also, while the alarm is switched on, the remaining time until the wakeup time is calculated. Both current time and remaining time flow to the UI to be displayed.

In case of the wakeup time having been reached this is flagged to the UI and the alarm bell is rung.

After this interaction the rest is easy. Let’s do start and stop in one diagram:

image

Starting the alarm clock means registering the wakeup time and setting the status to “active”. Stopping it means setting the status to “inactive”.

Taking multithreading into account

That’s an easy design - but unfortunately it would hardly work if implemented just like this. The reason: there are multiple threads at work here. This would at least cause difficulties for displaying the current/remaining time. They flow into the UI from a non-UI thread. You can see this in the following diagram: a red data flow arrow is connected to blue box.

image

Interestingly the same happens in Check wakeup time: the functional unit accesses the wakeup time and the status from the red thread - but this state is blue, because it first got set by Start which gets its data from the UI.

Multiple threads reading and writing the same resource does not seem like a good idea. So what can we do about it?

To solve the problem of data flowing into the UI from a non-UI thread it’s easy to insert a synchronization point. This functional unit just takes data coming in on some thread and passes it on on another thread, the UI thread.

image

Technically this is no problem in .NET with a SynchronizationContext.

But how to protect access to the common state of Start and Check wakeup time reached and Stop from multiple threads? That could be done with a lock.

For a long time I’d have gone down that road - but not anymore ;-) I’ve become a fan of the actor model and its .NET implementation Akka.NET.

Before I introduce actors into the design, though, some class design is in order after the flow design.

Class design

So far the design contains only “functional units” (FU) as processing steps in a data flow. Those FUs will be implemented as functions. But which classes should these functions be put in?

This is easy, I’d say. Have a look:

image

UI, clock and alarm bell all get their own classes. I guess that’s a pretty obvious decision.

And Watchdog? That class encapsulates the state shared by the remaining functional units. Shared state to me is a “hard aspect”. It calls for being wrapped in a module of its own.

Actor design

From the threading point of view the class situation looks like this:

image

Two classes need their own threads: the UI runs on the UI thread, the clock on some system thread.

The Watchdog is accessed by multiple threads and needs to protect its inner state.

And the Alarmbell pretty much does not care. It receives data on the clock thread, but does not need to do its job on that thread. Depending on how the alarm bell gets implemented it can run on the clock thread - or maybe gets its own for even more decoupling.

Actors help to implement this without resorting to special synchronization mechanisms like SynchronizationContext or locks. In this case I just need to encapsulate each class in its own actor:

image

Between actors flow messages. They are received by the actors’ “inboxes” and worked upon when a previous message has been processed. All actors work on different threads. But each actor just on one (although that might be a different one for each message). That way there cannot be any conflicts when accessing state. Actors protect any state by sequential message processing.

Message design

Data flowing between two functional units in a Flow Design often does not need a special type. It’s clear what it is and what’s supposed to happen with it. A single processing step representing an activity produces data which is consumed by a single processing step representing an activity.

image

With actors that’s different. Actors are more like nouns than verbs. They represent entities rather than activities. That’s why they are called actors. Hence actors often receive many different messages to process - but all in a single “inbox”.

In order to find the right message handler it helps to send messages of very concrete types. That could be commands or events. Commands describe, what’s supposed to happen. Events describe what has happened.

Let me take a subset of the actor flow design as an example:

image

Each actor has a single entry point into which all messages flow.

The UI actor outputs/sends commands because it is the one relating the user intentions to the rest of the program.

The watchdog actor on the other hand outputs/sends events informing other actors about what happened.

Commands and events are “implicit” in the original flow design. They now have to be made explicit in order to have the actors communicate clearly with each other. See the GitHub repo with the implementation for a list of them.

Implementation

I implemented the application in two phases:

  • First I did it without actors. There were only the classes and synchronization with the UI thread. Not even a lock around the watchdog state. This I did not to get it 100% right, but to see if my idea of an alarm clock flew at all. It was much more than a walking skeleton - but not really the fully fleshed application I wanted. You find the sources for this version here.
  • Only in a second step I wrapped actors around the classes. This proved very easy. I just took what was already working and put in another set of containers. Functions and classes are modules; modules are containers to produce evolvability and productivity. Actors on the other hand are host; that’s how I call containers to produce some efficiency, e.g. a non-functional requirement like performance, scalability, or responsiveness. The latter is required for this application. The UI must stay responsive to be able to start/stop the alarm clock at any time. You can find the sources for this version here.

The implementation did not pose any challenges, except one: Getting the alarm bell running on OSX. I’m working with C#/Mono on a Mac and all’s well including doing graphical user interfaces with WinForms. (WinForms GUI’s on a Mac don’t look that nice, but they serve the basic purpose.) The simplest way to play sound files in .NET/Mono is to use the System.Media.SoundPlayer class. But it simply would not work with a .WAV file on OSX. Bummer. So I had to switch to an out of process call to the OSX utility afplay. This led to an interface for the alarm bell - IAlarmbell - and two implementations: AlarmbellOSX and AlarmbellWin.

But that’s really a minor point. Most important is that switching from “regular” multithreading to actors worked like a charm.

The first actor I wrote was the clock. I call it an actor even though it’s not an Akka.NET actor. Rather it’s a simple class doing its work on its own thread: every second it publishes the current time via a C# event.

image

I needed it for the first phase and saw no reason to wrap a real actor around it in the second phase.

The other actors I wrapped around an existing class. For example the Watchdog class to check, if the wakeup time has been reached:

image

Each of the “bubbles” of the design becomes a function. Input flows into these “bubbles” as function parameters. But the output of Check flows out via C# events. I could have implemented it with continuations instead, but wiring up the initial classes in phase #1 was easier with events. Anyway… I hope you agree, this looks pretty straightforward and clean.

This class is free of any multithreading concerns. I can test it easily.

Enter the actor: The WatchdogActor takes a Watchdog instance and wraps it so it becomes thread-safe.

image

See how the actor itself does not contain domain logic. It just wires its “inbox” to the “input ports” of the domain class:

Receive<StartCommand> (cmd => dog.Start_watching_for (cmd.WakeupTime));

(Please see the Akka.NET documentation on how receiving and sending messages with actors works. Or even better: Join the Akka.NET Bootcamp to get your hands on this awesome framework.)

The same happens for the "output ports" of the domain class. The actor registers handlers for each event, wraps the event data into an event object, and sends it on...

dog.OnRemainingTime += remainingTime => {
 
var e = new RemainingTimeEvent{RemainingTime = remainingTime};
  onEvent.Tell(e, self);
};

The domain class does not know what’s done with its output downstream in a data flow. Neither does the actor know what’s done with the event objects it outputs. It’s a matter of the integration in Program.Main() to determine who’s going to listen to whom:

image

Actors are created through a factory, e.g. sys.ActorOf (dogActorProps, “WatchdogActor”). The factory gets what it needs to produce a Watchdog via a Props structure:

Props.Create<WatchdogActor> (dog, new[]{ "DlgActor", "AlarmbellActor" });
...
Props.Create<DlgActor> (dlg, dogActor)

The parameters of Create() can be the ones passed on to the constructor. In this case that’s an instance of the domain class, e.g. dog for Watchdog.

In addition I pass in a list of actors who are recipients of the actor’s output. I do that with a list of actor names. This list then feeds an ActorMultiRef which is used to broadcast messages to multiple actors:

var onEvent = new ActorMultiRef (Context, eventReceivers);
...
onEvent.Tell(e, self);

Akka.NET does not seem to support “multicast events” in any other way. Routers seem too heavyweight for that purpose. So I created my own small multicast actor reference. It looks up the concrete actors by name. That way I can “forward reference” actors not yet instantiated. This lets me integrate actors in a very easy way and as flexibly as ordinary objects.

Summary

The next diagram shows the class hierarchy of the solution:

image

As you can see there are two strata of integration and - again - only one for operations. Only the Operation-classes contain logic. Neither Integration- nor Data-classes contain any. There are no functional dependencies in this solution.

The actors solve an efficiency problem as hosts - but at the same time work as modules integrating domain behavior. This integration is very simple, since there is a 1:1 relationship between actors and the “workhorses” they “ride”. But still… The resulting class diagram is very, very simple. And the “workhorses” (operations) are easy to test.

My bottom line on this project is: Actors fit nicely with the IODA Architecture and Flow Design. And they make solving problems with multiple threads easier.

To me actors look like coarse grained modules. They are a different kind of classes so to speak. Their USP is the much more rigorous encapsulation of internals. They feel quite a lot like objects as Alan Kay envisioned them. They are somewhere in the middle between class and µService with their asynchronicity and message based, but platform dependent contracts.

I guess, I’ll use more of them in the future :-) Not for technology’s sake, but as a means to encapsulate logic even better than with classes - and at the same time improve on performance and scalability.

Print | posted on Tuesday, May 12, 2015 6:29 PM | Filed Under [ Software design ]

Feedback

Gravatar

# re: Actors in a IODA Architecture by Example

Very interesting posting. I went back and read the previous one on IODA to get more background on your perspective. I really like what you have done here and appreciate the cleanliness of the design. You ever consider doing an example using IODA and Akka for something like an MVC application? You level of detail I believe would be a benefit for those just learning Akka.

Cheers,

Jason Wyglendowski
5/13/2015 2:42 AM | Jason Wyglendowski
Gravatar

# re: Actors in a IODA Architecture by Example

Glad you like my approach.

As for MVC: I think MVC is a detail of the UI aspect of a software. If you're using it, the controller should just do integration: it takes input from the view, hands it over to some "backend", and later on puts results into the view.

The controller should be as thin as possible.

And the model? You need to distinguish between data and behavior. The data should be thin, too. The behavior is most important.

I'm no Web/MVC technology buff. I'm more interested in the conceptual design. So from that point of view MVC is a detail ;-)

But from a very technical point of view it might not be so easy to get MVC play nicely with Akka.NET. But I've found some info here: http://stackoverflow.com/questions/27634843/akka-net-actor-system-in-asp-net
5/13/2015 8:21 AM | Ralf Westphal
Gravatar

# re: Actors in a IODA Architecture by Example

I've read up on IODA design, and very much like what I see. I have come up with a program structuring pattern myself called "Declarative, Imperative, then Inquisitive", or "DItI" for short. It's interesting that IODA and DItI seem quite compatible with each other, what with the former addressing large-scale program structure, and the latter addressing finer levels of detail (down to individual program statements and function design). If you're interested, http://sam-falvo.github.io/2010/02/27/declarative-imperative-then-inquisitive/ . I'd be interested in your thoughts.
5/14/2015 10:09 AM | Samuel A. Falvo II
Gravatar

# re: Actors in a IODA Architecture by Example

Nice to see you having reflected the actors approach regarding your IODA architecture. I thought about that already when designing the ScalaFlow and XtendFlow libraries (but you are as always one step ahead :-)). Actors seem to be very close to the concept of functional units. Similar encapsulation - independence of each other, similar concept of receiving and forwarding data. Even the problems regarding message processing strategies like at your Flow-Runtime seems to be similar (as mentioned in your article http://blog.ralfw.de/2012/09/der-fortschritt-in-datenflussen.html) to those actor systems in Scala and Akka have.
Only the purpose from architectural point of view is different. Actors are more hybrids - hosts at one side - solving concurrent programming problems, integrating modules on the other side as you mentioned already.

What do you think about combining function units and actors closely together - every function unit has the semantic of an actor for each of its input ports, means, each port works like an actor's inbox? Maybe, this should not be applied to the more general concept of IODA. But for a real flow design programming language this could be a very valuable approach.
In fact the actor concept is the first really successful try in main stream languages to deal with the concurrency problems programmers have today, almost stumble over them. Actors seem to be the right language abstraction for concurrency programming. Why not combining both?
The only challenge would be to make message passing trough an inbox-based port quite efficient as a method call. But that, as I understood from the theoretical papers from Scala and Akka, is already solved and should not be a problem (and was also already solved by your Flow Runtime).
Denis
5/15/2015 10:23 PM | Denis
Gravatar

# re: Actors in a IODA Architecture by Example

Making each and every functional unit of a data flow an actor to me seems overengineering. It's the same as with Event-Based Components.

Actors are an even more natural translation than classes it seems. But truly independent message processing is not always necessary. Actors are a wonderful addition to the list of patterns of how to translate flow designs.

Currently actors to me seem more coarse grained than classes. Even though communication between them seems to be efficient it surely is slower than between functions. There is a price to using actors. And that I'm not willing to pay all the time.

As demonstrated I like to think of them as means to build async flows by integrating sync functional units. Maybe 1:1, maybe 1:n.
5/16/2015 4:21 PM | Ralf Westphal
Gravatar

# re: Actors in a IODA Architecture by Example

How does DlgActor look like and syncronize thead to ui? How does that integrate with mvvm?
9/6/2017 7:00 PM | Thomas Stegemann
Post A Comment
Title:
Name:
Email:
Comment:
Verification:
 

Powered by: