Some thoughts on Event-Based Components

The German software engineer Ralf Westphal currently spreads some knowledge about an alternative model for programming components and especially communication between them. Due to their nature they are called Event-Based Components. After some discussion with colleagues at SDX I want to share some of my thoughts on that with you (of course for further discussion as well).
The aim of Event-Based Components (EBC) is to create software components that are really composable without specific topological dependencies. You can compare EBCs with elements in electronic circuits. But first things first…

Interface-Based Components style

Normally we’re developing components in .NET as IBCs: Interface-Based Components. That means client classes have topological and functional dependencies to interfaces (or directly to other classes), which provide some sort of functionality. Well developed, such a dependency could be resolved with a Dependency Injection container like StructureMap:

class Program
{
    static void Main(string[] args)
    {
        // Bind (here: StructureMap)
        ObjectFactory.Initialize(x =>
        {
            x.For<IBusinessClient>().Use<BusinessClient>();
            x.For<IDataAccessComponent>().Use<DataAccessComponent>();
        });

        // Resolve and Run
        IBusinessClient client = ObjectFactory.GetInstance<IBusinessClient>();
        client.BusinessOperation(0);
    }
}

interface IBusinessClient
{
    void BusinessOperation(int personId);
}

class BusinessClient : IBusinessClient
{
    private readonly IDataAccessComponent _dataAccessComponent;

    public BusinessClient(IDataAccessComponent dataAccessComponent)
    {
        _dataAccessComponent = dataAccessComponent;
    }

    public void BusinessOperation(int personId)
    {
        Person p = _dataAccessComponent.GetPerson(personId);
        // do something ...
    }
}

interface IDataAccessComponent
{
    Person GetPerson(int id);
}

class DataAccessComponent : IDataAccessComponent
{
    public Person GetPerson(int id)
    {
        return  // ...some person...
    }
}

That’s pretty standard so far, isn’t it? In Ralf’s opinion this programming style lacks real composability of the components. Due to the topological dependency the clients is bound to a specific interface and no arbitrary component can perform the functionality. Instead a component has to implement the specific interface. You’re not able to use components which could provide the functionality, but don’t implement the interface…

Event-Based Components style

Ralf suggests Event-Based Components to the rescue. Components in this programming style can be compared to components in electronic circuits. Methods act as input pins of a component and can be called by other components. Events/delegates act as output pins and establish a connection to other components that should be used by the component or to provide calculation results. The output pins can be bound to any arbitrary method that meet the signature. Thus the dependency is still functional, but not topological any more.
The example above in EBC style could look as follows:

class Program
{
    static void Main(string[] args)
    {
        // Build
        var client = new BusinessClient();
        var dataAccess = new DataAccessComponent();

        // Bind
        client.GetPerson = dataAccess.GetPerson;

        // Run
        client.BusinessOperation(0);
    }
}

class BusinessClient
{
    public Func<int, Person> GetPerson { get; set; }

    public void BusinessOperation(int personId)
    {
        Person p = GetPerson(personId);
        // do something ...
    }
}

class DataAccessComponent
{
    public Person GetPerson(int id)
    {
        return  // ... some person ...
    }
}

This example shows the components BusinessClient and DataAccessComponent interacting as EBCs in a very simple form by using the Func<T> delegate type and thus enabling symmetric communication. Ralf encourages the use of standard input/output pins as Action<object>, which leads to asymmetric communication, because the DataAccessComponent would need to declare an output pin for providing the Person as result of GetPerson(). For the sake of simplicity I haven’t followed this principle here.

So the example uses a Func<T> delegate and no event. But you can still think of it as Event-Based Component, just because events are nothing more than multicast delegates. I could have used events instead of the simple delegate as well, but I’m quite fine, because I don’t need the functionality of multiple subscribers here.

As you can see from the example, just like IBCs the EBCs have some kind of initial Bootstrapper phase. This is the time when the components are composed. The output pins of a component’s client (BusinessClient in this example) are connected with the input pins of the component itself (here: DataAccessComponent).

Benefits

When I first saw EBCs I thought: „Dude, this is damn cool, isn’t it?“. Indeed this kind of programming style first feels strange and alternate and thus for me it’s really interesting. But are there some real benefits as well?

I think one big benefit of EBCs is their composability. A client hasn’t to know the interface of a component from which he wants to use some functionality. A component on the other side is not forced to implement an interface to provide some functionality, but it’s still retaining loose coupling. Even without interfaces the components are still independent from each other and have great testability.

Other benefits I see are the exchangeability and the topological independence. Components are not bound to a specific topological context in form of interfaces and thus are independent from topological changes on the interfaces. You can exchange the components easily by replacing the binding section with any other setup phase and can binding other methods to them. Especially your components are not forced to use (or implement) some kind of interface from which they will perhaps use just one single functionality…

Last but not least I see a very easy way to intercept calls and adding functionality without changing the components themselves. If you use events as output pins you can add some more event handlers in the binding phase. Thus you can easily integrate Logging, Tracing etc. into your applications. Of course you can achieve this with IBCs as well, I just say that EBCs are suiting very well for those requirements.

Drawbacks

Besides those benefits in my opinion there are some significant drawbacks as well.

First of all is the additional complexity which comes with EBCs. Composing EBCs can become complex, at least in projects of significant size. Due to binding methods and events together on the fine instead of interfaces on the coarse, there have to be much more binding statements. In fact you can think of an event’s signature as a one-method interface that has to be fulfilled from components. Furthermore (again especially in projects of a reasonable size) you will loose intelligibility and  overview over your system and the component interaction. Any arbitrary component can provide a functionality and there is no way to navigate between layers and components as clients and suppliers of functionality. Explicit interfaces are much more comprehensive than such „implicit“ specifications.  Perhaps in the future there will be tools that simplify composition between EBCs and navigation through EBCs, but until there’s such a tool I consider this as serious drawback.

Another drawback of EBCs is the loss of interfaces as formal contract of coherent functionality. Of course you can define interfaces and let your components implement them, but while clients are not compelled to use them they loose much of their value. Interfaces force components to implement a certain set of functionality completely and make this set explicit. Clients have to refer this contract explicitly. Explicit contracts lead to intention revealing and this is a good thing!

Conclusion

So in my opinion EBCs have benefits as well as shortcomings. I think they are worth investigating and knowing them, but at the moment I don’t see that they will establish well and become a replacement for IBCs. First there is the higher complexity, which could perhaps be solved by tools and some sort of „DI container“ for EBCs in the future. But second, being explicit and define formal contracts through explicit interfaces is no bad thing. Of course it’s not cheap as well, but I don’t see that this justifies the application of EBCs on the small scale. On the big scale there are other solutions like BizTalk, NServiceBus etc. to achieve the goal of pluggable components which have features like scalability as well. So perhaps there are delimited scenarios for using EBCs (like component topologies that change often), but I would not suggest to use them in general.

kick it on DotNetKicks.com

5 Gedanken zu „Some thoughts on Event-Based Components“

  1. In fact, Ralf is currently working on a „DI container“ for EBCs: http://ebcbinder.codeplex.com/

    I totally agree to the lag of overview:
    We are using the image of electronic circuits, which includes the components (== classes), the output-pins (== events) and the input-pins (== methods). The solder would be the EBC binder.

    But we are still missing a circuit board! It would give us an overview of the connected (or faulty connected) pins. I’m thinking of a designer like the one for the Windows Workflow foundation… This could be the missed tool.

    I’m going to watch the progress of EBC. Let’s see if it can join the club of the standard design patterns.

  2. Thx, Matthias, for your review of EBC. I mostly concurr with your opinion. In a couple points I beg to differ, though:

    Interfaces as formal contracts are not missing from EBC. Right to the contrary! You can still define the offerings of an EBC component like your DataAccessComponent using an interface. And that´s even better than with IBC. Because in order to specify an IBC completely (like your BusinessClient) you´d need to list all exported interfaces as well as all imported interfaces. In your case that would be IBusinessClient + IDataAccessComponent.

    In the EBC world the specification of the BusinessClient component would be just IBusinessClient.

    I deem this an advantage over IBC. Specifications are more compact.

    You´re right in that the current bindings are a bit cumbersome. EBC surely would benefit from generating them from some DSL.

    However I find in my daily EBC practise that this drawback is only minimal compared to what is gained from EBC.

    a) EBC „require“ you to clearly separate domain functionality from code that just composes such functionality. It is a very helpful separation of concerns.

    b) The difficult to read binding code usually is not very long. Due to the ease with which you can design on different levels of abstractions (compared to IBC) EBC boards are kept quite small.
    In addition it is recommended to keep the design sketches with your code. They are a „poor mans DSL“ until there is a designer tool. If you do that look at them to understand your software, not the wiring code in the boards. It´s a common mistake to stay glued to the code instead of using diagrams. With UML I understand why people do that; diagrams and code quickly get out of sync because it´s hard to translate from diagram into code. But that´s different with EBC. The translation is trivial. Thus the code is in sync with the diagram. And changes should flow from the diagram/design to the code.

    So EBC fosters a less ad hoc, less cowboy programmer way of software development. Look at the cumbersome wiring code as a feature instead of a bug 😉 It´s a constant reminder to program in a clean way. Yes, that takes some getting used to it… but my experience is that´s worthwhile.

    c) Although the wiring code is kinda hard to read it in fact is simple. It´s so regular… Once you develop an eye for it, it´s not that hard to comprehend anymore. I deem this simplicity very important. It makes software more predictable in its form. And that helps evolving it.

    d) EBC very explicitly deal with dependencies. The only dependencies left are concentrated in board. And these board don´t have any domain functionality on them. So highly dependent code is simple. And complicated code is independent. That´s in accordance with all good principles of software development. Dependencies are the developers bane – penning them up in a few places thus is a great help.

    Finally one word about topological dependencies as I termed them: They make IBC dependent on how functionality is grouped. If component C needs functions f() and g() it´s dependent on them. Maybe that cannot be avoided. But why in all the world should C also be dependent on f() and g() being lumped together on an interface?

    As long as that´s the case C has two reasons to change (which is against the SRP): it needs to change if new domain requirements come up regarding its domain responsibility; and it needs to change if f() and g() are rearranged onto different interfaces for whatever reason. That´s bad.

    -Ralf

    PS: I suggest all interested in EBC to have a look at EBC 2.0. It´s a whole different view on how to carve out components from requirements. And the beauty of it: the nasty request/response communication simply goes away… 🙂

    PPS: Just for the record: I´m not advovating giving up IBC altogether! Even EBC rely on them for defining EBC boards. But also beyond that IBC are of value. Don´t try to throw them away. They can be of great use within EBC parts/actions (atomic EBC components).

  3. Hi Ralph,

    Thanks a lot for your detailed comment. I think it’s a good thing to dispute with both concepts (IBC and EBC) in a critical way. During the last weeks I got the feeling that people missed this important discussion and were hyping EBCs too much just because this style of programming is „different“ (but without questioning the backgrounds and impacts)…

    Back to your comment: it’s adding some new aspects that I didn’t see before. I’m not very certain about them, but I think it’s time to dig deeper into EBCs again 😉 I’m still an interface guy and like them as formal contract. In your comment you say when a component C calls f() and g(), an interface for f() and g() doesn’t make sense. I believe it makes sense when f() and g() belong to the same logical context and thus should be coupled into an interface. This explicitness IMHO improves readability and comprehensibility.

    I think EBCs could get big with tools. Tools for binding, tools for navigation, but most of all tools for visualizing EBC systems. With such tools we could start to see EBCs not on a class/method base, but on a bigger scale as component systems. And this would be a big deal! Are such tools on their way yet?

    ~ Matthias

    P.S.: EBC 2.0? Where can I find information/descriptions about that?

  4. Matthias,

    although this is a pretty old post in terms of the speed of „software development“ development, I ought to drop a few notes.

    First of all, I do agree that there is a „lack of common“. On a circuit board, you’d better agree on a certain Voltage, like 0..5 V+=. Something like a short-circuit brining the 230 V~ to the board would evaporize it. As long as the components (yes, components, back to the old days…) don’t protected themselves.

    What sexy thingy could possibly protect the components from being blown up this way? Well, you guessed it: a microkernel.

    At least in my opinion, Ralf’s idea becomes revolutionary when you drop your affiction to method signatures, and draw your attention to messages aka data carriers aka payloads.

    Opposite to electric circuits, where the only language spoken would be electric charge, expressed in Volts and Watts, events could, if we let them, throw around anything, even dynamics. Just add a [Serializable] attribute. Although I’d agree that the simpler the definition was, the better we’d walk away, we could still leave any verification to the receiving component, as long as we implement a good fuse.

    The most important thing that Ralf offered with the EBCs, at least in my humble opinion, is that there is no „response“. What in turn lets any x-tier architecture become deprecated. If you want to talk to me, throw a ball at my direction. If I want to talk to you, I’ll throw a ball at your direction. As simple as it sounds, as simple it is. No more hierarchies. Call it democracy at the level of data containers (aka SOAP messages, be it inProc or outProc, it doesn’t matter).

    As long as all parties involved speak the same language (repeat: as I said, that’s a microkernel’s job), you, as a coder, „just“ have to say goodbye to orchestration.

  5. Hi, Neat post. There’s a problem with your website in internet explorer, could test this?
    IE still is the market chief and a good portion of folks
    will leave out your magnificent writing due to this
    problem.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.