All about the volatility lens
In this episode, I introduce the volatility lens, which seeks to help us write code that deals with a changing world.
[00:00:00] All about the volatility lens.
[00:00:04] Hello, my name is Eric Normand, and this is my podcast. Welcome.
[00:00:10] So I'm writing a book and it's about executable specifications as a means of domain modeling. And it's a hard topic because it's about software design, and that's just a hard thing to teach. And the way I've come up with teaching it is I'm teaching it as a bunch of different perspectives. I'm calling them lenses.
[00:00:40] Each chapter is going to talk about different questions that you could ask to get a little bit more information about your software and the context in which it's running so that you can make better design decisions. And today I'm talking about the volatility lens. In the volatility lens, we ask what can change, what is likely to change, and how often and in what way?
[00:01:17] Change is one of those difficult topics in software because the discussion about it has turned into basically a boogeyman situation. When people talk about software change nowadays, they often talk about it like it's this unexpected thing. It could happen anywhere. Your requirements could change out from under you.
[00:01:47] And so you just have to be ready to change anything at any time, in any way. There's no way to predict it. If you try to predict it, you're gonna be wrong. I think that there's a lot of truth in what they say in this discussion about change, but they are also missing something very important.
[00:02:09] So the discussion about change is often what I would call unknowable and maximal. Anything could change and you can't know.
[00:02:22] So one thing that I've learned as I've gained more experience as a software engineer is that you shouldn't add 10 lines of code today to save 10 lines of code tomorrow. I see people doing that all the time, putting in something like, oh, I might want this to be configurable later, so I'm going to add this complex mechanism to be able to configure it so that I don't have to change the code. But what you're doing is you're adding 10 lines today so that you can avoid adding 10 lines in the future maybe. Those things add up. You add 10 lines here and 10 lines there, and 10 lines there. And maybe only one out of a hundred of those things actually comes true.
[00:03:20] Now there's a psychological factor coming in too, which is that this kind of gambling effect that the one that does come through, you feel like, ah, it was so good. You see how I anticipated that change? The bet you made paid off, but only one out of a hundred bets paid off. You played a hundred bets and only won one.
[00:03:48] It wasn't really worth it. You're basically in the red. You lost, but it feels like that one was worth it. If you could just do that again. You've forgotten all the cost it took to get that. You forgot that you made 99 other ones. And all the lines of code you had to write for those. Something about the dopamine of that one time covers up for all of the mistakes for all the other ones.
[00:04:23] And I'm guilty of this too. It feels really good to have anticipated the change when it comes down. When when you finally have to change it, you're like, yes, I'm so glad I did this work up front.
[00:04:36] Now at the same time, in mostly agile circles, the discussion is that requirements change. Requirements are these fickle things from people who don't really know what they want, and they're going to change things. And so you have to make your code adaptable. How do you make your code adaptable? You add indirection.
[00:05:05] Maybe we're gonna need to add another kind of way to sell something, so like, let's make that an interface and, and maybe we're going to have a different kind of product, so don't hard code that. Put a thing to make it extensible. And so you add all these indirections that aren't paying today, they're basically for the future to make the change cheaper.
[00:05:35] So we got this tension here between you're probably not gonna need that to be so flexible and it has to be infinitely flexible. 'cause anything could change at any moment. You can't trust today's requirements won't change in any possible way.
[00:05:53] So how do we resolve that? Well, one thing that I think is not talked about enough is that a lot of change is actually known upfront. A lot of change is knowable with just a tiny bit of analysis, a tiny bit of information. And often the stakeholder is not the person who has this information. The information is contained in the domain, but sometimes the stakeholder knows.
[00:06:27] So what am I talking about? In our coffee shop, we can look at the coffee shop's business and what they've done in the past and ask the owner and the other managers of the coffee shop, how often do the sizes of coffees change? And they might tell you something like, look, we've been open 10 years. We've had small, medium, large since the very beginning. We never changed it. We haven't added one, haven't removed one. That's some useful information there because that can really help you choose how you're going to implement it.
[00:07:13] Now you might also ask like how often do the add-ins change? And they might say, we have like seasonal ones, so we could have a pumpkin spice in the fall and peppermint for for the winter. And we always come up with a new spring flavor and there's always summer flavor. So at least seasonally, but then, you know what, we also run out sometimes and we don't want to sell those anymore.
[00:07:48] So we want that to be reflected in the orders. If we run out of almond syrup, we don't want to sell that anymore. So we need to be able to dynamically say what's available. Okay, that's great.
[00:08:06] They can change basically every day as you run out of stuff you don't want. That also helps you decide how to implement it, because if it can change every day, you probably don't wanna hard code the list in the code because then you'd have to make a deployment just to change the add-ins. You probably want this as a value stored in the database and then the database can be updated and then things query the database to get the current list. This is just analysis and then basic coding, basic common sense of how things need to be.
[00:08:46] But at the same time, the sizes they said haven't changed ever since they opened the business. You could hard code them. It's easier to hard code them than to read them out of the database every time. And the code is gonna be simpler.
[00:09:07] And you know what? Things might change. They might add a fourth size, but that's okay, because it's very unlikely. And so the cost of that is worth it. It's worth taking the risk that it might change, and you'll just have to open up the code, change it, and make a new deploy.
[00:09:30] And you can go down the list. These discounts that you're giving, do those ever change? Oh yeah, we do monthly promotions. You don't want a hard code each one. Needs to be something that a manager can make. Oh, okay. So not a programmer or a manager, they're going to need to configure the promotion. We want something more dynamic, it's going to have to be designed in its own right.
[00:10:00] And if they say, No, we just have the same sales every week or every month, it's the same thing, it just changes the name of it. Now it's the March sale or this April sale. You can hard code that sale.
[00:10:15] Change is something that is a factor in design. And you can look at the things that change and isolate them from the things that don't change. Now, you might be wrong. You can't avoid being wrong. But you can do your homework, get as much information as you can, and make the best decision you can with the information available.
[00:10:43] What I see people not doing is the homework. They don't go and do the analysis of how often does this change, how might it change? How likely is it to change? And then designing that in, they just think, well, maybe it'll change. Frankly, it could be fun to make it more general, could be fun, to make it more abstract and indirected. So they code something in to make it changeable when it doesn't really need to be.
[00:11:18] How does the volatility of something, meaning how often and how likely is this going to change? How does that affect your choice of encoding? How are you going to implement this thing? I'll attempt to explain it here on a podcast.
[00:11:39] Imagine a spectrum of the frequency of change. The frequency of change can go from never to, minute to minute, even maybe second to second if you really want to go that far.
[00:11:55] And on that spectrum you can put how hard something is to change. So if you have a really intricate piece of spaghetti code, that's hard to change. So you are gonna put that closer to the never spectrum. We're never gonna change this. It's just gonna keep running forever. And then something like values in the database, that can change second to second. The database can read and write all day long, so let's put that on the other end of the spectrum. And you can do this for all of your constructs.
[00:12:38] And you could have something like an interface that has multiple implementations, you know, an interface with four classes. You know what? I can add a new class without changing any existing code. That's gonna be further toward the changeability side. Okay. Because you can add a new kind of sale, a new kind of promotion, without affecting the old promotions.
[00:13:11] So it's add only, which is great. That's a good way of growing. You don't have to change anything. Something where you do have to change stuff, but maybe it's not so hard. You have something like an enum if you have to add a new size. And you're using an enum that has small, medium, large. Is it so hard to add a new kind of size?
[00:13:36] Well, it might be because let's say you add extra large, then now all the places in your code where you are switching on the size, you have to handle that extra large case. It might not be that many places, but if it's a lot of places, yes, that's a big change. 'cause now you have to modify your code all over the place.
[00:14:02] Some static languages will tell you you're not checking this case. That makes it easier because then you can just follow the error messages and add each one. But if you don't have that, now you've got a big problem because you don't know where you're gonna have to modify the code.
[00:14:21] So it's gonna take longer, it's gonna be more of a paint. Okay? So you can go through each construct and you know, roughly place it on this spectrum. How big of a deal is this to change? Now, one thing you don't want is to say, Well, I'm afraid anything could change. I don't want to make anything hard coded, and you start pushing all your code to the dynamic stuff.
[00:14:48] The problem is the dynamic stuff is more expensive. It's harder to code in. You're not gonna get as many checks. Values in the database are harder to check than something that's part of the type system. 'cause the type system is gonna tell you when you've made a typo or you've missed one of the cases. Values in the database, they're just strings coming out of the database. But there's no good way to check it. I mean, you can have a check in the database table itself, but it's, it's still, you know, at runtime when you put a value in, that's when you learn that it was the wrong value. It's more expensive to learn about that mistake.
[00:15:39] This analysis is not that hard to do. You can imagine how often is this thing gonna change? Do your homework, do a little research. How likely is it to change? Because if it could change every day, but with 10% chance it might not be worth doing. It might not be worth doing if that likelihood is so low ' cause it's not worth the cost.
[00:16:05] Do the analysis of both your domain and the programming language constructs, where do they fit on the spectrum? I like to think of three-ish buckets. The spectrum is great, but sometimes it's too, too much choice, right?
[00:16:27] You got your closed bucket. This is stuff where you actually have to change existing code to make something work. You're changing the enum type and now all the code that use that type may have to change.
[00:16:41] There's open, which is like adding a new class. As long as the class implements the interface, all the code that was working with that interface can use this new class. It's open 'cause you can add something and without changing any of the existing code, and in theory you could change the class, an existing class as well, as long as it still implements the interface. It's open.
[00:17:11] And the third one is runtime. This the most changeable. This is where you're using strings, storing them in the database. Your logic is less tied up in the type system and more at runtime. This makes it very dynamic because you could read in the values that you need from the database each time. Could be different each time. Something else could be changing them while you're reading them. We're out of soy milk, so don't sell that anymore. And so now your program is just gonna adapt to not having soy milk. It's not gonna try to sell it, it's not gonna put in the interface anymore.
[00:17:52] This has been volatility. It's all about getting more information from your domain so you can make better decisions. Don't make changes easy if you're not sure whether you're gonna need that change or not. The rule is you're not gonna need it. YAGNI, you ain't gonna need it. That indirection is not worth it until you are sure you're going to need to change it.
[00:18:18] My name is Eric Normand. This has been another episode of my podcast. Thank you for listening and as always, rock on!