All about level three, algebraic modeling
This is an episode of Thoughts on Functional Programming, a podcast by Eric Normand.
What do I mean by algebra? And how do we get from level 0 to level 3?
[00:00:00] All about level three algebraic modeling.
[00:00:04] Hello, my name is Eric Normand, and this is my podcast. Welcome.
[00:00:12] So today I wanna get into level three. In my new book about domain modeling, level three is algebraic modeling. And the idea of these levels is that there's certain breakthroughs that you have when you're on this journey of learning domain modeling.
[00:00:34] And this is the third level that you can get to in my book. I don't want to say this is the only way to learn it or anything like that. It's just the way I've chosen to organize it because I looked at all the stuff I wanted to teach and this made a lot of sense.
[00:00:51] But this third level --algebraic modeling-- is really exciting to me. Even though I'm excited about it, it's actually [00:01:00] the least important. Okay. It's very cool. I like it. I enjoy doing it, but the data modeling is way more important than the algebraic modeling. I just want to make that super clear. You can't do algebraic modeling without doing good data modeling. By definition, the data modeling is more applicable and more useful. But also if you're looking to learn better models and then this is it.
[00:01:37] Let me go through the whole journey again. The first level is data modeling, and that is where you represent the states of your model in the structure of data.
[00:01:52] While you're learning how to do that and getting experience, you start to realize that there's quite a lot of choices, [00:02:00] okay? There's a lot of different ways that you can choose which data structure, right? And that's a hard problem because you could get stuck with your data model. It could be you chose one and you chose poorly.
[00:02:21] As you're learning, you start to realize that, Man! If I had just written this operation first, or even thought about it first, it would've saved me making the wrong choice. Because when I look at this operation, it's obvious that I needed to put this in a hash map and not in an array, right?
[00:02:39] The breakthrough is you realize, Why don't I just start with the operations without even thinking about the data structure yet. I'm gonna lay all the operations out and pick the most difficult operation, the most complicated one, the one that I think is gonna give me the most [00:03:00] trouble, and I'll think about that one and come up with a data structure that works for that.
[00:03:08] That breakthrough will take you really far. But as you're using that and gaining more experience, you start to realize, Wait, it's not even the single operation that I should be worrying about. There's a lot of information in how the operations compose. I'm never doing just one operation.
[00:03:30] I'm doing 10, 20 operations. And they often interact in ways that I hadn't thought of and predicted. So I should start thinking about how they interact before I even think about how to implement the operations.
[00:03:51] That is algebraic modeling. That's the breakthrough. If you design the composition of your operations,[00:04:00] that will get you to the next level of expressivity and clean code and clarity, understandability, all that stuff. So that's what I want to talk about or at least start talking about in this episode.
[00:04:24] Whenever I mention this, I get one of two reactions. One is, oh yeah, that's really important. You should talk about that.
[00:04:31] Or, Algebra? What does that have to do with what you're talking about? Okay. So I wanna explain to those who think it's weird that I use the term algebra.
[00:04:46] It is very much related to the high school algebra that you had, but probably not emphasized enough in your high school algebra.
[00:04:59] Here's [00:05:00] the cool stuff about algebra, right? You remember. You have equations where you use letters instead of numbers, right? What's cool is that you were able to learn a lot about an equation without even knowing the numbers .
[00:05:20] Yes, there's an idea of solve for X. Is cool that you can kind of eliminate a lot of the numbers in it and figure out what X has to be. That's cool. That's not what I'm talking about. I'm talking about stuff like, You know that X plus Y is equal to Y plus X regardless of what X and Y are. It's kind of cool that you can know this property and never have to reference the actual number. Of course, it's easy to prove that three plus four is equal to four plus three. But to say it's true for all [00:06:00] numbers, that is a much bigger deal.
[00:06:07] So what we're really talking about when we're talking about algebra as part of modeling, is to say what must be true no matter what when we do these operations. We're talking about being able to reason over whole classes of situations at once instead of just individual situations. We're not talking about, There's three situations in my unit test. We're talking about every situation, every possible pizza, and every possible add a topping operation you do to it.
[00:06:49] I'll give a very specific example and then we'll generalize it to a variable. Right? Okay. If I take a pizza that is a small size [00:07:00] and then I set it to large size, and then I set it back to small size, I will have the same pizza I started with. It started small. I set it to large, and then I set it back to small.
[00:07:19] Now, if I just take that size and I call it X. If I start with a pizza at size X, I set it to large and then I set it back to X. The pizza should be the same.
[00:07:36] This is saying quite a lot, by the way. I mean, it seems obvious. Yeah. You're setting it back to where it started. Of course, it should be the same, but I'm also saying, it's not changing anything else. It's not changing the toppings, it's not changing the cheese and the sauce. That's a strong statement.
[00:07:55] Now I can take that large and replace it with Y. Okay, so now I can [00:08:00] say if I have a pizza size X, and then I set it to Y and then I set it back to X, I have the same pizza I started with.
[00:08:12] You can, you can see where this is going. I'm able to make this general statement about what setting the size means.
[00:08:20] Let's take another example. What if I have a pizza with no topping set? I add olives, and then I remove olives. I should have, again, the pizza I started with.
[00:08:35] And you can easily just replace olives with X, right? So I add X and I remove X. I should have the same pizza I started with. Now I can also use another variable and not just start with an empty pizza, like a pizza with no toppings. I can start with any pizza and call that P. So for any pizza P if I add and then remove [00:09:00] X, I should be back to P. Now, this may or may not be true, but it's a property that you could assert right now.
[00:09:08] When would it not be true? We gotta think through this. Well, what if I go over the three topping limit, right? Maybe if I add a topping, it goes over the limit, so does nothing, right? That could be how I implement it. If it's got three toppings and you try to add a fourth topping, do nothing, just return the same pizza again. And then I remove it. Then uh oh, now I'm down to two toppings. So maybe that rule doesn't work.
[00:09:45] That is one of the reasons why you want to defer that topping rule, that maximum topping rule till later. Like maybe do that in the UI or in the API. If you leave out that [00:10:00] maximum topping rule, you can just always add another topping and then remove it.
[00:10:05] That's an example of why I would want to defer it. It keeps your algebra really clean. So much nicer if you have this nice, clean model.
[00:10:17] I think I would complicate it and I would say, Why don't you add two toppings and then remove them to make sure that you can remove them in any order. So I would probably add a topping X and then add a topping Y and then remove topping X and then remove topping Y. I would probably generalize it even further and say, You can just add N toppings randomly, and as long as you remove all the ones you add then you should be back to where you started, regardless of order. Like you shuffle the order and then you do it again, and then you remove them. That's a general property [00:11:00] that you can rely on.
[00:11:04] When you're thinking about operations and making them total, this is where those things really pay off. Cuz it's hard to do this kind of algebra when you don't have total functions. This is also where the high fidelity of your data model pays off.
[00:11:26] The fact that your model doesn't have all these weird states means that you can operate at this level. And I think the reason we often don't get to this level in our code is because we don't have total functions and we don't have high fidelity data models.
[00:11:45] We're mired in the complexity that the low fidelity bring us. We're just lost in that complexity and we can't see how a clean algebra is even possible. And I'd say [00:12:00] the answer is the deference. The way you get it is you make the clean model and you defer the hard stuff to another level as it makes sense.
[00:12:14] Alright, well that's about all I have to say about this. This is really just the introduction to the algebraic level algebraic modeling. I'll have more episodes about it.
[00:12:29] My name is Eric Normand. This has been another episode of my podcast. Thank you for listening. And as always, rock on.