Previously when we talked about the evolution to a Monolith, we saw that after the actual coding is done, a waste of time exists. This time we’d be diving into the actual coding and the code growth, which is another evolution process of its own. We’d see it is another source of inefficiency that causes Velocity drops. We’d be doing this through deep diving into the most frequent and probably the most important event – change. How it is all bundled together through two more important events – the deployment and the revert.
Get ready for a rough ride as we’re about to entirely change our world’s point of view, from the world of actions to the world of events. To start and see our application’s life cycle as an event stream. Through it, we’ll be getting many insights to many more evolution processes.
The Event Stream
This won’t be our first event stream. We’ve actually seen our first when we discussed the Evolution to a Monolith, only shown as a state machine:
The events were the decisions of “no redesign” we’ve taken and the last event was us finally being frustrated enough to say “I can’t work like this any more”. We’ll see more event streams / state machines in this series. This time, we’d be taking our actual work on our application, and out of it we’d create it’s event stream.
First, we’d need to model our work. What we do as engineers is changing. Even when creating something new we’re changing it from a non-existing to an existing state. As such, a change to our application is an action done on it or to its immediate dependencies. E.g:
- Any alteration in code (git commit)
- Package update
- OS update on the running server
- Security/role change
- DB Schema change
- Many others…
As we do one change after the other, it would be easy to place them all on a timeline:
Change can be the smallest alteration, even as little as removing a commented code. Thus through an application’s lifetime there would be many changes, easily in the thousands and tens of thousands.
Change is not the only action we perform. We also Deploy, and an interesting relationship between the two exists. A change is left on paper, not taking effect until it is actually deployed. Let’s place the Deploy actions on the timeline as well.
From the timeline we can see what is deployed – an accumulation of changes. As the deployment couples them together it is a Bundle of changes. Furthermore, the deployment is agnostic to the contents of the Bundle, to what Changes we have made.
If we were to inspect the simplest deployment process, we’d see it. The entire code is compiled and put into a zip file (The Bundle). The zip file is copied into our server, unpacked and the server will be restarted. The process is entirely agnostic to what the code is and what changes were done to it.
If the process creates a Bundle and is agnostic to its content, we could unify all the Changes of the timeline. We can transform them all to a Change, without detailing which was it.
With that generalicity, we’ve modeled the actions done to our applications. Change and Deploy.
Changes don’t come out of nowhere. There are reasons that make us engineers do something, reasons that push us to actually do the action of Change. A cause. Each action has a predecessor, its cause.
We can easily come up with several causes for changes from our day-to-day work:
- A bug was found
- A product change was requested
- A new feature has been fully specified
- An old feature needs to be tweaked a little
- A new dependent package version was published
- Configuration change needed
- So many others…
Just like the action of Change has a cause, so does the action of Deploy:
- It’s 4pm
- The new feature is ready and must go live today
- A show stopping bug was fixed and must go live ASAP
- So many others…
We can put causes on the timeline as well. For simplicity, the only cause for deployment of our application would be “it’s 4pm – End of Day”.
Time to notice something funny with how we sometimes incorrectly treat time. Let’s review our analysis so far. We have first placed the actions, then placed the causes afterwards. We’ve literally said that “each action has a predecessor”. First there was the action, then there was the cause? It sounds like we are looking backwards on time.
If we were to have another look at the timeline with the forward moving time from left to right, we’d see it correctly. First there was the cause, then there was the action. “A cause has a successor” is more exact. It entails that every action is actually a reaction to cause. And a cause is always something that has already happened – an event. Which is why events should always be named in past tense.
Our timeline is currently a mixture of Events and Actions. There is one last thing to do in order to get our application’s first event stream. We’d need to transform the Actions to Events. An action has an interesting property. At the exact moment when it is fully fulfilled, it is done. Thus each action can be transformed to an event named “Action Done”. So the action of Change can be transformed to “Change Done” or Changed for short (Deploy -> deployed as well). That is the change event, the most frequent event an application has. With these transformations done, we can have one last look at our timeline, which is now an Event Stream.
If we deploy a Bundle, it is not only an accumulation of changes as actions. A Bundle is an accumulation of events and the Bundle is created at the moment of deployment.
Not that we know what a Bundle is, next we’d be talking about its consequences on deployments and reverts.