Great talk! The analogy between imperative / functional and request response / event-driven architectures really makes it easier to understand the use of a distributed log system.
the "concurrency control" issue (at 30:50) is going to be a tricky problem. if you want to have some consistent (in terms of what the user sees) view, you will need something like a statemachine, which have the side-effect of making you think of all the use-cases before you do it. also, great talk! this is fantastic.
I don't think an strong association between imperative vs functional necessarily maps to request/response vs event-driven is supported. The latter consideration maps more to the concurrency model being considered than the style of function/procedure modeling. It is not true that event-driven is fire & forget. Use cases where the event source needs to make a decision based on the result of a function executed as a result of the event are quite common - so system architectural style is orthogonal to style of function abstractions. True, a functional model tends to help make things more composable and state vs. stateless circumstances more explicit but one style vs another is not a pre-requisite or even an indicator as to what concurrency model you've adopted. Indeed ultimately decentralized systems must deal with unbounded non-determinism which is actually not something easily modeled via lambda calculus which pretty much all functional style languages are based on. Go's CSP gets most of its concurrency challenges due to its attempts to map lambda calculus to non-deterministic conditions by pretending they really aren't. Channels like global event logs ultimately hit scaling limits and add random unpredictable latencies in what could be critical call paths unnecessarily delaying responses and exposing otherwise locally modeled services to impact from logically unrelated loads. I would compare this to Erlang's actor model which truly models unbounded non-determinism and orchestration of independent simple actors (represented in a functional-like but still somewhat imperative sequential code style) that allow optimized emergent behavior that can naturally prioritize results and manage non-functional qualities like capacity and latency. The ultimate microservice, to me, seems to be the individual actor. Rips away a lot of unnecessary complexity.
This is kind of like the actor model, the actor mailbox is the distributed log, just that the mailbox and the actor instance are going to be running on separate application instances
It is just moving around complexity within the distributed system, but not removing it nor the challenges associated with it. And the biggest talking point I hate in these discussions about distributed micro service architectures is that you can have stand alone teams do whatever they want in silos without having any understanding of the larger system they are working on. That makes no sense and will often lead to problems and fail to achieve the kinds of efficiency that is desired. You have to look at the big picture and understand the trade offs at every level before making key design decisions about individual applications. And the other contradiction is that a distributed system has to be a monolith. That is totally incorrect. A distributed system can and should be heterogenous made up of different patterns and frameworks that are loosely coupled at the integration layer but at the transactional/local level tightly coupled depending on domain.
When implementing a microservice in Akka, I like to think of every actor as its own microservice which happens to be running in the same OS process as other microservices (which has the benefit of not having to serialize every message). When working with a sufficiently strong type system (e.g. Scala) the compiler allows for guarantees that get thrown away when one introduces a network boundary; this means that I would advise building a more monolithic system for a given bounded context for as long as one possibly can. The relative ease of clustering a service which is implemented using the actor model means that you can scale something more monolithic and delay having to split it into microservices until team dynamics make independent microservices worth the trouble. At that point, since you've been designing the components around asynchronous message passing, it's fairly easy to separate actors into new services.
Thanks Benjamin, you saved me a lot of keystrokes. I couldn't express my doubts in a better way! It may sound harsh but for me this talk was a bit too focused on buzz words. It's not that it's bad but title is setting high expectations and the whole talk didnt deliver well on it. For me the biggest issue with "event" model is how hard it is to make it done properly and keep it that way. For many people "events" and "messages" mean something completely different. Simple request/response is making things just plain and simple especially if you enforce fault-tolerant design.
Often in hardware, writes are easier than reads for the same reason, one doesn’t need to return data. Doesn’t mean one can build write only systems! Authentication and authorization often have in process synchronous requirements. Many domains do. Therefore this is not an either or thing. Many writes can use event logs with materialized views for state. They are then eventually consistent. But one still ends up needing some amount of synchronous access to immediately available data. When these two are mixed however the issue because if the view is up to date arises. This is addressed somewhat at the end. But the first part looks like a black and white view of technology. Black and white doesn’t assist the construction of systems, but confuses technology with philosophy, leaving the designer with either a screwdriver or a hammer. They need both.
Wonderful talk. I’m a believer - I’ve always wanted to implement a fully event log driven architecture, but every time I try I just realise the developer tooling isn’t there. It’s just too damn complicated to develop with. I’m excited for a future where we can replay & debug events with ease, but we’re not there yet. I’ve seen a few startups in the space (there was one in Y Combinator last cohort), but again, it’s just not there enough for me to switch what everyone knows best over to this paradigm. PS this doesn’t apply to change data capture, which is already exceptionally useful and everyone should be using for search and analytics!
An in-proc function call is /not/ within our control. There are multiple opportunities for failures. Full HD, device driver crashes, radiation corrupting memory, bugs in external libraries, bugs in the CPU, etc. Introducing network does add a failure point, but it doesn't add complexity. In-proc state mutations have the all the same concerns as out-of-proc. Anytime you mutate data with a series of function calls the mutation set is not atomic. You have to use patterns, such as ARIES, to ensure both durability and integrity of system state. Concurrency obviously adds more complexity. These concerns aren't unique to network-separated distributed systems.
It seems like much of this presentation is about the benefits of having a distributed log of messages between micro-services. Fair enough, but couldn't you implement such a log in a strictly synchronous request/response environment by routing all of the requests and responses through a single proxy, much like how in this event driven scenario all events are being routed through a single queue? As the presenter details there are many uses for an activity log, but I don't think it is necessary to use an event-driven model to get one.
Great talk, Melinda. Loved the illustrations and the clear analogies from functional/imperative to sync/async.
Great talk! The analogy between imperative / functional and request response / event-driven architectures really makes it easier to understand the use of a distributed log system.
the "concurrency control" issue (at 30:50) is going to be a tricky problem. if you want to have some consistent (in terms of what the user sees) view, you will need something like a statemachine, which have the side-effect of making you think of all the use-cases before you do it.
also, great talk! this is fantastic.
I don't think an strong association between imperative vs functional necessarily maps to request/response vs event-driven is supported. The latter consideration maps more to the concurrency model being considered than the style of function/procedure modeling. It is not true that event-driven is fire & forget. Use cases where the event source needs to make a decision based on the result of a function executed as a result of the event are quite common - so system architectural style is orthogonal to style of function abstractions. True, a functional model tends to help make things more composable and state vs. stateless circumstances more explicit but one style vs another is not a pre-requisite or even an indicator as to what concurrency model you've adopted. Indeed ultimately decentralized systems must deal with unbounded non-determinism which is actually not something easily modeled via lambda calculus which pretty much all functional style languages are based on. Go's CSP gets most of its concurrency challenges due to its attempts to map lambda calculus to non-deterministic conditions by pretending they really aren't. Channels like global event logs ultimately hit scaling limits and add random unpredictable latencies in what could be critical call paths unnecessarily delaying responses and exposing otherwise locally modeled services to impact from logically unrelated loads. I would compare this to Erlang's actor model which truly models unbounded non-determinism and orchestration of independent simple actors (represented in a functional-like but still somewhat imperative sequential code style) that allow optimized emergent behavior that can naturally prioritize results and manage non-functional qualities like capacity and latency. The ultimate microservice, to me, seems to be the individual actor. Rips away a lot of unnecessary complexity.
This is kind of like the actor model, the actor mailbox is the distributed log, just that the mailbox and the actor instance are going to be running on separate application instances
It is just moving around complexity within the distributed system, but not removing it nor the challenges associated with it. And the biggest talking point I hate in these discussions about distributed micro service architectures is that you can have stand alone teams do whatever they want in silos without having any understanding of the larger system they are working on. That makes no sense and will often lead to problems and fail to achieve the kinds of efficiency that is desired. You have to look at the big picture and understand the trade offs at every level before making key design decisions about individual applications. And the other contradiction is that a distributed system has to be a monolith. That is totally incorrect. A distributed system can and should be heterogenous made up of different patterns and frameworks that are loosely coupled at the integration layer but at the transactional/local level tightly coupled depending on domain.
When implementing a microservice in Akka, I like to think of every actor as its own microservice which happens to be running in the same OS process as other microservices (which has the benefit of not having to serialize every message).
When working with a sufficiently strong type system (e.g. Scala) the compiler allows for guarantees that get thrown away when one introduces a network boundary; this means that I would advise building a more monolithic system for a given bounded context for as long as one possibly can. The relative ease of clustering a service which is implemented using the actor model means that you can scale something more monolithic and delay having to split it into microservices until team dynamics make independent microservices worth the trouble. At that point, since you've been designing the components around asynchronous message passing, it's fairly easy to separate actors into new services.
Thanks Benjamin, you saved me a lot of keystrokes. I couldn't express my doubts in a better way! It may sound harsh but for me this talk was a bit too focused on buzz words. It's not that it's bad but title is setting high expectations and the whole talk didnt deliver well on it.
For me the biggest issue with "event" model is how hard it is to make it done properly and keep it that way. For many people "events" and "messages" mean something completely different. Simple request/response is making things just plain and simple especially if you enforce fault-tolerant design.
I was surprised to see pt. 9 stated as question, as I've been doing that for years, using either WebSockets or the EventSource API.
what was point 9? can you tag the time pls?
@ 27:55
Surprised that GDPR/CCPA were brought up, without any mention of the impossibility of deleting from an immutable log...
Kafka supports limited retention.
Often in hardware, writes are easier than reads for the same reason, one doesn’t need to return data. Doesn’t mean one can build write only systems! Authentication and authorization often have in process synchronous requirements. Many domains do. Therefore this is not an either or thing. Many writes can use event logs with materialized views for state. They are then eventually consistent. But one still ends up needing some amount of synchronous access to immediately available data. When these two are mixed however the issue because if the view is up to date arises. This is addressed somewhat at the end. But the first part looks like a black and white view of technology. Black and white doesn’t assist the construction of systems, but confuses technology with philosophy, leaving the designer with either a screwdriver or a hammer. They need both.
An excellent talk.
Wonderful talk. I’m a believer - I’ve always wanted to implement a fully event log driven architecture, but every time I try I just realise the developer tooling isn’t there. It’s just too damn complicated to develop with. I’m excited for a future where we can replay & debug events with ease, but we’re not there yet.
I’ve seen a few startups in the space (there was one in Y Combinator last cohort), but again, it’s just not there enough for me to switch what everyone knows best over to this paradigm.
PS this doesn’t apply to change data capture, which is already exceptionally useful and everyone should be using for search and analytics!
Do you recall the name of the YC startup that's in this space?
Jose Valim has his task cut out then.
Please reach out to him may be he knows what can be done.
Very great talk 👍🏿
It truly help to popularize Event Driven Systems & Reactive Systems 👏🏿
An in-proc function call is /not/ within our control. There are multiple opportunities for failures. Full HD, device driver crashes, radiation corrupting memory, bugs in external libraries, bugs in the CPU, etc. Introducing network does add a failure point, but it doesn't add complexity. In-proc state mutations have the all the same concerns as out-of-proc. Anytime you mutate data with a series of function calls the mutation set is not atomic. You have to use patterns, such as ARIES, to ensure both durability and integrity of system state. Concurrency obviously adds more complexity. These concerns aren't unique to network-separated distributed systems.
It seems like much of this presentation is about the benefits of having a distributed log of messages between micro-services. Fair enough, but couldn't you implement such a log in a strictly synchronous request/response environment by routing all of the requests and responses through a single proxy, much like how in this event driven scenario all events are being routed through a single queue? As the presenter details there are many uses for an activity log, but I don't think it is necessary to use an event-driven model to get one.
I believe that Kafka is exactly your single proxy.