Skip to content
Simon J Stuart edited this page Sep 4, 2022 · 4 revisions

Welcome to the EventDrivenSwift wiki!

The purpose of this Wiki is to provide you with a central location to learn about every aspect of EventDrivenSwift, particularly in respect of integrating this library into your Swift projects.

What is Event Driven Development?

Event-Driven Development is a modern expansion of the traditional Observer Pattern.

Where Event-Driven Development differs is that, instead of the Observer having to directly register itself with the Observable; in an Event-Driven System, the Observer does not need to be contextually aware of the Observable at all.

Instead, individual Components of your system can - whenever they need to - Listen for and Dispatch Events, which are nothing more than a Payload of Information with a Defined Type.

In this way, what would have been considered an Observer is now entirely Decoupled from what would have been considered the Observable.

Even better, the Observer does not need to care about where an Event is coming from. In this way, multiple Components within your system can produce and Dispatch Events, and the Observer can treat them all equally.

Traditional Observer Pattern

Traditional Observer Pattern necessitates direct awareness of an Observable from an Observer, which looks like this: Diagram of Traditional Observer Pattern In the above diagram, you can see that each View Model is tightly-coupled to the Data Model Repository.

While we can use Interfaces to provide some degree of decoupling by abstracting our references via the Interface, meaning that any Concrete Implementation of that Interface will work interchangeably for each of the View Models, there are still a number of significant disadvantages to the Traditional Observer Pattern:

  • Each Observer (the View Models in the above example) presumes that all Data Models will originate from a singular location. In many scenarios, this would not be the case.
  • Every time the Observable changes in any way, or for any reason, all Observers (View Models in the above example) would be invalidated (a state which necessitates an update), thus the associated Views would be invalidated also. This represents a considerable inefficiency, as it is more often not necessary to update an entire View in response to any change. Traditional Observer Pattern doesn't particularly cater to optimised performance.

Interface-Backed (Protocol-Backed) Observer Pattern

An enhancement over Traditional Observer Pattern is a concept known as Interfaced-Backed Observer Pattern. In the Swift programming language, we would call this Protocol-Backed Observer Pattern.

This is where an Observer conforms to one (or more) Interfaces (Protocols in Swift) that the Observable has been programmed to invoke in response to specific operations. Diagram of Protocol-Backed Observer Pattern While the above Diagram may look a little bit complicated at first glance, if you follow each line carefully, you will see that it simply illustrates how each of the three key Operations in the Observable (Data Model Repository) will iterate through all Subscribed Observers and invoke the appropriate method for all Observers conforming to the Protocol applicable to that Operation.

  • MyModelListViewModel implements both DataModelRepositoryAdded and DataModelRepositoryDeleted, so will be notified every time a Data Model is Added or Removed, thus invalidating MyModelListView and displaying immediately the results of these changes. However, it will not be notified when a Data Model is Updated (i.e. Modified).
  • MyModelDetailViewModel implements only DataModelRepositoryUpdated, and so will only be notified every time a Data Model is Updated (i.e. Modified), but not when Models are Added or Removed.

As you can see, this approach - which is provided by our own Observable Library for Swift - affords a number of advantages over the Traditional Observer Pattern, in that Observers can be infinitely-selective of which Observable operations are relevant to the Observer.

However, the following disadvantage still applies:

  • Each Observer (the View Models in the above example) presumes that all Data Models will originate from a singular location. In many scenarios, this would not be the case.

While it is possible for a single Observer to subscribe to multiple Observables, this would simply increase the number of Tight Couplings you need to maintain in your codebase.

So, how do we eliminate these couplings completely?

Event-Driven Observer Pattern

Event-Driven Observer Pattern is the next evolution, expanding upon Protocol-Backed Observer Pattern, only dispensing with the need for the Observer to know anything at all about one or more Observables.

In Event-Driven Observer Pattern, the Events themselves constitute the Observable, meaning that it doesn't matter where an Event originates from, literally any Object anywhere in your code can Listen for any number of Event Types, and operate upon the Event Payload in the Context applicable to that Observer (Listener, when we're talking about Event-Driven systems) Diagram of Event-Driven Observer Pattern

As you can see in the above Diagram, there is no longer any coupling between the View Models and the Data Model Repository. Indeed, the View Models do not even need to be aware of the existence of the Data Model Repository. They will simply receive the applicable Events whenever an operation takes place, and act upon it.

There are no Silver Bullets!

Always remember that software design and development are about determining and applying the best pattern, practice, and approach for each individual problem. There is no such thing as a one-size fits all solution in software, so it is essential that you determine - as part of your planning stage - which pattern/practice/approach (or combination thereof) best resolves each given requirement within your system.

Event-Driven Observer Pattern is an extremely powerful way of abstracting discrete Components of your system, while retaining total Interoperability.

Clone this wiki locally