Transcript from the "Complexity and Purgatory" Lesson
>> Lukas Ruebbelke: Complexity leads to purgatory, any seasoned developers in the room, or even not. I think it took all of two hours or less of me trying to program before I found myself in this state of, what is going on, like doesn't feel good. So have you ever been programming on something and you just hated your life?
>> Speaker 2: [LAUGH]
>> Lukas Ruebbelke: You're just like, I wanna quit and go deliver pizzas, like this is not fun.
>> Lukas Ruebbelke: The majority of the time it's because of complexity. And so to be clear, sometimes even just ambiguity leads to complexity. Things appear, where you're processing things and the perspective is that it's very complex because it's ambiguous, like, what's happening.
[00:00:46] But complexity leads to purgatory, so let's see a couple examples here, and just to illustrate my point. I'm not trying to scare you, but imagine if I can kind of kind of drive these points home in a few slides. Now, imagine doing this at an enterprise app level.
>> Lukas Ruebbelke: So, let's take this code here.
>> Lukas Ruebbelke: We are calling a method inbound, over here, taking an item, we're doing some kind of processing, and we're then returning a total. So, an item comes in, based on this value here, currentCategory. Determines what logic gets processed, and then you return a total based on that.
[00:01:37] So this is kind of some quasi code, but the question is, when you call this, what are you going to get?
>> Lukas Ruebbelke: Well, the answer is you don't know. Like you cannot say for certain, in itself, in a vacuum, when you call this what you are going to get.
[00:02:02] The reason being, is because this method has hidden state. So I could call this 10000 times and get a different result every single time. The reason being, is that if I'm changing current category I'm changing the internal workings of this method. And now, in order for me to reliably assert that this method is going to return this thing or there's going to be this outcome, I also have to control this hidden internal state, in this case, it's currentCategory.
[00:02:44] And so now we're thinking, in order for me to wrap my mind around this method, I also have to add in this additional piece into my Cogno processing. As human beings are not very good at this, so for instance,
>> Lukas Ruebbelke: Let's say we have three dice.
>> Lukas Ruebbelke: How many possible combinations can we have with three dice?
[00:03:13] So I know there is a math formula for this, but for me, when I try to think it off the top of my head, I can't do it. So imagine you have these three things in your method that affect the outcome, and now you have to try to figure out what is going to be the outcome of this.
[00:03:34] So, I think kind of the easy argument for this is, is like well that's why we write unitests. The problem is, or rather I'm all for unitests, but we have this little thing called before each, as in every test that you run, you are resetting state, you're controlling the state as it goes into the text.
[00:03:58] So we have this equivalent in real life, and its called restart your computer, restart your phone, refresh the browser. Cuz what happens, you go in a bad state, a state you didn't intend to, you have to refresh it, you have to reset that state. That is kind of the real life equivalent, IRL before each is it's called restart the thing, because you've gotten your application into a state that the developer did not account for.
[00:04:28] So you can see one method one internal state and we can no longer assert what this is going to be without understanding the impact of that hidden state. And not only that, if you were to introduce an additional logic structure into this, like let's say it was a child, then, do this, because this other outcome would be dangerous.
[00:04:54] And, this kinda seems a little contrived; I've seen way worse. In the sense it's very common to see blocks of code that is doing multiple things where you just see this procedural, top down, if this do this, if this do this, if this etc. But the problem is, how do you even test this, this internal thing, this structure right here?
[00:05:22] How would you say, if it's dangerous and it's a child, do this, if not. The only way to get to this is you have to step through the entire rest of this body to get to it. So again, complexity leads to purgatory.
>> Lukas Ruebbelke: So, now we're thinking like well how do we manage these possible states?
[00:05:46] Let's take it a step further. So this is a real easy one, we have an inventory class, two components, that have this add method on it. And so each component simply you can call add on it and, it will update the total on the inventory ledger. This seems totally benign, when I started Angular JS, I did something like this all the time, the problem is, this.
>> Lukas Ruebbelke: What happens if the items component has a requirement that you can never ever, ever, ever, ever or the factory will explode have a negative number?
>> Lukas Ruebbelke: Or you can never get below 10. So let's say this was like a thermostat or something. There is a real reason why something cannot be in certain state or you cannot have a certain value.
[00:06:48] So, what would keep the widgets component, so let's just say you can't have a negative number,
>> Lukas Ruebbelke: In the items component. The widgets component does not share that same constraint, what would keep the WidgetsComponent from setting it to the negative 10?
>> Lukas Ruebbelke: One, the answer is nothing at all.
>> Lukas Ruebbelke: More importantly it's that, I think in kind of the benign approach or kind of the trick, I think people get kind of lulled into this. Is you have a programmer writing both of these classes, they're like I just know like they're here like I know you can do it.
[00:07:24] And so it's kinda right there, on top of mine. But what happens when three months later some other developers come and they're not aware of the constraints? So that's how, in a very poor way, you would keep this from happening you said, the widget's component has to have knowledge of the ItemsComponent, and vice versa.
[00:07:44] And so now purely because of the fact they are in this mutual state of like, mutually assured destruction, if you will, that they're coupled together.
>> Lukas Ruebbelke: One has to know something about, some constraint that has nothing to do with that component. And so this is where shared mutable state is a real problem, and we saw it yesterday when we were doing the detail form, we started typing and it's changing over here.
[00:08:10] You had to be super careful to avoid that, let's talk about controlling flow. So this is actually from Jafar course, so this is kind of a big problem they had at Netflix. And so kind of borrowing the approach they did is, what happens when you have, you're making a call with a promise, and you need to recover and do it again?
>> Lukas Ruebbelke: What do you do? So anyone who studied 1.x, I mean, that's a real concern it's like, hey, this call failed I wanna actually recover, I wanna try it again, I wanna retry.
>> Lukas Ruebbelke: Well, the only way to do that is to introduce more code. Like, this is how code volume spins out of control, it's cuz you don't have mechanisms so they're kind of like agitate each other.
[00:09:02] It's like I don't have the proper mechanism to manage my control flow, so I have to introduce more code volume, which then introduces state. Or I have to introduce state which is more code volume, and it's just this cycle of complexity leading to purgatory. So in this case I need a retries count, again that's outside of the structure, that you're saying, try it three times, if not, then give up.
[00:09:27] Now imagine, and this is where Jafar just was kind of like, you're starting to imagine if you had two calls that you had to coordinate. So in the case of Netflix, you will basically wanna go get the videos that users requests but at the same time you need to check to make sure that they're logged in, and they're dependent on each other.
[00:09:47] So you cannot move further like forward without both of them successfully resolving, like how do you control that?
>> Lukas Ruebbelke: I think I'm getting an ulcer thinking about this. I mean, these are easy things that can fit on a single slide, and already you're like that is a really hard problem.
[00:10:08] And so this is where this leads to, again, state management, grove control, and variably, I think the bottom of the threes, what you end up doing is writing more code to try to handle it.