Check out a free preview of the full Enterprise Architecture Patterns course:
The "Simulating User Actions" Lesson is part of the full, Enterprise Architecture Patterns course featured in this preview video. Here's what you'd learn in this lesson:

Lukas discusses how user interactions can be simulated by manually dispatching actions. A properly decoupled system is not dependent on what triggers an action. It subscribes to a stream and waits for an action to be emitted.

Get Unlimited Access Now

Transcript from the "Simulating User Actions" Lesson

[00:00:00]
>> In our last and final module, we're going to talk about distributed complexity. So the entire theme of this entire workshop has been managing complexity. Because I think the great enemy of good high quality software, enterprise applications is complexity. And so we've started at a micro level. And we've talked about the axis of evil.

[00:00:26] Then we moved on to what I would say a mezzo level, which is feature complexity. And then we talked about it, it kind of a macro level. Which is really this time domain that exists as we deal with asynchronous programming and how we can use observables to help manage flow control in our application.

[00:00:48] And so, in this last module I want to talk about distributed complexity and how, by applying these techniques, especially with proper state management and flow control, that we can do some really interesting things by manipulating time and space. So I want to take a moment and just walk through the natural progression of web applications as we know it.

[00:01:18] So, I would say it the first advent of JavaScript as we know it, the first phase of greatness. The first dynasty of greatness was really, when jQuery showed up that kind of before that it was just too cumbersome to really work with JavaScript because of the browser and consistencies.

[00:01:40] The challenge with that was when you're building a jQuery application air quotes is that your user interaction and the he logic that handled them were incredibly tightly-coupled is that the interactions knew about the logic and the logic knew about the interaction. And they were very much intertwined that you were mixing declarative markup with imperative logic.

[00:02:14] Now when angular JS, the original angularJS came on the scene. One of the big things that it offered was the ability to separate the imperative logic and your declarative markup. And so now you have a little bit of separation between the user interaction and the logic that handled it.

[00:02:40] And so this went very, very well. This was kind of a new thing, and it was very, very popular. The problem is, is that as your application started to grow in size, is that now you had two controllers that needed the same thing. And so how did you solve that?

[00:02:59] Well, with a service. And so notice now we're taking this shared logic and we're just extracting it out further and further. And so now we have a Dom of Multiple HTML elements in the DOM that are sharing controllers that are now sharing logic within a service. Now, here's the challenge with this, is that a typical stateful service is responsible for not only fetching remote data but also managing the state of that data.

[00:03:37] And this always bothered me because I felt like I was staring at a stateful service and it's like this is doing it a minimum, two things, two very distinct things. And thankfully for us Redux shows up. And what this allowed us to do is in its simplest form, is to separate the state management portion in to or the logic that handled that into reducers and then the actual state itself into the store.

[00:04:11] And then it also provided a mechanism for managing that asynchronous part in the term in the form of effects, but what we're seeing here is we're starting to move this complexity further and further away from our component layer. And so here's a quote that I like quite a bit and It was quite, I think serendipitous that I was reading this as I was thinking about programming and very quickly, it says in classical physics, if you know everything about a system at some instant of time, and you also know the equations that govern how the system changes then you can predict the future.

[00:04:57] That's what we mean when we say that the classical laws of physics are deterministic. If we can say the same thing, but with the past and the future reversed, then the same equations will tell you everything about the past. Such a system is called reversible. And I realized as I'm reading his theoretical minimum by Leonard Susskind that this is everything that I would want out of an application.

[00:05:26] And so I'm just sitting there thinking like, what did I just read? And so let's break this down because in some ways Leonard is talking about classical physics. And for me, he's talking about everything that should exist in a well architected system. In classical physics, and a well architected application, if you know everything about a system at some instant of time, well guess what we do?

[00:05:56] It's the store. It's your single state tree. You can know everything about a system and application at any given time because it's in the store. And you also know the equations that govern how the system changes. Well, guess what we do, they're reducers. Then you can predict the future.

[00:06:21] That's what we mean when we say the classical laws of physics are deterministic, and we can say the same thing with the future and past reversed, such a system is called reversible. And so with proper state management in a Redux pattern that we can accomplish all of this.

[00:06:40] And what this allows us to do is some very, very interesting things with the user input and how we respond to it. So typically, in a very naive system is that you have a user interaction and then very quickly almost immediately, you have a response to that. But through proper state management and proper flow control, we're able to create time and space between the user interaction and how we respond to it.

[00:07:17] So how do we do that? With actions, is that we can communicate that something has happened via an action. And so now you have a user response or an interaction and then the response and then this action has to communicate this and travel some distance. And we can play around with that.

[00:07:40] So now what we can do is we can create a user interaction then or user event dispatch the action, and then it has to travel some amount of space and then arrive at some other place to be processed. Then what we can also do is if we can express user interactions or events through actions, then we can take those and recreate those at any given time.

[00:08:15] So this is what I mean by time and space. And from here by using time and space and through the proper handling of the logic and the state that this presents opportunities to do to not only separate it but manage the state in ways that we could not previously do.

[00:08:40] But create or recreate interactions that historically have happened immediately to where we can recreate those actions. Or we can automate actions or we can isolate certain actions and control them in a very specific way. So let's start with manual dispatch, let me show you a space example. So in a standard application, let me just go over to the browser here, and I'm going to just close the sidebar down.

[00:09:17] What I have here is I'm clicking this user, so John J. And you can see as I click it, that on the left hand side, my form is updating. And so how this is working quite simply is that I'm capturing that user event and I'm dispatching an action.

[00:09:43] To say, hey, this is the new selected client. So remember the exercise we did around the four elements. This should be somewhat familiar that we have a state object with the selected client or a current client and we're simply setting that. Now, back to the slides. What would happen if we could capture that action that is being generated off of that click, and we were able to dispatch it from the side we could effectively simulate that user action because we're converting that user interaction into an action.

[00:10:27] And so we can then side or dispatch it from the side and recreate that same exact user interaction. So what does this look like? In our code here, what I've done is I've created a set of or recreated a set of actions. Because remember, an action is nothing more than a simple object with a type and a payload.

[00:10:56] And what I can do is, and I'll just refresh this is that I can take these actions and instead of clicking over here I note that if I'm going to click on this John DOE element, that I'm going to dispatch an action, well, I can just go here, and I can preemptively create that action.

[00:11:19] And so notice now that I am essentially manipulating the form on the right by manually dispatching actions on the left, so this is what I mean by creating space. So, put your thinking caps on and just start to think why or how this may be useful. Now, if we can capture and simulate a single user interaction.

[00:11:50] What happens if we take, and we put a bunch of them together, and we manually cycle through a number of actions. So if we can simulate one action, why not a group of actions? And so we can do this via manual cycle. So imagine now instead of one, we're going to dispatch a number of actions and just iterate over them.

[00:12:18] And so now we can increase our kind of sophistication in terms of space. So the difference is we have our actions, and then I'm going to cycle over them in some interval. So I'll hop back in the code. And now let's go to the manual cycle. Now I'm gonna refresh this just so we can start clean.

[00:12:41] And I'm going to go to the manual cycle. And all I'm going to do is instead of one by one dispatching these actions, I'm going to just iterate over them. And so now you'll see that on the right hand side, I'll do this one more time. It is essentially simulating if I were on manually on the right hand side and just clicking back and forth between those clients.

[00:13:13] Now, we've already manipulated space because I'm manipulating this thing over here from here, but I can actually change the cadence in which, or the speed in which I'm iterating over those actions. So, let's go like one and a half seconds. Notice now if I click this, like this is happening actually very fast.

[00:13:39] So let me refresh this. And let me just move this up to like one second. Here we go. And so now it's moving even faster. So it was a half a second. It was a second. And we're able to actually change the cadence in which we are now simulating this user interaction.