Yeah, so I want to welcome everyone to this month's meeting of the Houston Functional Programming Users Group. And tonight we have Eric Normand speaking. I think many if not most of you know Eric. He is very, very active in primarily teaching functional programming. He has one book, Rocking Simplicity, which has been very, very well received. People talk about it all the time as being one of the most accessible texts out there on learning functional programming paradigms. He is currently working on a second book. He has a podcast. He has classes. He speaks all around the country, maybe the world. And this second book he is talking a lot about on his podcast right now. If you're not listening to it, I highly, highly encourage it. It's really nice stuff. There are short pieces. He did really long ones for a while. And now these are really short ones about 10 to 15 minutes. And Super Nice Guy, he presented, I don't know how long, two years ago or something like that. He presented right when I sort of took over organizing the meeting and we were going online. And so we're really happy to have him back. He and I have actually been corresponding over email recently, back and forth, and been having some very exciting discussions, at least from my perspective. And I look forward to continuing that. And I'm very happy to welcome him back to the Houston Functional Program in Houston. So let's turn it over to you, Eric. Cool. Thank you very much, Claude. Yeah, it is great to be here. It's great to be back. And it's cool to see meetups kind of starting up again, people sharing droplets and what have you with each other. And I guess I'm just going to start. So like Claude said, I'm writing a book on domain modeling. It was originally supposed to be, I'll give you all some exclusives in this talk. So don't worry, you're getting some good stuff. It was supposed to be part three of Grocking Simplicity, but I cut it after finishing part two. It just didn't seem to be part of the story of Grocking Simplicity. Grocking Simplicity is sort of functional programming. How would I put it? Like if you could start as a beginner and then have most of the skills that you needed to be a professional functional programmer by the end. Now, of course, you're not going to be good enough. You got to practice and all that, but it was all in there. And this is something, domain modeling is something that I always thought was really important. I've always loved it, but I saw so many people not using it. So I figured if they can work professionally and not know about it, then it must not be fundamental to being a functional programmer. So I decided to cut it out. And that, fortunately, let me publish the first book and finish it, wrap it up. And I still had this idea in me, so I've been working on it. And I'm glad I did cut it out for that other reason because I'm still working on it. I published the Grocking Simplicity two years ago now, and I'm still working on these ideas. So it's taken longer than I thought. Okay. So my talk is trying to introduce the main skills of domain modeling that I can do in like an hour. Okay. Okay. Let's go. So I have this thesis that software design has failed. What I mean by that is that software design is good. I practice it. I do it and I read about it. But no matter how much people talk about it, we still have this problem. We still feel like our software is not designed well enough. And it's kind of like a little cottage industry of people selling rules of thumb for how to make your software better and to solve the problems. And well, I'm going to bring up a quote by a famous architect, Christopher Alexander. He's the person credited with starting the pattern movement in architecture, which was it inspired the design pattern movements in software. And he actually was invited to speak at UPSLA in 1996. And I'll just read this. I began to notice by the late 70s some weaknesses in our work with patterns and the pattern languages. By the late 70s, I had begun to see many buildings that were being made in the world when the patterns were applied. I was not happy with what I saw. It seems to me that we had fallen far short of the mark that I had intended. But I also realized that whatever was going wrong wasn't going to be corrected by writing a few more patterns or making the patterns a little bit better. So in short, they had all these patterns, people were doing them, but the architecture wasn't any better. And when I hear that, especially in a software context, I think of stuff like this. Abstract Singleton proxy factory bean, which is actually a part of the spring framework, it's real. It's not a joke. It is serious. It's deadly serious. So I feel like the same thing has happened in the software design world. People can follow the rules and still not get good design. And to me, that means it's broken. Not the design is bad, but that we just don't know how to do it. And maybe we're even focusing on the wrong thing. So let's imagine these white squares are our code. We don't like it. It's all messy. It's disorganized. And we can start to point at stuff and say, look, there's too much coupling or there's too many classes, or there's all these code smells. Right? We're talking about the code. Look how messy it is. It's just a jumble. It's spaghetti. The code is bad. And so then we start cleaning it up and we add some indirection to get rid of the coupling. We use the decorator pattern to remove some classes. We refactor. Okay, but it's less messy. It's like we cleaned up our room, but we're still just talking about the code. We're not talking about what the code represents. Does the indirection that we just added correspond to anything in the real world? We've removed the coupling, but was there coupling in the world that we just covered over? Does the decorator encode the possible states? I've seen some uses of decorator pattern, especially in the books trying to explain it, where they take a thing where the classic example is Starbucks coffee, where you have mocha, almond, soy, latte with chocolate. And you can just add all these different add-ons to your coffee. And they represent those with decorators. And so then you've got these objects wrapping other objects that change their behavior, but they can wrap in different orders. But it just like explodes the number of combinations you can make. So you don't have as many classes, but you still have this problem of combinatorial explosion that doesn't represent anything in the real world. And we've refactored the code, but maybe it's easier to find stuff, but does it actually correspond to how the world is? I propose that this is the main failure of software design is that it just tries to talk about the code, just tries to clean up your existing code. And what we should do instead is build a domain model separate from our app functionality. So domain modeling is a set of skills and practices we apply to encode our understanding of a domain separately from the software's explicit functionality. So your app functionality is like all your features, all we need to be on this platform, that platform, we need to talk over JSON, all those incidental decisions you have to make when you're building an app are very different from how you're going to model the problem domain that you're trying to solve. And if you separate those out, and then implement your app functionality in terms of that domain model, then what happens is you separate stuff based on the frequency of change. So your domain model is going to change much more rarely than your app functionality. New features happening all the time, changing existing features, that's going to change a lot. You want to separate that out from your understanding of the domain model. I think besides just separating those things out so that your maintenance cost is lower, it also could give you a competitive advantage. I think that that's a leap that is hard to justify, but I've seen it happen at companies I've worked at. So if you can really find a good domain model that's better than your competition, you can iterate faster on your features and so out compete. Okay, I also want to at this point, I'm about to get into a different section. I forgot to mention, if you want to shout out questions, please let me know. I can't watch the screen and talk over my slides at the same time, so you got to make a noise so I can hear it. So any questions? I have a question. Yeah. So you start off with a couple slides back saying that that design has failed. Yeah. Right. So can you say more about what you think design is supposed to do and how like, so I'm not trying to say on the plane that fail without knowing what it was supposed to be doing in the first place. Right. So software design, I mean, this is one of the problems that I think you're, I've been investigating and trying to figure out what the original goals were of software design. It's very hard because most software design books do not give a definition of software design. Some do, or at least some give you the goal. And the goal that's most frequently cited is to reduce maintenance cost of your software. So like reduce the cost of change, make it easier to find the bugs, you know, that kind of stuff. And it's a very pragmatic goal that can kind of cut out some of the fluff, but it's still, I mean, when I read those books, it all still focuses on the code. It's sort of like, once you've written the code, you don't even think about the real world anymore.  Let's move it around. Name things better. You know, this method is too long. Yeah, go ahead. Yeah. So I wonder whether that's actually okay, because you said like, software designs this to sort of deal with the maintenance problems. That's not the world anyway, right? But maintenance problems exist within the software. Right. No, that's a good point. And my, this is the, I'm trying to create a connection between the quality of your model in the sense of how well it captures reality and its need to change. Like if you find a good model, it will change very rarely. And so it's code that won't have to change. It'll be super, it'll be solid in the sense of not, not that the software design solid, but it will handle cases that you haven't thought of. And we're going to get into how we can do that. It's one of the skills that we go through. So I believe that I am making a big leap and I am really trying to connect the dots. So please do keep asking these questions, because I really do want it to be very clear. And I also feel like this is a great opportunity because I actually clarified a lot of my ideas just making these slides. So thank you so much. So can, can we move on? And maybe you can ask after you see some more of it. Okay. So there's some teaching challenges that I'm addressing in the book. You know, I don't want to just start typing things that I believe. I actually feel like it's important to encode stuff. So I want to explain a little bit about why I think that it's a challenge to shift mindset to go back to like the world. Okay. So here's a kind of a model of a model, right? You have your domain. Let's say we're talking about coffee shops. You have the domain of coffee, which is just this amorphous thing, you know, you just, there's coffee, you can make it, there's beans, you roast them. It's like not very clear how you would encode that in a computer or what even you need to encode.  Okay. We're going to sell it in three different sizes and we're going to have three different roasts, light, medium and dark. And we'll keep it simple. We'll just stop there. There's obviously other stuff, but we'll stop there. And then you're going to take that conceptual model and you're going to turn it into an encoding some way of representing it in memory on, on over the network, maybe in a database, those kinds of things when you need them. So this is just saying size, this is a closure. So size can either be small, medium or large. It's closure-ish because that pipe symbol doesn't mean anything. Roast can be light or medium or dark. Okay. So what's going to happen is you're constantly jumping back and forth between these. And if you start on a project, you might be anywhere on this spectrum of stuff. You might be with the guy who started Starbucks and you haven't really figured out this simplified coffee model and you're going back to the domain and really figuring that conceptual model out. Or you might be joining Starbucks 10 years in and they already have it down and they just need a new POS system that you have to find the encoding for. So you learn the conceptual model and learn how to encode it. And sometimes you've already, you're already got the encoding and you realize, hey, we missed this thing in the domain way at the left. We're going to actually have to go back and even change our conceptual model and our encoding. It's like you're going to be moving between these quite a lot. Okay. At the same time, you're moving around in the language.  And you learn to use the features in certain ways. So you say, well, interfaces that kind of lets you start an is a hierarchy classes. It's how you model your entities. Oh methods, you start with your getters and setters and then you add some custom behavior. Got enums, but we don't talk about those too much. We got fields, that's for has a relationships, et cetera, et cetera. People, because the language is so big, and they learn, they have to learn it in some order and some methods so that they can get work done. They tend to learn these things. And this is a big learning challenge.  And so there's kind of a modeling process in the is a and has a way that Java programmers are taught. And that's the learning challenge is that they're going to have to unlearn that they're going to have to go back to their language and rebuild this middle mapping this usage mapping. So again, even after you've built it, you're going to have to go back to the language quite a lot. And so then these two things converge on the app, right, that's the encoding. And, well, I just wanted to show that they all they go together and you're going to be jumping around through all these things while while you're doing domain modeling. Okay, so to address these teaching challenges, I've come up with three levels. They're their levels because I feel like they go in like order of the most basic and fundamental to the most abstract. And each one, the part of the way I've tried to address the challenge of teaching it is to give give a focus so that instead of thinking about, you know, where's the has a relationships and the is a relationships, people start looking in a different place because we tend to want to jump straight into writing code. And we need to disrupt that and give them something for their brain to do while they're doing it. So each one has a focus and it has a goal as well for like what we're trying to achieve at that level. So the three levels are data modeling, operation modeling and algebraic modeling. We'll go through all three. Yeah, uh-huh. You put level one data modeling. I cannot imagine data modeling without knowing how it's used, but just keep going. We'll talk about it. Okay. Yeah, I bring that back up after if if I haven't answered it. Okay, so in level one, we're focusing on the relationships among values. This is again to give your keep your mind busy. So you're not jumping into like typing class dog extends animal, like the first thing you think of, right? Because that's where people are at. That's how we get those abstracts. I don't remember. Extract proxy factory method factory. Anyway, okay. So these are the values that we have in our small coffee domain, right? Got the three sizes and the three roasts. And I mean, I think for this kind of domain, it's very clear because it's already pre constructed. It's already, you know, digitized, discretized. These three things have a different relationship to each other than they do front to the others, right? So these three belong together. These three belong together. It's very clear. I don't think I have to dwell on that, but there is a relationship between the two. It's just like a weaker relationship. So we should characterize that relationship. So with these sizes, we're going to choose one among many. If we're building a coffee, right? If we're trying to describe a coffee, we will have to choose one of those. So it's small or medium or large. And I'm calling that relationship where you choose one among many, an alternative. You have many choices, but you can only choose one. We're going to do the same thing for the roast. But then at the bottom, the size and the roast, we're going to choose one of each. So we're not choosing one or the other. We're choosing one and one. So size and roast. And I'm calling this one a combination. Okay. So we're able to combine multiple values together into a single value. Okay. So now we're trying to, this is our goal now. Once we've done that analysis, we're going to take these features on the right from closure because that's the language we're using. So we're going to take these features and try to figure out which ones can encode the alternatives and combinations that we need. So I'm just going to do it like as an example, we could choose key words. It's not the only way to do it, but we're going to choose key words for the three choices in the size alternative, also the three choices in the roast alternative. But then our combination, we're going to use maps. And that way we can combine the two together. There's different ways you could do it. And at this point right now, it's just can you do it? We can evaluate it later. And just to say, like I know, geez, I put this on here and it just like looks so basic and so dumb, like who would do it any other way? Well, Java people probably would. So I'm going to give just a little example of how we might do it in Java. This is actually kind of a good way. You would have a class coffee as representing your combination. That's at the bottom. And it has a size component and a roast component. And each of those is just an enum. Okay, so that's pretty simple. That's one way to do it. And so you notice I brought up this idea of alternative combination. And I think that there's a bunch of these data modeling elements that are, I hate this kind of thing where it's like, well, you need this long list of things to learn to look for while you're data modeling. I wish it was much smaller. But this is the current state that I've got it in. And if you see any way to reduce this down, please help me. But right. So this, the alternative combination we talked about, we're about to talk about collection. So I'm going to leave that off for a minute. Mapping, that's a way of taking one value and getting another from it. And then optional is a way of saying we may or may not have a value. The atomic ones are pretty, pretty clear. Identifiers, counts, measures, dates, text. And part of the idea is to make it very language neutral. And not use any particular type. Because that if you use a type, then you're basically saying use that type. And that's not what I'm trying to do. Sometimes the language provides a type that is exactly the same as one of these. And in those cases, it's pretty clear. But in some cases, the thing that's called that, like it's called a, I don't know, like an optional, it might not be exactly the same. Okay. So I'm hoping to make a big inventory of these things. This is where I'm at so far. Okay. So let's make it a little more complicated. Take the same data model, but add a new thing. This time, just like it's Starbucks, there's all these things you can add to your coffee. We'll just keep it down to five just for ease. So you can add a espresso shot, almond, hazelnut, soy milk, or cream. Now what is the relationship among these things? It's a little different from what we've seen before. So before we saw that it, we saw that you would have this alternative thing, but then there was only one, but you can have an espresso shot and soy milk. And you can even do like double espresso shots. So there's something else going on here. And so what we're going to do is we're going to compose up that idea from these elements. So first we'll make an alternative. So we'll call this an add-in. It's an alternative. You choose one of those. And then we're going to make a collection, which is you choose zero to three of those add-ins. So that means you could have almond and espresso. And I did zero to three because I'm just assuming that the business would say no more than three because that just makes it easy on the slides. And then you would add it to the combination. So now your combination includes size and roast and add-ins.  You've done the analysis and you say, well, our alternative is going to be keywords like the other one. And we're going to use a vector for the collection. So we can have almonds and soy. And then we're going to add it to the map, which is our combination. And so we'll have add-ins with almond and soy. Was that the question? I heard just something. Okay. All right. So here's the thing. We've got to evaluate whether our encoding, our data model down here at the bottom is any good. And one way we can do that is to count up the combinations. So just to this small piece, just of this add-ins part, we have five possible add-ins. How many combinations do we have when we use the collection of them? So we have the empty vector that gives us one. One. We have five if we just have a single one in a vector. It's a total six so far. And then if we have two in a vector, that'll give us 25. And then if we add three, we have 125. So we add all of these up and that gives us 156 combinations. Okay. So we can actually represent 156 different combinations of, I feel bad because I'm using the word combination, which I shouldn't, but we're using 156 of them. We have 156 different states that that coffee can be in. However, we counted some of them twice and some of them three times. So here's one that we counted twice. Almond with soy and soy with almond. Those are the same coffee, right? They're going to mix together. It doesn't matter what order you put them in. And this one we counted three times. Almond, soy, soy, soy, almond, soy, so I said almond. So how many of those did we count twice? Actually, there's only 156 unique combinations. So if you sort them and then throw them into a set, you only get 56 at the end. So this is like an objective way to analyze our domain model or data model to see how many extra states do we have because we're going to have to deal with those at some point because you're going to say, well, are these two coffees equal? You're going to have to figure out how to change them to like a normal form. Okay. So what do we do with this mismatch between our data model and the domain model, the conceptual model? Well, we can live with it. We can just like throw if statements all over the code, figure out how to you know, maybe we refactor it eventually so that we don't duplicate stuff everywhere. But we're still going to have to worry about it all the time. And so I think this answers your question. I don't remember who asked it, but it's kind of an answer to the question that like bad data models, you know, I was talking about good data models, but bad data models force you, if you don't think about them and fit them tightly to the conceptual model, they will often cause you to spew if statements all around your code to deal with the disconnect between how you're modeling reality and the reality itself. So that's a way that it leads to better design. We could find a new representation. So if your language has a thing called an ordered list that I just made up, you could throw them in an ordered list that keeps it ordered. And so that way, equality is easy to see. And you don't have to deal with it elsewhere, like your data structure is taking care of it. And that's actually kind of a new, kind of a great way to do it. We could change the conceptual model. We could go back and say, I don't know how to code that. So please, can we change the business? And you could say, well, we're, maybe you're not changing the business, but you're changing how you analyzed it. So instead of saying, oh, it's a collection, we're going to use a mapping of identifiers to counts. So now, instead of saying almond soy, soy, we're going to say soy to almond one. And because we're using a hash map, the order of the keys doesn't matter. And we've got the count in there, right? That's that's included in the value. So we're kind of encoding the same information. But now we don't have this problem of being able to encode the same thing in two different ways. So I almond all soy almond soy and soy soy almond are the same. Okay, and now, so that that could be an improvement. And then sometimes you have to go back and revisit the domain. And this actually should say revisit the conceptual model. So revisit the domain, we could just say no duplicates allowed. Now we get to use a set. And you can't have two soy shots in your, in your coffee. That's kind of extreme. And we wouldn't want to impose that on the customer most of the time. Okay, and just in case I haven't, I haven't been fair to all the bad code out there that I've been showing like pretty clean code. Here is a way you could implement it in Java. You could make a class coffee and then use an int to represent the three different sizes. You know, zero is small, one is medium, two is large. Same for the roast, you could have zero as light and one and two for the other two. And then you could just like list as fields all the different add ins. So kind of hard code them in there as ints, right? You could do that. I see a ton of problems with this. I bet you do too. But I mean, it could work if given enough code to work with that, you could do it. And, you know, just imagine like the first, the like the Java util date class, how it uses zero to represent January. I mean, you could do it. All right, any questions before I move on? Do you mind if I just jump in? Yeah. Yes, interesting. It occurred to me just before that I guess when you were talking about choosing the right structures, I guess to represent certain data. And then I noticed, so when you pick keywords for these, you know, you have keywords in each of these cases, there's not necessarily something like that structure doesn't, as far as I'm not a very familiar closure, but it doesn't show that the three sizes that are keywords are somehow related or the three roasts, right? So then is that something that you would handle in another place in the model? Or is that something that would make you think like, maybe those need to be put into some sort of collection that shows that this is the exhaustive domain or all possibilities where otherwise you might not have that idea, or it might not know what's right. So you're talking about, I mean, it sounds like you're talking about validation in some sense of like, did I give it a size that is, you know, I gave it a keyword. Is it one of the three sizes that I'm expecting? Yeah, and that's a thing like different languages provide different features for checking those things. And so you'd have to go to your language and decide how am I going to enforce these things. Something like Haskell, you would probably use a discriminated union, and it just, you know, will work. It'll have three sizes as part of a type, and it'll only allow those three things, you know, at static compile time. Closure, you would probably use something, some kind of dynamic check, maybe spec or one of the newer ones. I can't remember the name of Ann Molly that does that kind of check. You'd have to, you know, you'd have to do it. You could do it ad hoc, right? You could have a set of them that's like, this is the exhaustive set. But you know what? It could also be that you want to be able to store them in the database and add and remove sizes pretty frequently, and you don't want it to be a type. You want it to be some dynamic value that it reads from the database. You know, the exhaustive set of sizes can change, and so we're going to do that. Certainly for the add-ins, you'd probably want to do that. You can like do a seasonal add-in, or like if you run out, you could like scratch it off the list, which would be hard to do if it was encoded in a type, right? And I do want to get into that in the book, talking more about like volatility and what can change. But I don't think I have time for that tonight. But does that answer your question? Yeah, that's great. Awesome. Right. So part of me is like a little happy, a little giddy, that it seems to me that I'm getting at something a little bit more objective when we're counting the states. When you're counting the states, it's a very numerical thing, and you can then have to reference reality, reference your conceptual model, and count those states, and compare the two. And any mismatch is going to require extra code. That's my contention. And we didn't talk about it, but I said you could sort that vector, and I'm calling that a normalized function. That's kind of like a very common thing to do. You have two values, and you need to normalize them so that you can compare them. Normalizing meaning, putting them into, if two things, well, if two things represent the same thing in the conceptual model, then they will be encoded in the same normal form. That's what normalize does.  You don't want something that doesn't make sense from your conceptual model. Okay, level two. Um, how are y'all feeling?  You following, feeling good? I'm good. Skeptical board, throughout some of them. We're feeling good because there's free beer here. Well, that doesn't make me feel good. You could get that anywhere. Or you could have anything. I think we're a couple hours earlier. So that's, that also helps here. Yeah, yeah. All right. Cool. Cool. Yeah. Sorry if I'm fading because it's eight o'clock here. All right. So level two. This, I won't take as much time with, and level three as well. I felt, I feel like that's the fundamental thing is data modeling that people aren't very good at it. And it's much more important to be able to do that. So what happens is you build all these data models and you see that, well, I have all these choices still. I could use a vector or I could use an ordered list or I could represent it like a map. And it's so hard to choose. It's not clear what's better. And also, sometimes you build your data model and then you go to write a function with it and you're like, oh, I can't, it's not really very easy. It's kind of awkward to do this one use case that's really important. And this happened to me. I eventually realized, well, I should look at all the use cases first before I even look at my data model. Now, you can't do that if you're not already good at data modeling because then you're like, off in La La Land. You can't get back. But if you know how to data model, I suggest you write out all your use cases and even turn them into function signatures. So here's a use case. We want to be able to take two coffees and know if they're two coffees and know if they're the same coffee. So we'll write a function called coffee equals that takes two coffees and returns a Boolean. So by function signature, I'm talking about the function's name, the arguments and their types. And this is just inferred from the name of the argument in closure. And the return value or return type. And here I have to put a comment because we don't have static type annotations in closure. Okay, so we have another use case. How many espresso shots does a coffee have? So I think anybody could write this in this room. How many question mark takes a coffee and an add in. So I'm generalizing it here. This the use case was like espresso shots, but I'll say no, I'll make it an argument. And it'll return a natural number, right, zero or more maximum number of add ins. So we want to know if we want to say that like no more than four add ins. And we might as well put a min while we're at it. So let's do without limit within limit takes coffee and a min and a max and returns a Boolean, right? So that's going to satisfy our use case. And add add in. So we take a coffee and add in to add in returns a modified copy of that coffee, functional programming, of course, so we're going to do immutable stuff. And then remove does the opposite removes one from the coffee. And there's probably more use cases, but you know, time and all that. Okay, so now let's compare the vector version and the map version. Remember, the vector version had the add in this is the only difference that the add ins are in a vector. And so you have this ambiguity with the order versus the add ins have the name of the add in and the count inside.  This is assuming that coffee and coffee B are both normalized. Okay, because it's kind of easy to assure that you're always normalized when you're always using your methods. All right, how many was someone moaning from disgust to my talk? Okay, so this is how many. So, oh, I didn't do this one right. Oh, I'm sorry. How many for this one should be much simpler. Can I edit it? Oh, that's editing the notes. Well, anyway. So this is this you have to do like over the list, you have to filter out the ones that match the add in and then count them. This one I messed up. This is this code is wrong. You actually just need to grab it out of the map, but with a default version value of zero, right? Within limit. Well, this one you have to count, but this one, look, I did it wrong again. Oh man, I'm very sorry. I actually want to edit it. Can I do that? Let's do it live. Can you still see it? Did it stop sharing? You stop sharing. It stopped sharing. Okay, so this should just be how many should we get out of the add ins of the coffee? Add in with the default of zero. Okay. Now the within limit is going to be a little harder now because we're going to actually have to add up all the values. So we're going to have to take, I'll just do it like this, reduce plus zero the values of that map. Does that make sense? The values are going to be two in one and we're just going to sum them all up starting at zero and check if it's less than max and greater than min. Okay. Now can I play this from where I was? Did I lose, did you lose the sharing again? No, we can still see it inside. You see it? Okay. It says screen sharing is paused. Oh, it hasn't moved. It has not changed. The screen is not moving. Okay. Cool. All right. So that's going to change back on the next slide, which is unfortunate, but I'll just keep going. So in this one, when we add on the left for the vector, we have to do something kind of easy. We're going to just call conge. Oh, this is not easy closure code. I'm sorry, could have been easier. We're going to add it to the vector, then sort the vector, which returns a list. So we're going to have to turn it back into a vector. Well, we can do that all in one line. The map version is much easier. We're going to just increment it with the default value of zero. So if it doesn't find it in the map, it'll start at zero and then increment. Because maps are easier that way. And then when we get to remove, well, we have to do a linear search. So I just wrote this loop to go through the list. I'm not going to read all the code. Just compare it to this, where in the map version, you only have three lines. All you have to do is you check the one case because you want to get rid of the zeros. You don't want them in the map. So you got to check if you're at one, and you're just going to remove it from the map. But if you're at more than one, you're going to decrement. Okay, so all of this is to say the implementations will help you figure out which one to do. You have a lot more information about what are the trade-offs.  But with the map, there was maybe a linear thing where you had to sum up when you did the within limit to count the stuff. But everything else seemed much easier. But I think as you get better at programming, you don't even have to implement them. You can just look at the signatures, just one at a time think, oh wait, that's a linear search, huh? Because I'm on a vector. This one, that's a sum, a linear sum. Do I have to do that? And this one is a linear search too. And you can kind of weigh all this in your mind, just looking at the signatures. So that's the focus of level two is looking at the signatures without the implementation can give you a ton of information if you've got some experience programming. And if you don't, you can just always implement it and see which one is more complicated. Okay, so another important idea that I almost left out but needs to be in here is that when we're doing operation modeling, we want total functions. Total function is a function that is defined for all valid arguments. And by defined, it means it doesn't throw an exception. And it doesn't do some undefined behavior. If it looks like you can pass it to that function, you should be able to. And I don't want to get into a whole debate about static versus dynamic typing here. It usually what happens is static types correspond to the notion of valid argument, but not always. Sometimes you use an end even though it shouldn't accept negative numbers. And dynamic typing, you don't even have checks. You just have to rely on common sense. So just as an example, there's this issue with remove. What if we try to remove soy from a coffee that doesn't have coffee? Or we try to remove soy. Yes, that's why I said soy from a coffee that doesn't have soy, right? It's got no add ins in it. What do we do? There's actually three options. There's always only three options. One, we can restrict the arguments, meaning we can somehow restrict that this add in has to be in the coffee. We can augment the return value. So we can say, well, sometimes you're going to return nil. Or we could change the meaning. So let's look at this. So the first one is restrict the arguments. So we could just say that, no, this is not even allowed. Do not call this with soy because it's not in the add ins list. It's undefined. It's not undefined. It's not a valid argument. So somehow you have to do a check beforehand. You're right. So you could do this in closure. You can make a precondition. And you could say that how many is going to have to be positive to call this? So what you're doing is you're making some combination of arguments invalid. You're forcing the caller to check the arguments before calling. There's no other way around it. This is going to throw an exception if you don't check beforehand. And it makes the function total though because you've changed the notion of valid arguments. So that's possible. It's a possibility. It's usually not the best. Usually not the best because you're just forcing an if statement before. What's the point of that? And you're always going to need to do it anyway. The second way to make something total. Are you all familiar with total functions, by the way, the concept? Have you heard of this before? We have heard it well. It was the first time I've ever heard of it. First time? Okay. So this is a function. This is a concept in math. So it's also talked about in functional programming. So this isn't something I'm making up. Yeah. Okay. Let's keep going. So you could augment the return value with an extra state indicating failure. That's what I did here. You could say, well, sometimes we're going to return nil if we couldn't actually remove the add in. Okay. And then finally, we're going to force, oh, and then this forces the caller to deal with it after. So you got to have an if statement after the call to handle that nil value. And that's not the only way you could handle it, but you always have something to handle when you augment the return value. Okay. Finally, you could change the meaning. You could say, listen, we're just remove. Yes. Like it doesn't really correspond to anything in a coffee. You can't remove soy from a coffee that doesn't have soy in it. But remember, we're not dealing with coffees. We're dealing with descriptions of coffees usually for making an order. And so if you add soy to your order, you can remove it. And what does it mean to press the remove soy button on the POS you know that the server is using to punch in your order. They press it one too many times. There's no soy in that order, but they still pressed it. What does that mean? Well, it should just be a no op. You're just saying that some combination of arguments return an unchanged coffee. It's just a no op. And then the nice thing about it is all checks are contained in the function. You don't have to make it an error just because it doesn't seem like you want to do it. And some languages have it.  But like in the 80s, some of the languages, if you had a string and you said something like remove all or replace all T's with S's, but it didn't have any T's, it would throw an error, right? And that's kind of like we think of that as ridiculous now. Like if you know there's no T's and it just like shut up, you know, just deal with it. I just wanted to remove all of them. I didn't need to check first to see if there were T's because that's what you're going to do. You're going to write a wrapper function that checks first and then removes them if it found any. So might as well just make that part of the domain model. Okay, another example of using total functions. I used this the other day actually.  Like there's no way around it. You've got to deal with them. So you can't, there's some things you can't do. You can't restrict the arguments to get rid of a timeout. Like it's out of your control. You can get rid of some things, right? Like if there are some known like query params that you need to use and some that you can't use, like you can restrict those but timeouts, you can't, you can't avoid them. You can augment the return but you can't change the meaning. Like the meaning is like make this call. So there's there's no way around that one either. So we can do number two and I do this often. You have a, you augment the return value by having different statuses. So instead of throwing an exception if there's a 500 error, you're going to return either a map that has a value. So the key status is going to say success. And then it's going to have the value and whatever JSON value comes back from your API, or you're going to have status error. And then there's going to be a code and a message. And of course, you might want to change this into an exception later. So you have this function called value or error that takes the response. If it has if the value if the status is success, you're going to just pull the value out and return it. But if the status is error, then we're going to throw the exception at that point. So I like this because it separates out what you want to do with it because at some points, you're like, yes, I'm in a safe place. I'm doing a lot of IO. I just want to throw an exception and get out of here. But other times you don't you want to actually look at it and examine it and you don't want to be dealing with tries and catches. So when you're modeling operations, you want to have a precise, complete and minimal set of meanings. These are the kinds of values that you want to converge on. You need to have totality of functions because you're going to be building on it later and you don't want to have to deal with all those if statements of checking the arguments and stuff. I believe that there's some encoding, some data models where it will be impossible or very complex to implement some of your use cases. And so you're going to have to revisit your data model and you want to do that sooner rather than later. That's why you should look at your operations first and try to implement them. Okay, we've just got one level left and this one is the shortest in the slides. Quick question before you move on. Are you going to cover in your book or touch on dependent types as a fourth method of handling this sort of solution? It's a sort of like pushing the restriction of the arguments to the type system. So I will probably mention dependent types. I don't think of it as a different way from the three. What it's doing is letting you do these kinds of, it's doing the restricting the arguments in a smarter way so that in some cases you can avoid an if statement before. So you could write a type that says this function takes a coffee and add in has to be in the coffee. And in some code paths, it can tell that that add in is in the coffee. But if you're dealing with a POS where people are pressing buttons to the computer, it seems randomly, there's not going to be any code paths where it can guarantee that it's in there. Or not in that loop that's going on, that event loop of the button presses. So you're still going to have to have an if statement. And that if statement will carry through. The if statement will check that it's in there and then the type system will be happy. Yes, you checked. So I know in this code path you're satisfying the type. Yeah, they're just better types. They're not, you know. So Eric, I have another question. Yeah. Okay, so confused about the relationship between level two and level one, because if we went, you go back a couple of slides through the, yeah, so removing the soy from coffee that doesn't have soy. So I guess part of level one was you're trying to make this case of like trying to model the real world more closely. But then, but then this part seems like a big concession for a bit of a turnaround because you said like, I think in real life you actually would have to check whether coffee has soy before you remove it from coffee, right? So the way that you, I guess the best way that you came up with was doing the checking internally for the function, right? So that the caller doesn't have to do the if statement before or after. Right. So I guess I'm confused what the focus on reality thought us in this case. That's a good question. Yeah. So remember we're not trying to model coffees, right? We're trying to model information about coffees. We're trying to model coffee orders. I mean, usually that's it. It's ordered before it's ordered, right? Or after to like look at reports of like how many soy coffees were ordered. So we're dealing it with information. We're not dealing with coffee. And so this real world that this thing has to deal with is the cash register, the ordering system that the server is pressing on. And in reality, they are going to press the soy button one too many times and remove more than what more than, you know, all the soys. And we're going to have to deal with that. And so we're just baking that into our model. Okay, so operations like the reality is different. Yes. So reality can't remove soy from coffee. You dump it out and make another one. No, but can I jump? Yeah, because I think this also hits on, unless I'm misunderstanding what you're saying and asking, this hits on 0.3 of change the meaning. So it's, it may not be about removing soy. It may be about ensuring that the coffee doesn't have soy in it or ensuring that the coffee only has one soy added. And that's a different thing from the process of removing soy. Hey, Claude, can I jump in here for a second? Of course. This entire discussion is completely different depending on whether you're writing the inventory system or the point of sale system. Right? Think about that for a minute. If you're writing the inventory system, you don't want to count all those negative soys, right? Because they didn't do anything in the real world, right? So the thing I would say is that you really need to understand the part of reality you're modeling because we don't, we don't model all of reality. And if you ever tried to write one of those systems where you do all of it at once, it's complicated, right? Imagine trying to keep it straight. Like you need to know what you sold, right? Somebody cares about that. But somebody else cares about how much soy added they need to order for next week, right? So I think all these things you talk about are really important. They have to be plugged into what the system is doing because there's quite a few different ways to look at a coffee shop. No, and I think that you're making a really good point. So there's a thing that I say a lot and I stopped saying it because people were like, it's so trite, but it seems relevant now. I wish that in like the OO modeling world, instead of calling the class person, they should call it person record because it's like a record of some information about a person that your software cares about. It's not trying to simulate a person. It's just trying to group some data together that happens to be related through the person. And it's a record. And in the OO world, at least the way I was taught, I feel like they have to teach it in a certain way. They need to babify it as like paint by numbers or it's like finger painting when we're taught programming in school. But eventually, you have to just discard that and look back at the reality. And the reality is we're not simulating people in a little marionette style. We're shuttling information around and we need to, I don't know. I think as an industry, we need a reckoning with that. We shouldn't call it coffee. We should call it coffee order. It's a piece of information. It's not a coffee. Anyway, thank you. You're just writing a simulation. You're actually trying to simulate a person to the object person matches. Right. It's a model, right? It's a model. That's right. But we're modeling and so we're using the tools that we would model a person to model something synonymous. Yeah. I used to get upset with people because a place I worked, we had to create employee function. And I used to argue that none of the people in the room had ever created an employee, but I had because my son happened to work for the same company. And oddly enough, that is true again. I always like to use the example of when you go to a supermarket, you don't send a buy message to a broccoli. But that's how we're taught, right? Like, oh, it's the verb. It either goes on the person or it goes on the product. Like, no, that's not what's happening. What's happening is I put this broccoli on my shopping cart and bring it to the cashier. There's an information transfer going on that is what you really should be modeling. Anyway, maybe that's what my book should be. It's just a long rant about that stuff. I'm sorry. What's your name back there with the glasses and the drink? The blue shirt that asked the question? No. Yeah, behind Claude. Yeah. Oh, Anthony. Anthony. Yeah. Does that answer your question? Does the reality of, let me ask it another way. Does the reality of a coffee order make more sense? Don't ask him about reality. He's a philosopher. Okay. So we're not modeling a coffee and we never were, really. So I guess that was my disconnect because I thought that that's what the domain, the part one was. I thought you were, you know, you wanted to get into reality. In some sense, it is the reality of the business of selling coffee. That's why I called it the conceptual model. It's like, what's happening in your head? You need to get that out of your head and into your software. And the challenge, let me, before I talk about the challenge, let me give you a little scenario.  So you're kind of interpreting this menu as a possible set of coffees you could order. So that forms your conceptual model.  The server, so you're transferring information vocally to the server. The server understands your words and forms a new model in their head of what you want. Then they press all the buttons. So that's, well, let's say they don't press buttons. So let's not involve computers. They write it down. So they're again encoding it back from a conceptual model into some information recording, you know, words on paper. They hand it to the barista. The barista reads it, forms a new conceptual model of the coffee that you want, then makes the coffee. That's also magic. So then you get this coffee, okay? So they're encoding their conceptual model of your coffee want into a real coffee. Are you including the steps to translate from their mental model to using the machine? No, that's magic. The machine is a different model. At Waterbird, you show them, you say, I'd like to order, and then they start typing. And you've got to wait. You don't say a single word until they stop talking because they're logging in. So this is a great one. They're logging it. The machine, it takes them like 30 seconds. If you say any words, they're going to forget them. So next time they're a little better, but you have to like one at a time tell us, I want this hamburger modified. I want rare. Sorry, y'all. And I want it no fun. So you have to wait in between because they are just typing away. Can I say the model of where your ordered food is flawed? You need to go better when it's very high quality. I highly commend it. There's one here, but there's actually two nearby. Right. So what this is, to me, what this scenario is saying is that there is a series of encodings and decodings of conceptual models going on. And eventually, you get your coffee. And you can know if it's right because if you remember what you ordered, you can compare. You can read the coffee. You can look at it. Oh, yeah, it's got the milk I wanted. It's the right roast. Smell it. However you decide, you taste it. And you compare it to your mental model and you say, yes, that is the same. So there's a final decode at the end when you drink it.  And it's got a conceptual model that the programmers had when they coded it. It's kind of, let's not go there. But because it doesn't actually have a conceptual model, we know that it's just bits inside the memory. But then it can encode it back again onto a screen for the barista to read. And so you can, that's where you would insert the computer. And the reality is that ordering process. That's the use cases that you're trying to model. Okay. So now I forgot where I was going to go with that. But I feel like that's an important kind of model of models. Like this is what's going on. You're decoding and encoding. You're decoding some information that's like recorded somewhere into a model inside the machine's memory. And then you're able to re-encode it. And the fidelity with which you can decode and re-encode is important because it's a game of telephone. You got hops going on here and you want to get the right coffee out at the end. And so you need to have no like ambiguity. You need to have no, you know, bad, invalid coffees that are getting being able to be written in that process. So yeah, okay. I hope that helps. Like there's a reality going on there. And that's what you're really trying to see. And there's two steps. There's the, when you walk into a Starbucks, the menu is, you know, fairly well designed. It's good enough that it serves the business's purposes. But like I said at the beginning, before Starbucks, like coffee was just some big amorphous blob of stuff. And you could walk into a coffee shop and be like, can I have like a little darker roast? No, a little darker than that. You know, you could just have infinite variations of roast, infinite sizes, infinite add-ins. You could put whatever you want in coffee. Why did they choose those five, right? And so it takes a different kind of skill to walk into one of these domains and really see what's going on, right? Really be able to say, oh, if we could write down a specific roast, then we could serve that to people. And that's different from the size of the coffee. And like it takes a real skill to do that. It takes a lot of knowledge of the domain to be able to parse out those concepts from it. So there's, that's the first step. And often it's done for us because we start with like legacy software, right? We started a new job at an old company. But then there's the second one, which is you take the conceptual domain, which has already been fairly well established and cut up into concepts and discretized and everything and turned it into an encoding. That's a second step, right? And that encoding and decoding has to be, it has to be very truthful to, you know, it has to be able to, it has to work all the time. Encode, decode. You don't want errors in it. Let's put it that way. Does that make sense? Am I, I feel like I'm losing people here. It seems like you could measure, they measure the wrong, you could compare different models based on how many, how many, I guess, transformations you have to make. Possible states? No, no, no. Transformation between different models. Ah, between equivalent models? Yeah. Well, okay. So in a previous slide, you showed the version of vector and the version of maps. And the real difference was kind of the complexity of the transformation. But how much effort did it take to transform from one together? And if you take that up a notch, you can judge the entire order of coffee between how many, well, from a process standpoint, you say steps or people, but you can also judge it based on how many mental models you have to jump through and transform between and compare equivalents. So that, that slide that you just put up, I think is exactly, I was working on this issue just last week for my own stuff. And I think it's about the number of states. Total states, system or total states? Of the encoding, yeah. So like, so you have the conceptual model, basically how many coffees are possible to order that are, you know, different versus how many can I write down in my encoding. And it could be that there's some coffees you should be able to order that you can't write down. That's possible. And that's a problem, right? Because your business wants to have people are going to want to order those things. There's going to be some times where you have more states that you can write down more states than coffees that actually exist. Right? So like, you know, you could imagine something where you could say, well, we don't have small dark roast, right? And so, well, now we have this, we have to have an if statement in there to like, disallow that from being ordered with throw that in our validate function. And then you have, sometimes you have ambiguous, you can write the same coffee down in multiple ways. And that's what the normalized function is for. This is useful. I just want to say I've worked on C sharp projects, we've done dvd on the book and it's in this condition. Anyway, we've done it. And I think your explanation is interesting. Can I can you clarify what you mean by conceptual model? Because here's the deal work with a lot of people and they say, I've got this great conceptual model. And then it's incredibly not reflective of reality. What are you working with social scientists? Everyone who has opinions about software and it's probably for me and I'm blind to it will create them. They'll be like, this is great. My conceptual model is an XML based rules engine, which will support all these cases. Or they'll say something like, you know, I, I have a conceptual model that handles coffee and you can order a soda and you're like, well, the sodas don't exist yet. They're like, well, it couldn't sell the business on selling sodas by implementing a model. Class soda extends or drink. For what I understand, your conceptual model is minimal, right? Like if this is like the minimal set of possible things you could order. And if your conceptual model doesn't match that, then you need to go back to your conceptual model and think about how to make it more like reality. This is a rough real quickly and ask if we can let Eric finish his off and then go into this. Yeah, that might be good. It's very close. Very close. It's a good question though. What's your name again? Peter. Okay. Good question. And I do want to talk about it because I think there's a lot there that that I need to work on in my book. All right. So last level. So, okay, okay. What happens is you realize, wait a second, like I've implemented all the use cases, but that there's still more because people are going to be like adding and removing and like random orders is never just one use case. The use case was add soy, but like they're going to be adding soy three times and then adding almond and removing soy and like we need to model the composition of these things. Like how do they work together? And so that's what the focus of level three is. Look at the composition of functions. And I'm calling it algebraic modeling and I hope it becomes clear why in a second. So here's a little test we could do. So you have this coffee. It's small light roast, no add ins. I'm going to assert that that coffee is equal to the coffee that I get if I take that original coffee, add espresso and remove espresso. That seems pretty fair, right? Like if I added thing and then remove it, I should get the thing I started with at the beginning. And so we can actually replace that. Oh, I put a bracket there. Shouldn't it be a bracket? We can replace this espresso, what was here, espresso with a variable. And we'll say it shouldn't just be for espresso. It should be for any of the ingredients, any of the add-ins we could put in. So we're just going to select a random one and use a variable, right? So I'm replacing, you know, just like in math where if you replace a number with a letter, with a variable, here I'm replacing a specific add-in with basically any possible add-in. And that should still be true, right? But it turns out I could actually construct a random coffee too. It should work for any coffee, not just that specific coffee I wrote. So I'm replacing that specific coffee with a variable that is some random coffee. Okay, so that's why it's algebraic, right? And we should be able to say this. And, you know, depending on how far you want to take this, how much assurance you want that what you're doing makes sense, we could say, well, it's not just for adding and removing a single ingredient. I want to be able to generate a random list of ingredients called add-ins. And I'm going to take my coffee, I'm going to add all of the add-ins to it. This is the coffee width line. I'm going to reduce this add operation starting from coffee, add all the add-ins, then I'm going to remove them all. And they should be equal to the original coffee. Then I could say, well, but you know what? I could go even further. And I could do add-ins prime and shuffle that list. I should be able to remove them in random order, not just the same ones, they're just in a different order. And I should still get the same coffee. Okay, so this is the kind of reasoning you do at this third level where you are, excuse me, looking at the relationship between add, remove, and how many. So in this case, we're saying how many of this particular add-in, whatever it happens to be, it could be any add-in. This is the first line of code here. How many of that particular add-in are in the coffee? It has to be less than if I, oh, I should have had an how many in here. Let me, I stopped sharing, hold on. Let me share it back. This should have a how many around it. And this should have a how many. Oh, lovely. There we go. Debugging my slides as I present. Okay, yeah, that's right. All right, so then this one I should say, if I remove an add-in, there should be fewer of those in the coffee. So this is, you can see how this is starting to have a, you're starting to talk about the relationship. How do they relate together? How does adding and removing add-ins relate to how many and to, and to each other? So what about relationship of add with itself? Well, I can say, you know, I stopped and think about it and I say, well, if I take a coffee and add A and add B, it should be the same as if I take the coffee add B and add A. Relationship will remove itself. Same, same with this. Okay, so that's actually my last slide. So that's it. Now we can, now we can have a fight. Actually, real quick on this level three before you move on. What is the benefit? I think there is one, but what is the benefit of doing the algebraic model? Right. So I should have written that up at the top. I'm going to jump back to a previous slide, this one. The goal of level three is to support unforeseen use cases. Generalizing? You're generalizing it. So you're saying, look, we thought of the use case of adding an espresso and removing an espresso, but we didn't think of the use case of the server accidentally leaning on the remove espresso button and like adding 50, right, or removing 50. And we can, we can accommodate it. We can make sure that that's possible by just generating random, I mean, this is property-based testing stuff, but you generate random sequences of operations, random ads and removes and test them, make sure it works for all those cases that you wouldn't have thought of. So if we are modeling a subset of reality, is the third step effectively sort of, I guess, simplifying the implementation of that model and through that simplification, also generalizing it to you for more use cases. Because effectively you could write a function for each transformation, like remove for coffee, remove for everything else.  The cost of implementation has gone down, and the speed at which you can model more of reality has gone up, and you can sort of model more scenarios. So is that effectively a way to, I guess, to my previous point about measuring a model based on the transformations you have to go through, is that effectively making a model cheaper and thus faster and easier to implement as it scales? I believe it, I believe I want it to be a way of making it cheaper and more robust, basically. That I hope I can show how to do in a general way. It does, I believe that thinking in this way of focusing on the composition of the operations, again, without implementing them, you just say what must be true, is a way of thinking about it in an algebraic way, because you're using variables. So you don't really know which coffee you have, so you have to think about what can I say about any coffee that would be passed in. That is the idea, is to get people thinking that way, because if they do it at all, it's ad hoc, and this is what I see, people have already decided I'm going to use an array for this, and so now it's simply like, oh, I have to implement this new method, but I've already got an array, like how do I get it done? They can often get it done, but then it's unclear, just by brute force, they can figure out, and they're testing like five or six, maybe even 20 test cases on that method, but they haven't ever thought, how is this thing going to be used in concert with other things? They're simply trying to solve the next test case, and they're usually very simple, and they're hindered by the previous choices of data structures that they have, and so they're dealing with a lot of constraints here when they really should be thinking, what am I trying to do, and what do I want to guarantee about that, and if they're thinking at that level, then I think that that's where software design wants people to go, but it isn't really pointing that way. I think that's my hypothesis right there. I hope it answers your question. I want to jump in here real quickly before we start include and move to the broader discussion about the algebraic modeling. I have two questions. One more specifically on algebraic modeling is, how do you figure out which behaviors, operations, properties you're trying to model? I don't think there's one way. I think that it depends on what you're doing, you know, if you're doing something that you don't understand, you're a programmer, you're just paid to write the software, you have to go talk to experts who do understand, and try to get around the curse of expertise that they can do this, but they're not very good at explaining it, and so you have to draw it out of them, and this is kind of an answer to Peter's question. I think that it really helps, I'm trying to make it a stronger statement, it's too late for me to do that. It really helps to write the code down, to make it concrete, that a lot of times what happens is people stay in the conceptual model and they've never written it down in any kind of formalized way. Architectural astronauts is a word for that. You just got all these ideas, but they're untested against reality. One part of the process or the skill that I want to show is that you can write it down in code and actually implement it in a very naive way at first and get a prototype really fast. That prototype, you could even refactor it, not even hard transformations into an actual production application if you follow these steps. If you do this little bit of analysis before you choose a data structure, and before even that, you write down the signatures of all the use cases that you want. It's code, remember, it's all in code. And then of course before you do that, before you figure out how to implement it from the signatures, you actually look at what are the laws and the properties of the operations that I want to maintain. If you do that, you're always in code. What I've showed is always code and you can show the expert, look, is this what you mean? Or you could debug with the expert set. You can take what they said, build a model of it and say, this function isn't really total. Am I missing something? And you go to them and they say, oh, yeah, well, there's this other case that's like, I didn't tell you about that. Oh, well, that makes this, I could encode it and that would make the function total. I'm hoping that it gives... All right. So this again, answering Peter, I read the DDD book and I felt like there's a lot... The guy who wrote this knows what he's talking about, but is just like blurting out everything he believes and hasn't sat down to turn it into something real. And of course, that's why there's like conferences about it because people are still trying to figure it out. It's a whole industry. It's a whole industry. Yes. Like, what did he mean? Let's talk about it because it seemed good at the time, but I'm still trying to understand it. And so... There's only two good chapters in that book after looking back at it. Oh, there's so many conference talks, which I've watched. I have watched all of the conference talks and they were more informative than the book I've been told. Yeah. Yeah. I would know. The book is a mess. It's a mess. I mean... If you were designed, that was the part he still stands by. Are we going to end the recording so we can get to it, but so... The thing I want... I have a few questions with the recording and then we'll end it and really go at it. I'm not holding back anything. Can I interrupt here for a second? Because after the recording's over, I need to ask Peter about a comment he wrote and some code. Yeah. The thing I want to do with this book is to give people the actual nitty gritty on the ground. How do you build the model? Because domain-driven design, it has a few good points, like go talk to an expert, make a prototype. Your words might mean different things to different teams. There's good ideas in there, but the nitty gritty of how you do it is, I think, just not described at all. Or it's very cryptic and it's very object-oriented as well. So I'm trying to make it less cryptic. Here's the nitty gritty of how you do it and throw in stuff like what I'm calling runnable specifications. If you start with the function signatures, that you want, instead of just having to refactor based on the arguments that you have, you can actually make it look like a spec. You can just write your code, write your spec and run it, basically. So I'm going to thank you very much for the talk right now. You're welcome. Thank you. We are going to do applause and then ask some questions. So thank you very much. So a few questions on the recording and then we'll stop the recording and really go at it. So who wants to ask a question on the recording? I've got a few, but... I have a question. I don't know if I can jump in. I guess it's maybe not so much a question. I mean, so one thing that I really like, that really appeals to me about this is it feels like it's like the anti-GitHub co-pilot. So I actually like co-pilot a lot, but this is the kind of thing that GitHub co-pilot can't do. And so this is a terrible question because I'm asking you to prognosticate. But what does this say about the future? I mean, I think this is the future. I think this is great. But I mean, what does the future of programming look like that's for people working in programming and code? I mean, is it going to be like high-level languages that do data modeling very well and we pass it off to an AI that handles implementation? Is that out there? I mean, I think it would be cool if you could skip straight to the last level and just say, okay, we've got these operations and this is how they compose and computer figure out for me how best to represent this data so that it's got the right algorithmic complexity, but I could also easily decode it in a JSON. And you just have all these constraints and it could figure it out. I mean, that seems plausible today. Maybe a few months ago it didn't seem very plausible, but I played with chat GBT and it seems to do some pretty cool stuff. All I'm saying is that this seems to be like a good future-proof approach to programming, which I think is great in that sense. Okay. Thank you. I'm sorry. The only thing that comes to mind is the scene from Office Space. It's like, why can't the customers talk to me in GPs? Why can't the business users just talk to chat GBT? Well, they will. Okay. So a question that I had sort of early on when you were talking about basically domain modeling, figuring out sort of what's really going on in your subset of reality. So I do a lot of database design work and database working. And I remember it, so maybe this has been a fair question, because in one of your podcasts you talked about, like, I'm not really a database person, but I use them all the time. But designing a relational database is also very much about modeling the domain. And when I would do that, so I actually was employed where I wasn't a DBA. I didn't do the optimization. I modeled it. And a lot of what I did, and a lot of this was like back in the 90s, was go around and talk to everyone in the company about like, what do you do when everyone modeled this and all get database designer or architect. It was basically a bizarre architect. But yeah, I didn't have to, I didn't have to optimize anything. I didn't worry about it in the same way that stuff, which was great. Right, right, exactly. And so one of the big issues you're going to deal with database modeling is because it's really expensive to change it. And anytime you change it, everything on top has to change, right? And they've invented all these, you know, intermediate layers now to sort of try to manage that. Tons of people then end up trying to abstract out the database. And so like you get these wonky, I've seen it like wonky databases where they're like column type, column value, right? Six normal form. And so I guess there just seem to be sort of a resonance when you're talking about the main modeling about sort of getting to the truth in a sense as something that's fundamental. And I'm wondering about that issue of you get it wrong, right? It'd be great to fully be able to model what is a coffee, but we get it wrong. And then you get all these sort of qualifications and this mess and building on top of that. And I guess I don't have a specific question except do you have thoughts about that? And how easy is it to fix your domain model? Right. So about getting it wrong, I hope it was clear, it probably wasn't, that the whole level two and level three are about getting as much information as you have at the moment available to you so that you can make better decisions about how to data model. Right. So before you jump in and say it's an array or it's a vector or a map, hey, go through your use cases, like just one at a time. What is it like if I use an array? What was it like if I use a hash map? Oh, this one does a linear search. Maybe hash map is better for this operation. Just like getting all that information to help you constrain the problem to like the right model. I mean, there still could have choices, but it helps you gives you fewer choices that would work. And then if you go to the third level, you're seeing even more like, oh, we're going to have to be adding and removing these things really a lot. So maybe that changes it somehow. So I think that that's trying to avoid getting it wrong. And even maybe reveal stuff that you wouldn't have seen like, this function can't be total with the way I've encoded it. And so I should, you know, that that probably wasn't apparent when if you just sat down and tried to draw your tables, you know. But then of course, yes, I think that you were right about, like, often we try to draw the tables in the abstract, and we haven't really analyzed enough of the domain, we're kind of like, oh, this is a person, of course, it has this, this, this, this field. And, you know, really, is that true? Like maybe a person has multiple addresses, don't just put an address right on the person record, you know, right in the person row, like a street one, street two, like might want a little bit like a join going on there. Okay, that said, I think that there's also this idea of volatility. And I'm, I'm calling, like, when I say volatility, I'm talking about predictable volatility.  Can I hard code these three sizes in there, and like bake them into the tests and everything? They're gonna say, oh, yeah, no problem, we have three sizes. But if you ask them, how often are we going to get a fourth size or one of these change? They might tell you, well, you know, we have this special where we have like the mega cup. Every six months, we introduce it again, like, aha, you see, like, it's not so fixed, right? And do you want us to have to do a commit and a deploy every time you want to introduce the mega cup? And so I think that I think that there's a, there's like, I think the best I can do is point people to show them that, like, there are ways of modeling that are easier to change. Like if you put it in the database, instead of hard coding it, it's easier to change. So like, when you're looking at, should I use a, should I hard code this as a type, right, which you might do in Haskell? Like, think about it, wait a second, that's, that's fixed, like I have to do a deploy to change this. Maybe you should go ask your boss or whoever, the product owner, whoever it is, like, hey, can we, are we going to do that? Same with like the ingredients and stuff, how often do those change? Maybe they're more often throw them in the database. Um, yeah. So that's a kind of like, that's not getting it wrong as much as looking ahead to the future. I feel like this is another thing I didn't mention that software design gets wrong. It's like changes a boogeyman that's just like, Oh, no, it's requirements are going to change. Like, yeah, but did you, did you ever think like maybe like you could figure out some of the ones that are going to change ahead of time and like model that as part of your model? And it seems to me that they don't, they're just like surprised by everything. So one of the lines, um, and actually we discussed this briefly and I'm thinking about over email is in my own work when I'm trying to model social white, one of the things is trying to distinguish between what is absolutely fundamental and cannot be removed versus what is transitory or ephemeral in some way. And what I found is that's a really fundamental difference. When there's something that I say, this characteristic, you cannot remove from whatever I'm trying to model. That helps me make that distinction. Yeah, I like to think about like, is this your business? Or is it all coffee business? Right? Is this, is this a library that anybody could use? Or is this like, just for you because you like to have, you know, a certain kind of sale, certain kind of promotion. And yeah, so it distinguishes two levels, two layers is the domain layer and your business rules layer. Well, and I think that that's a distinction that a lot of people have trouble with. It's like, what is fundamental about selling coffee and what is just what we do today, right? So it's a humongous size enrollment period. That's what you add support for. And then you'd have like, from February through March, and we tell people it ends at March, but it actually in April 1st, because you got to give them a few hours in case they're past midnight. So put that in your app, you've got a humongous size enrollment period. You can have it, but only large and then you can have a humongous size available for a limited time. So your hard code is special. No, no, no, it's data. They enter more enrollment period. Now, can you modify the enrollment period? That's a question. I say your hard code at all and speed up your, your, uh, one middle process because it is soft. We've got a radical. So, wait, can I interrupt for a second? Because the code I've been working on at my day job in Peter's comment in the code from years and years ago, by the way, Peter, do you remember writing this causes an N plus one problem, but we have bigger fish to fry? Because you wrote that for a while. I just want to tell you, I'm frying a much bigger fish than you ever imagined at that point in the code. I also want to say roughly around the time that column was written, we had checking the number of items in the cart, uh, ran something like a thousand or a billion queries. I can't actually remember the number. Because these are a thousand or a billion queries that hydrated the entire domain. Well, so it's not that bad, but I am making the N plus one problem in particular worse, but it's for good cause. But here's how this relates to the discussion that we're having because so my view of the world is really worked by the fact that most of my career has been working with organizations after they got it wrong in their domain model, which I completely agree about the tenant. The domain model is generally pretty set, right? And the business world's changed. So, okay, I don't want to like give anything away here, but imagine that you were selling products, right? And maybe you were going to sell them on different sites, right? And so you might have a description of the same product, a one website that's different from another website, right? You might even have different prices and all this other stuff. You might think it's a good idea to encode things so that you test strings for equality. But here's, here's the big takeaway I want to tell people. The closer the thing you're doing is to the computer, the farther it is away from reality. So, strings don't exist in the real world. They're entirely something we make up as software developers to help us deal with stuff, right? So, string equality is never actually the requirement. And if you ever get to the point where you have to describe things in multiple languages, that will bring home to you in great detail. Anyway, so I would encourage people where they do their domain modeling and they're doing this stuff. The functions that are like, there's a whole list of functions that actually make sense in the real world. People actually do process lists from the start to the finish. Like, that's a thing people do, right? However, people don't assume that the characters B-L-U-E always mean the same thing, right? Because it's the color, it's a color. And if it's a mood, right, it's a mood. Like, I'm blue, I'm depressed, right? And so, just when you're doing all this, I think it's a good idea to kind of stay as far away from the array, string, right? The closer you get to something fundamental to the computer, the further you weigh you are from reality. Unless you're like, modeling a computer. It's a whole different thing. The model's all domains. Okay, thank you, John. So off the rails at this point. Just settling some scores. Okay, sorry. Stop the recording and then we can go totally off the rails. Thank you so much. This is great. Thank you. Now, give me a minute to figure out how to actually stop the recording. Wait, wait, wait. You hadn't stopped the recording? Don't keep. I don't really care. All right, everything I talk to when they say, we'll edit this out. And they're not joking? Like, we'll edit this whole part out and they're not joking. Stop recording. And then you're listening to it.


All right guys, we're out of new place right now pick up this chatter bait try to give it a try Super clear water in here a lot of grass. Oh Man, there's some decent fish in here. You guys should see how crystal clear this water is It's almost unbelievable how clear That was close dude Jesus man, is there anyone else out here?  Hey What the man? Dude, what the what the Jesus Christ? Did you see how close that bullet just got?  Hey, I'm getting out of here man ain't worth it