Journey to Event-Driven — Part 1: Why Event-First Thinking Changes Everything | Apache Kafka

Image by Jan Alexander from Pixabay

Overview

An opinionated history of “events” — Why do they matter?

It’s taken the last 25 years to get to the point where we consider the event as a core principle in system design. Throughout that period, much of the world was stuck thinking that remote object calling was the right way of doing things. REST and web services started by exposing the API as a concern, but that was done by a synchronous protocol.

A sequence of events captures a story. Replaying the events allows time-travel, to see that behavior again.

Adoption journey of the “event”

There are many paths to the inception of an event-driven architecture within an organization. For some, it is a natural pattern evolving from domain-driven design (DDD) principles, the related and powerful event-storming practice, decoupled systems design or just event-driven microservices. The point is they can come from any level, whether business or technical, but it will be a conscious adoption that doesn’t just happen by accident.

Considerations of the event-driven architecture

There are many considerations when evaluating the event-driven architecture. Events initially start out to as atomic and drive reactionary callbacks (functions). As a use case evolves, workflows develop and the criticality of the application generally increases along with the nature in which an event is considered. This raises numerous questions. Is ordering important? Do I want to ensure transactionality? How do I trust the execution? Security? Lineage? Where did the event come from?

  • Atomic: something happened (bid on an item, send an email, device temperature)
  • Related: a stream or sequence of events (tracking a pricing change, device metrics changes over time)
  • Behavioral: the accumulation of facts captures behavior

Transitioning to event-first thinking

  • Is it observable, and are the flows of streams behaving as expected?
  • Is it trusted, meaning transactional, exactly one or at least once? Will it scale?
  • Is stateless processing, such as filtering, projection, cleaning or enrichment required? Is stateful processing, such as aggregations or stateful sequence processing required?
  • Is a materialized view against the stream required? How many transactions per second are required for a windowed view?
  • Do we want to scale/fan/map out (parallelize), fan-in/collect and, build materialized views?
  • Does it support error handling, such as error flows and dead letter queue?
  • Does it send and transform events from one stream into others (stream processing)?
  • Does it react and drive intelligence from the state collected from a stream (stream processing)?
  • Data pipelines (ETL, integration)
  • Monitoring and alerting, including log collection and aggregation
  • Event-driven microservices
  • Enterprise wide event-driven microservices
  • IoT
  • Customer 360
  • Digital transformation
  • Real-time enterprise
  • Central nervous system/digital nervous system (using CloudEvents)
  • Capture facts
  • Capture behavior
  • Provide a representation of the real world
  • Model use cases of how we think
  • Supports repeated evaluation and processing (a time machine)
  • Provide horizontal scaling
  • Speak the same language as the business (ubiquitous language)

Event-first versus event-command patterns for event-driven design

You can build the same application using either the event-first or event-command approach, but the event-first approach is generally recommended. If we rewind onto familiar ground for an example, we see that traditional REST applications are an event → command pattern. They are coupled in multiple ways: Firstly, the endpoint is known (i.e., the service address). Secondly, the method being called is also known (i.e., an API call to doStuff), and lastly, the calls tended to return a value; they are synchronous. Newer frameworks will allow this call to be handled synchronously or asynchronously — it is called the event-command pattern.

The Purchase processor knows what to call and in which sequence; high coupling makes architectural evolution difficult

Event-first pattern

With the event-first approach, each service listens for inbound events and outputs zero or more events after performing some (re)action. For example:

Everything emits its event; easy to replace with new processors and support change
Events provide low-coupling; adding new functionality is done without shutting the system down. Functionality can be enabled using feature flags

The cost of the event-first approach

The tradeoff of event-first/event-driven architecture is the amount of scaffolding required to inspire confidence. In the old days when transactional consistency shaped our expectations, and NoSQL pushed us to eventual consistency with CAP theorem tradeoffs, it was known that data wouldn’t (and shouldn’t) get lost. Event orientation requires not only different thinking in replacing the command model but also the ability to support traceability, failure paths, scaling and explanation about why things have gone wrong. These challenges are easily solvable and are also quite fun; I will revisit this topic later on.

Benefits of the event-first approach

The pure event-first approach described above demonstrates:

  • Decoupling: Processors don’t know anything about upstream or downstream processors
  • Encapsulation: There are clean boundaries between processors.
  • Inverted knowledge: Knowledge and responsibility are reversed.
  • Evolutionary change: The system and events can change over time.
  • Event sourcing: When using a log and log-aware stream processors, we gain the ability to potentially rebuild and restore application state. It’s not a free lunch; the application state needs to be captured and managed. We don’t want to have to re-build event derived state by replaying events from the beginning of time.

Orchestration versus Choreography

I will touch on this topic briefly, but it is due much more space than I have allowed. The event-first architecture is described as Choreography. Events don't know who will consume them, they just exist; there is no master controller. This principle instills evolution, supports feature flags at runtime where new functionality is enabled without taking the application down (flags are used to determine where events are consumed). Orchestration is a workflow, the relationship between events is owned by a third party. The third-party is responsible for routing, filtering, but also failure and recovery scenarios. If a processor fails to handle an event, it knows to undo-previous states on upstream processors. With Choreography, you need to use a sensible approach to recovery (Martin Kleppman explains it nicely in his excellent book). Using the Saga pattern to handle failures offers an understood approach. There will be situations that Orchestration is preferred over Choreography and vice-versa; they are not mutually exclusive, yet instead, will co-exist in the large event-driven organization. Choreography is ideal for connecting the organization together at scale, hierarchical topic naming keeps topic organized and allows governance models to be put in place.

Finally…

I have reasoned about how event-first thinking represents a new opportunity, a new frontier for technology and businesses to go back to first principles of system architecture and design. Changing the underlying foundations of how we conceive technology naturally shapes how we approach business problems, and therefore how we develop technology.

Interested in more?

If you are based in London and want to meet for a coffee or deep-dive into your solution architecture — give me a shout at my new home: liquidlabs.com

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Neil Avery

Neil Avery

@Liquidlabs, ex Confluent, CTO-Excelian, Thoughtworks. Founder Logscape, Startups, code-monkey, songwriter tennis-nut, snowboarding-nut, and Dad!