In my previous article I designed and implemented a small desktop calculator using Event-Based Components. That was fun and went smoothly – but in the end I was in a hurry and missed a bug and a feature. In the meantime I found some time to fix both.
Let me take the opportunity to show you the application architecture in its entirety. The missing feature – Clear calculation - has already been added:
This is the high level view. All activities except one are so simple, no further detail is needed. Calculate, though, deserves some refinement. So let´s quickly zoom in:
That´s it. An application defined on two levels of abstractions. No class diagrams needed, no component diagrams, no packet diagrams. Just some kind of activity diagrams with a clear set of rules for translating them into C# code – which, by the way, you can find here.
The beauty of it – as I see it – is that you can draw EBC diagrams on as many levels of abstraction and you´ll find all of them in your code. Model and code are always in sync.
And what about classes? Sure, there are classes:
But mind you: they do not depend on each other. That´s the power of events. The classes are either manifestations of activities (e.g. Calculate) and thus do not depend on other´s by definition. An activity does not depend on another activity to be performed; it just uses input and produces output (or a side effect). Or the classes are aggregations of activities and thus also do not need to depend on others.
The bug to fix was, that the calculator did not deliver a correct result if after a “=” an operator was clicked and then another number entered, e.g. 1+2=+4= did not deliver 7 as the result.
The solution to that was a bit tricky. But in the end I managed to implement it without a major architectural change. I only needed to make the current number a nullable type:
private double? currentNumber;
public void ExtendNumber(char c, Action<double?> out_currentNumber)
if (c == '.')
if (this.currentNumber == null) this.currentNumber = 0.0;
That way the CalculatorEngine can distinguish between an operator clicked after entering a number and an operator clicked after “=”:
public void In_ApplyOperation(Tuple<char, double?> input, Action<double> out_result)
double result = 0.0;
if (input.Item2 != null)
if (this.operation == '=') this.operands.Clear();
result = Calculate();
if (this.operands.Count > 0)
result = this.operands.Peek();
this.operation = input.Item1;
It made me quite happy that no change to the overall design diagram was needed to accomodate the bug fix. I took it as a sign of a good design ;-)
Event EBC designs don´t protect you from forgetting stuff and writing buggy code. But still I think they improve my coding. They narrow my focus, because the domain stuff happens mostly in leaf activities:
Depending on your level of detail those atomic activities are comparatively simple.
Composite activities on the other hand seem complicated – but they are not. I even think they could be automatically generated from an EBC design. For now, however, I´ll stick to hand crafting my EBC code ;-)
Since EBC diagrams do not show implementation details like classes, objects, interfaces they are true models to me. They abstract from a concrete platform. You could translate them to C#, Java, Ruby, F#, C++ etc. That I also find quite important. You don´t want to get stuck in implementation details during the design phase.