Front-end web architecture has made exciting advances in recent years. But before we get to that we need to have a discussion on what has led us to this point and the driving principles behind it.
In this video, you will learn about coupling, and see how decoupling has driven developments in front-end architecture. And, you will gain an understanding of the parallels between front-end architecture and cloud architecture.
Instructor: [0:00] Hello, friends. We are going to talk about serverless in the context of moving from a plain JavaScript function to a fully deployed endpoint. This shift has some relatively profound implications in terms of what we can accomplish as front-end developers.
[0:15] One welcome discovery that we'll examine is the distance between a function and an endpoint, which, perhaps surprisingly, is not nearly as far as one might imagine. After 20 years of programming and cycling through my fair share of technologies, I believe a learning approach that's focused on first principles will produce the greatest return on time when investing in new skill acquisition.
[0:40] Before we get to the shiny stuff, I want to lead with a quote from Neal Ford. "Architecture is the tension between coupling and cohesion." I don't have hard data on this, but I suspect that 85 percent of the problematic code that I see in the wild is a result of improper coupling, a problem which could easily be solved through better abstractions.
[1:02] Coupling is such a deceptively simple principle that a lot of engineers, to their own detriment, have a superficial understanding of it. In my experience, there are a lot of senior engineers who understand the hottest framework of the month, to the point that they want to argue obscure philosophical nuances about it.
[1:20] The same senior engineers will turn around and violate the single responsibility principle with nested logic and hidden state and wonder why they can't test their code or why their code doesn't scale. This is why.
[1:32] If you're going to talk about state management, NgRx, Redux, observables, facades, etc., you absolutely must have more than a cursory understanding of coupling. By extension, we can't even evaluate a technology as a good solution for our organization without also considering the cost that coupling and cohesion will incur.
[1:54] Vendor lock-in is just another way of saying tightly coupled, which is usually just another way of saying hostage situation. Do you really want to couple the future of your career and your organization's livelihood to a single ecosystem?
[2:10] On the other hand, when your technology is architected on clear layers with clean abstractions, you can swap out one technology for another without toppling the entire thing. To drive this point home, how many Flash developers you know that are thrilled they bet their future on that platform?
[2:28] This is a perfect segue into a brief history of web apps, which also happens to be a great study on the evolution of decoupling. If you've ever had to build a "jQuery application," then you know how tightly coupled the DOM was to the logic that controlled it. The DOM was the single source of truth, and you had to parse it before executing any kind of business logic.
[2:55] Fortunately, there was a wave of first-generation modern web frameworks, like AngularJS, that separated the DOM from the logic and the state that defined it. You simply had to update the underlying data model, and the template would render. The controller was the single source of truth, until that fell apart.
[3:18] When you needed to share state between two controllers -- enter more decoupling from stage left -- common logic was abstracted to a service, which was fine until it wasn't because a typical stateful service was responsible for not only managing and storing state but also communicating with the remote server.
[3:40] It was like multiple businesses being run under the same roof. State-Stored Solutions LLC, Business Logic Experts Incorporated, and Expert Event Couriers were all splitting rent, and nobody liked it.
[3:54] Thankfully, this monopoly was broken up because the newly formed Redux and Co. allowed us to separate our business logic, async operations and state storage into separate and distinct places. Redux encouraged us and, if we're being honest, forced some of us to reorganize into functional, cohesive units that were responsible for a single function within our application.
[4:17] What was most interesting about this new way of organizing our applications was that it not only profoundly simplified things conceptually, but it also presented some incredible opportunities that were not immediately obvious.
[4:30] By completely separating your component layer from the rest of your application and then applying a command-and-query approach for communication, suddenly, we introduce time and space into our applications that did not exist before.
[4:45] In a traditional event-based application, an event handler is triggered, which immediately calls a function that responds to the event. This is a nearly instantaneous and synchronous execution.
[4:58] On the other hand, if an event is converted into an action object that is dispatched, the response to that event is not as obvious and not guaranteed to happen immediately. In fact, you could replicate the action object that represented a user event and sideload it into your application, essentially replaying the event.
[5:20] Imagine an entire user flow, which is nothing more than a series of events that are translated as a collection of corresponding objects.
[5:30] What if you could recreate the entire array of events and then side load them in one at a time. Not only have you created distance from the point of human intervention, but you can also play those events back in whatever frequency you like, which allows you to manipulate time.
[5:48] Taking this a step further, what if you could store a valid action in a remote data store, and then dynamically load and dispatch it? Or load an entire collection of objects from a remote data source and play them back sequentially.
[6:06] Notice how this is possible because we have decoupled the event producer from the event consumer. Let's take this yet another step further. What if the remote data source was real time?
[6:24] What would that mean if you had multiple connected clients that were consuming the same real-time distributed data source? By taking a moment to ponder first principles, specifically coupling, suddenly we are on a fairly short path to something really compelling.
[6:43] I don't think it gets any more enterprise than real-time distributed applications. I've planted a small seed, it's time for the big idea.
[6:54] It took me all of 20 years to come full circle and realize that all of the velocity that I was able to achieve as an engineer was because somehow, some way, I had developed a deep and intimate understanding of the most basic principles that I had learned in my first year of programming.
[7:13] That's when it hit me. If we want to learn new things, we should strive to understand what we already know. I'm going to assume that if you're here, you understand how to write functions.
[7:27] As a result, I believe that on some level, you know how to create API endpoints using the exact same skillset. Let me make the case. Here is a basic function. We give it an input and we get an output.
[7:40] Because we understand this, we know how NgRx effects and most middleware works. We have an effect that is called via a trigger event and emits a completion event. You may know where I'm going with this, a Serverless Function. Request in, response out, and let's keep going.
[8:02] Because we understand how one effect works, we know how to sequence them together by using a completion event from one effect to serve as the trigger event to another until you are all the way down the chain. Prepare yourself. You know how step functions work.
[8:20] Functions that are sequenced together where the output of one function becomes the input of another function. This brings me to my final point. Because we understand frontend architecture principles, we already know Cloud architecture principles.
[8:38] Just as we saw the evolution of imperative logic from being coupled to a component, then to a service, then to a layer. Ultimately, into a distributed layer. We can see a similar evolution with JavaScript functions as we reduce its coupling to the environment it lives in.
[8:58] A function in a vacuum is entirely dependent on the local development environment. The same could be said when you put it inside a framework like React or Angular. You decouple that function by putting it on a server.
[9:11] It's still dependent on your ability to manage the environment as it is probably unmanaged i.e. EC2. The Holy Grail is when you can just put your function into a fully managed environment.
[9:25] It's decoupled from all of the thorny design considerations that we had to think about up until the last couple of years. Ultimately, my goal in this course is to impress upon you a new way to think about what you are capable of accomplishing.
[9:40] I hope to help you realize just how decoupled you now are from the constraints that in the past have made it really hard for you to build great applications at scale. There's only one place for us to go, and that is forward.