The Architect's Napkin
Event-Based Components – Leaving the beaten path of canonical object orientation
Object orientation as it is taught and practiced today has a problem: it leads to designs that are hard to change and hard to test, because classes depend on each other in intricate ways. I want to show you an alternative: Event-Based Components (EBC).
A litmus test: Tic-Tac-Toe
To see whether canonical OO really is adequate for designing software, let´s take a simple, well-known example: a Tic-Tac-Toe game with a whiteboard-friendly design exercise.
The requirements: two players take turns marking fields in a 3x3 grid; the first to get three of their marks in a row, column, or diagonal wins; if the grid fills up without a winner, it´s a draw.
The GUI is a simple 3x3 grid of buttons plus a status display showing whose turn it is or who has won.
Try to design this with classes and their relationships/collaborations first – using whatever your favorite OOAD approach is, e.g. CRC cards or UML class/sequence diagrams. Chances are, you´ll end up with classes that reference each other in a tangled way: a Game class referencing a Board, a Board referencing Cells, some Player class, and a WinDetector needing access to the Board's state, and the GUI needing to be wired to all of this. Testing any one piece in isolation becomes hard, because of all the direct dependencies.
A simpler example first
Before tackling Tic-Tac-Toe in full, let´s look at an even simpler example to introduce the alternative approach: a colored rectangle on a form, toggled between red and green by a button.
Requirements: on startup, the rectangle shows some initial color. Clicking the button toggles the color between red and green.
Instead of designing this with classes calling each other, let´s design it as a flow of activities – boxes and arrows, resembling BPMN or UML Activity Diagrams, but used pragmatically rather than strictly:
- "Get Initial Color" – produces the color to show at startup
- "Toggle Color" – takes the current color and produces the opposite one
Boxes represent activities named with verbs (what they do), and arrows represent data flowing between them (events carrying data), not method calls. No activity calls another; data just flows from one to the next.
Translating the diagram into code
Each activity becomes a class. Its inputs become methods (prefixed In_), and its outputs become events (prefixed Out_):
public class ColorManager
{
private Color currentColor = Color.Green;
public void In_ToggleColor()
{
this.currentColor = this.currentColor == Color.Green ? Color.Red : Color.Green;
this.Out_CurrentColor(this.currentColor);
}
public void In_GetInitialColor()
{
this.Out_CurrentColor(this.currentColor);
}
public event Action<Color> Out_CurrentColor;
}
The GUI itself is modeled the same way, as a functional unit with its own inputs and outputs:
public class WinMain : Form
{
public event Action Out_Start;
public event Action Out_ToggleColor;
public WinMain()
{
InitializeComponent();
this.Load += (s, e) => this.Out_Start();
this.button1.Click += (s, e) => this.Out_ToggleColor();
}
public void In_CurrentColor(Color color)
{
this.panel1.BackColor = color;
}
}
Note that neither ColorManager nor WinMain know about each other. They just define input methods and output events. The connections between them – the wiring – happen elsewhere, decoupled from either class:
static void Main()
{
var wm = new WinMain();
var cm = new ColorManager();
wm.Out_Start += cm.In_GetInitialColor;
wm.Out_ToggleColor += cm.In_ToggleColor;
cm.Out_CurrentColor += wm.In_CurrentColor;
Application.Run(wm);
}
This wiring code directly mirrors the diagram: boxes become classes, arrows become event subscriptions. And because ColorManager and WinMain have no compile-time dependency on each other, either one can be tested, reused, or replaced in isolation.
Summary
This is the core idea of Event-Based Components: design software as a flow of independent, event-connected functional units, rather than a web of mutually referencing classes. Diagrams translate directly into code, and code stays traceable back to the diagrams. In later posts I´ll apply this to the Tic-Tac-Toe example and to more elaborate scenarios.
PS
Source code for these examples is available in a Google Project repository (see the link on the original article page).