Two and a Half More Domain Modeling Lenses

I was honored to speak at HFPUG again about the topic of my book. This talk is a sequel to this one and this one. Watch those first because there is some intro material I don't repeat in this talk.

Download slides

Transcript

So, I want to welcome everyone to January 2025 and our first meeting of the Houston functional whole programming user group for the new year, as is now our tradition. We have Eric Normand speaking to us this, we believe this is the fourth time he has spoken to our group and he now always speaks in January, we do this because it is really, really cold where he is in Wisconsin and not as cold here and so, you know, we like to harass him a little bit about that. So I will turn things over to Eric, Eric, welcome, it's really good to have you back. Hello, thank you, it's good to be back. I really enjoy this tradition when Claude invited me for this time. I was like, "Yes, I tend to use this as a way to work through ideas that I'm working on for my book." So this is the third year I'm talking about domain modeling and every time I learn something, it's a good group and I don't have to go outside for it because it is very cold, they can just stay in the warm house. So I always do get envious when I see people in t-shirts. Luckily, I don't see a lot of t-shirts today because it's colder down there right now, but it's very cold here, just so you know. And it's good to see you, thank you for having me. This is a great group, I really enjoy this. Should I start my presentation? I'll share. Yes, this is your time. My time. All right, y'all can see that. Yep, looks good. Okay, so this is called two and a half more domain modeling lenses. Like I said, I've given two other talks on the domain modeling. It's topic, about a year ago after, I guess it was two years ago, after giving a talk here, I decided to organize everything into lenses because the way I was talking about it at that time in this group, people wanted it to be, or they thought they were interpreting it as me giving a process and I was not giving a process, that was the furthest thing from my mind is not what I wanted to do. So let's just, let's get into it, we'll talk more about that and what the lenses are. Oh, sorry, I got to go over here. All right, before we get into that, people mentioned my book, so I quickly threw up this slide. This is a book about functional programming. It's for beginners because I felt like there wasn't a book out there that I could recommend to beginners, everything was too advanced, basically they assumed you knew too much. This one starts very, at the beginning with pure functions and what they are and why we do them, we spend maybe four or five chapters just on pure functions and immutable data. So check it out, this first link is going to take you to Amazon. So if you like Amazon, that's the one I prefer right now to send people to. But if you, this one takes you to the Manning website and that one you can get 50% off. So if you want 50% off, you know, use this coupon code at the Manning site. It's come to my attention that a lot of people don't like Amazon, so I'm putting up the other link. All right, that's enough shilling, let's get on with it. So domain modeling is a kind of software design and software design is not easy. It's like this multi-dimensional search through, or the search through a multi-dimensional space. You've got all these choices to make and not only do you have to make a lot of this, it is the choices affect each other. So if you make a choice, you know, to like use a hash map, well, that means it's going to change something over here that now you have to make a different choice. And so it's really hard, it's just a really hard problem. So I have this hypothesis that because you have to make all these decisions, really what you're trying to do is get good information and the source of that information is the domain. That's what domain modeling is. It's just looking to the domain to help you make the right programming decisions. I'm trying to define software design as broadly as possible. A lot of software design texts are talking about like code quality or some kind of ephemeral aesthetic that you find in the code. And I really want to talk about everything from the algorithms you choose to how you structure your application, to if you use a for loop or a while loop, all these choices that you make, that's all software design. So this is this graphic, I'm trying to illustrate what the lenses are. Like each lens is giving you this little peak at one aspect of a whole. There's a whole out there. There is a whole design that you're trying to get a peek at. And I can only show you a little bit at a time because it's too multi-dimensional. You can't see it all at once. But hopefully, if you get enough lenses, enough peeks at it, you can kind of get the whole picture. That's the idea. The main sort of vision behind what I'm trying to teach is that you will wind up with a library that is very expressive for your particular domain. And it's so expressive that you can say anything you need to say, any scenario you can come up with in your domain, you can easily write out an expression that will represent that, that will encode that scenario. And if you have a good, if you had that good library, you're not going to have to code around it and all have all these corner cases that you're handling with if statements or what have you, all the other code that you have to write to handle the bad model. And so sort of my, this is another hypothesis that a lot of what people call bad code or messy code is just they have a bad domain model that doesn't properly encode the abstractions that they need. And so the best way, you shouldn't just refactor it, you should actually try to find a good domain model. All right. So these are the lenses that I've got for my book. I didn't mention I'm writing another book and these are the lenses that I'm working on. I put them side by side like this because the ones on the left are actually sort of building blocks for like how to build a domain model. And the ones on the right are like concerns that are like external concerns. This might not be the right way to put it, but it's something about, you know, these aren't like the way these aren't things to build up a domain model. But they're things that you have to think about while you're building a domain model. So these are all of them, I gave a talk, this was end of 2023 that had these three lenses. So if you want, this is, I'm not going to go over these other lenses. So you should find that talk and watch those. This one is the one I gave one year ago here at the Houston functional programming group. And these are the lenses I talked about these for. And so there's only a few left. Well, there's actually only two left time and domain. But I also have a much better, I have more things to say about runnable specifications. So I'm, I'm throwing in a half a lens there. All right, so let's get into this is just a, like to explain all the examples I'm using are from a coffee shop, and it's a Starbucks style coffee shop, which has three sizes of coffee, three kinds of ropes, and then a bunch of things, you can get ropes. And here's a base version of the coffee. And we'll, we'll see some more of the stuff. I just want to give you a flavor for the kind of stuff that we're, we're going to talk about. All right, so runnable specifications as a lens. What does this mean? So I mentioned before, the main vision behind runnable specifications is this super expressive library that captures the important concepts, behaviors, rules, data that you have in your domain. And if you have such a library in your code, you, you can easily express any scenario you need to express. And that will help enter your location, that portion of the application. Any application is going to have multiple domains. And the tools that I'm giving in the book is that you do everything in code, and it will lead you to this library. You don't model it in an external form, like in UML, and then have to translate it. You start in code and you end up in code, and so you're, you're constantly moving toward and refining this library that becomes, it's like a good domain model. Here's a schematic of the domain modeling process. So the model, it kind of just exists in your head. It's just an abstraction, and there's the domain outside that may or may not be so clear what you're trying to model. And then you're trying to convert it all into code at the end. So you abstract stuff from the domain. And that just means you're leaving out unnecessary details, things that don't matter to the business that you're running or what have you. And then you're going to encode it in code, right? Now when it's in code, you can do stuff that's interesting, like even just looking at it, you might say, "Huh, that's not going to work." Or maybe you can't see that, but you run it and you say, "Well, it didn't work." And so then you can evaluate how does this code actually encode the model, like, does it do a good job? And maybe it does. Maybe it doesn't. And you can encode it another way, and you can go through this loop on the right until the code is good. But maybe you say, "Huh, well, it kind of does what I thought it would." Well, it's a good encoding, but it doesn't capture something. There's something missing that I need to go back to the domain and learn more about, right? So there's these two loops going on where you're learning about the domain, and you're also learning about how to encode your model, and your model is changing, and your model is how you understand your domain. And you're refining your model because you've got code, which is this formalized language for encoding your model. All right, I want to stop here and just ask, like, what do you all think of this? Any questions so far? I know it's all very abstract right now, but I will have concrete stuff in just a minute. So I'll jump in here and say, one, I think that this is a clear explanation of this process than I've heard from you before, because I think you and I might have had some conversation about this, or maybe you were on your podcast, and I was just talking at your podcast about being confused about the domain versus the model, and where we were all located. What I wanted to say, and I know we've talked about this before, is that the model that you're presenting here is so similar to the model that I use for understanding social research and how we conduct social research, and I can send you a slide. This is that, in fact, from the talk that I gave just last month, that essentially is doing something so similar to what you're doing here. But yeah, what you're articulating here is very, very close to how I understand the process of social research being an interpretive process, basically, to come up with instructions of, so it's not construction, so social research is constructed, and what we're constructing are representations of social life, and what you're doing here is so similar to me at least. So I think this is very interesting. Cool. Cool. Can I, I would like to interject there as well, Eric. To introduce some software engineering lingo here, some terminology, I think, what I understand from this slide and from your presentation is that the model would be, in software engineering, would be the requirements, and then the specification of those requirements, like if you go to very regulated industries, you would want to, every line of code would have to be associated with a spec, with a specification, and you would have to prove that that line of code, what part of the specification for the problem that you're solving is addressing. So I guess that's what you're trying to say, that the model is something that you, maybe not only in your head, but you have, as a written requirement, and further, I remember that a requirement, a specification for a requirement, is that, does that make sense? Yes, so how do, where do I start? So yes, the model is your understanding of the requirements. I've never worked in an industry that was quite so regulated that they could just give you a book that's like, here's everything that your software has to do. And the jobs I've been on, there's rarely anybody who knows what it's supposed to do. They might have vague ideas, and so part of the modeling process, vague meaning they don't have a very clear model that could just be encoded right away. You would need to go through this process of encoding it to realize how imprecise their understanding is. And so you might do this and then show them, right? Do you mean this way or this way, because we need to resolve these ambiguities somehow. And one thing you can do when you do this like new look is to do kind of a scientific test, right? Where you say like, well, I've got this code and it has certain behavior, let's test that the domain behaves and let it, we'll get the same answer as the domain we'll get, right? And if it doesn't, you know, you got to re-abstract it and figure out again how to encode that new abstraction. And my understanding, like I said, I've never worked in this, but my understanding from the reading is that it's actually very rare that the spec is good enough to actually encode directly. You have to go ask an expert who will dis-ambiguate the language in the spec because they're written in English or at best they might have a table of inputs to outputs or something that you have to code. So that is the idea, that there is some idea of like requirements somewhere and you need to come up with a way of representing that, of encoding that in software. And that's what this is about. I hope that answers your question. Yeah, thank you very much. Yes. So if I can jump in there very quickly, one of the things that I really like about OCaml getting into the statically typed thing is it separates out the signatures and the implementation. And one of the places where I end up using the signatures, and this was very surprising, I didn't expect this when I was using OCaml, when I started learning it, how many years ago, is I use the signatures for the entire left half of your model, right? So it's a way of sort of articulating the model, thinking through the domain and all that without actually having to implement code, but it can still be compiled, it can still be evaluated and it will tell me when the types don't work. And then I'm like, what is going on? And then I realized, oh, I don't understand what I thought I understood over and over again that happens. And it's lovely. It's absolutely wonderful. What you're describing is what I call the operation lens, where you just work with function signatures, even if your language requires a body of your function, just work with the signatures. The signatures are the name, the arguments, and the return type, and just play with those, because you'll realize, oh, I need a third argument to this function, otherwise I'll never be able to calculate, I'll never be able to construct the thing that it returns. So I need to add this other input to the function. And just working at that level, it's very lightweight. You don't have to invest a lot of time, or certainly you won't have as much to throw away when you realize your design is wrong, but it tells you a lot. And that's one of the tricks, I call it a trick. Let me continue in the slides, because I'm about to talk about this. The idea is you're trying to get to code, like a library that actually runs and works. And if you are writing function signatures, those are ready to be implemented at any time. You don't have to implement them, but to get to the library you will. But you're actually getting, you're taking steps toward code, but they're small steps, very cheap steps to take. And so you get to iterate more on the design before you commit to implementation. All right, so this thing, I have something, it's not quite worked out yet, but I had that thing at the beginning about my thesis, which was you need better information to make better decisions so that you can have better design, because design is all about decisions. And this diagram has like four kind of steps in it that create these two loops. And I don't know where it fits into this, but there's like four things that the lenses are trying to give you. They're trying to give you better information. They're trying to help you see more options. So I see beginners get, stumble a lot where they're like, oh, I have to use a class for this. I use a function, or what about even just a hash map, or just an enum, or you know, there's all these options that are available, and we often don't evaluate them. And I want to say that just like a chess player, like a given chess player will do better evaluating more options per move. I think we would make better design decisions, and so do better software design by evaluating more options. But then you have all these options and you need to evaluate them better. That's another part of the chess metaphor, so like you have to know that that move is better somehow. You have to be able to compare them. And so you have to evaluate them. And then we need iteration and feedback, which is the loops. Like you want to be able to get through these loops. Like the more iterations through the loops, the better design you'll have, you know, all things being equal. All right, so, Eric, I think Tim wanted to say something about the diagram before you move on. Yeah. Yeah, thank you. I just really wanted to praise the way this diagram played out, because it makes it clear it's not a linear process. It's not require a mascara code. Yes. It's a loop. In fact, it's two loops and it looks like an infinity symbol with your mental model. That's right. It's never ending. And I agree so hard on the fact that you are often not given all the requirements up front. Nobody knows what they are. Or they think they have them. Yeah. But if you have close access to domain experts, then you can lower the latency between the going back through the left side loop. That's right. That's why you get the right side loop to go faster too. That's right. I mean, this fits very well into the agile, you know, ideology, the agile ideas of fast iteration, working with your customer, the spirit, whatever you want to call it. Like I want to avoid the, you know, I don't know, the stamp agile on it. But I also want to avoid people thinking that this is a big upfront design process. So I need to like kind of thread that needle, which is kind of hard. But no, it does fit into the agile idea of like talking to your customers. Lots of small iterations. The thing is, it's a design like a, what do they call it? It's not, it's not building features, right? It is like a design activity. So it's not like directly going to get your feature out faster, the feature you're working on today. But in theory, it will help you get, if you have a good domain model, it will help you get the next feature out better, faster. I feel like this agrees a lot with domain driven design. Yeah. It's the spirit in spirit. It doesn't speak in methodology out of it, because that's always too, right. You know, I have, I think I think it got recorded, but I have a whole rant on soft to on on domain driven design. In the last one I gave last year. So I won't, I won't do it now. I even though I'm tempted to, I'm just going to, I'm just going to move on. Please do keep stopping me for questions. Okay. So to get this double feedback loop thing going, and to wind up with code in a library that gives you all those nice benefits I talked about, there's three, three parts to this. There's modeling in code, there's separating specification from implementation. There's, there's feedback. So modeling in code, why, what, what is, what is modeling? Why do we do this? So like I looked up the term modeling, that means all sorts of stuff. You might think of like this kind of model, a fashion model, like there's like this, the artists model who kind of gives you an idea of like, what, what, you know, the shading and how to, the colors and stuff and what you should paint. There's the architects model, which is sort of a light weight way of testing out shapes and, and how things are laid out in a very cheap building material instead of building the whole thing. Then physicists model too, they'll, they'll talk about building models. And then there's this one that that maybe is closest to what we do, which is like accounting is a model of transactions. Yeah. It's an abstraction that, you know, when I do a transaction, I'm giving somebody money, they give me a good, that's like a physical thing happening in the real world. I'm using, you know, particular bills that I pay them and the good is a specific thing. But when you put a transaction in the book, you just say like $100 debit, $100 credit and the other account. It's an abstraction. You're leaving out all these details. So the, the kind of modeling I'm talking about is actually these three. So the architect builds this model to learn. They have all these ideas about how it's going to work and they want to make sure those ideas are true as true as possible, as sure as possible about their truth before committing to like expensive building. Then a physicist is modeling to communicate like that, yes, they want to solve some problem in physics, but they're also like going to publish a paper or something. So they're, they got to write it down in a way that someone else could understand it. And then the accountant is modeling to record data in relationships. So this thing at the end, this is like what our production systems have to do. They have to actually record that data and process it correctly. But this is what we're doing. We're modeling to learn so we understand it better. And then we have to communicate with our team and with the stakeholders about what it does. So we're, we're kind of doing all three of these levels at the same time. Okay, so we, when we modeled to learn, we do all this stuff like we're reducing the number of variables. We're trying to make the problem more constrained. So one, one technique you might want to do is like not use a real database because that's got a lot of problems. You're going to have to deal with. You'll deal with them later, but you just use an in memory version of the data. You want to build as little as possible to answer your question. You want to know, hey, did these functions or is there a way to express this situation at the coffee shop? Like, how, how can we, how can we build a thing that could even express this? We don't, let's not worry about implementation yet, but just looking at the function signatures and like trying to create a little prototype. And then you can defer decisions that don't answer the question. You can just leave them out. You don't need to. You can just use a stub. And then this one, this one I think is like super valuable is like answer the hard questions first. A lot of people do this thing where they're like, they create a class and the first thing they do is they add all these fields and then click in their ID to generate the getters and the setters. And man, the getters and the setters, you can generate those at any time, they're basically free. Even if you have to type them out, they, they're so easy to write. It's the hard methods that you should write first because you don't even know if you've got the right fields yet. Like why are you worried about the getters and setters? And the reason I'm so angry is because I do this too. I'm like, oh, let me just get all this easy stuff out of the way. And then I'll do the hard stuff. And then you realize, oh, no, yeah, I need something else. I need this other thing, but I don't have that yet. Oh, where would I get that from? Oh, I need to thread this argument from all the way up here. And like, if I had just done that one first, I would have learned that right away. And I wouldn't have had to change all the code that I wrote that was solving the easy stuff. So there you go. Right. So we're, we have to communicate. Our code is made mostly to communicate with other people. I mean, and to the computer, that's, that's super important. I'm not saying it's not important. But we have to communicate to ourselves in the future, to other programmers. And so we need to be able to, to like try it out. Like, does this work on the use cases we can think of? You can run your thing. You can visualize it. When it's in code, you can do a lot more than you can in like English sentences. Right. I mean, I don't know what more to say about this one. I think it's pretty obvious. I guess the last thing, the testing one, one of the cool things that I've, that I've noticed by doing this, I'm going to put process and quotes process is that at the end, you have this like in memory version, like it, it's a stubbed out version, but it runs and it's correct. It gets the right answer. The behavior is right. This can be your test oracle that you can compare your actual implement production implementation. So even if like you don't know how to like, unstub it and make it productionized, like you can still use it as a test oracle, that's, that's very valuable. Okay. So here's this other thing, the separating implementation from specification. This is the thing that whenever I ask people who think deeply about like the process of growing as a developer, as maturing, this is the thing that they say is really the thing that separates juniors from seniors that a junior is just like, I just need to get it working. Like that's really hard all by itself. So I'm not going to do all this, you know, abstraction stuff, but a senior starts to think about how to separate out the specification from the implementation. Okay. So I've separated them out. One goes on the top, implementation goes on the bottom. So there's all these techniques that I'm developing in the book to help this. So well, let's just give some examples, I guess. I guess this is trying to compare the runnable specifications idea to other ways of modeling. You can model in natural language, you can model in UML diagrams, but then you have to do this hard translation step, it's error prone. And there's still information that you're not getting in the UML diagrams, like it might be really hard to implement. You might not have it disambiguated enough. And so you still have an answer to a lot of questions until it's actually in code. So while it's useful, it's like that architects model, it's not really going to get you all the way. You still have, you know, you shouldn't leave like, you shouldn't spend a year on your UML diagrams and think, okay, in six weeks, we're going to code this up. Like you got to leave a lot of time at the end to discover all that stuff and work through it. Whereas in runnable specifications, you're in code, in your language, right? You're in Java or whatever, and you just take steps toward the implementation. Can I just ask a question? Yeah. So I really like this idea and my question is so good. That's a good question. No, no, no. And so most of the time I see English specifications and UML diagrams used is when dealing with non-technical, like I'll say non-technical people, people who aren't familiar with you. It could be someone who knows JavaScript but doesn't know closure, right? For example, or my boss, who's a mechanical engineer, but he doesn't code. So do you have any thoughts or maybe are you going to get into this on how you can make your specification runnable to non-technical people? And one thought that I have is when my boss will say, "Hey, I want this different colors," I sort of taught him how to use the debugger window in Chrome, right? And so he can change the CSS and he can do all that. But are there other techniques like that? I mean, is this something that needs to be part of your workflow? Definitely, yes. So just for background, UML is this really well-developed system of diagrams and it's really got like a methodology behind it. It's not just like boxes and arrows. First of all, working through, as the architects, as the programmers, working through the design of the system in a way that gives you an artifact to talk to the stakeholders about, right? Like, "Hey, here's a use case diagram. I think that's what you call a sequence diagram. This is what we're thinking is going to happen, like this guy's going to press these buttons and then the software is going to go do a thing and he's going to return an answer. Like, you have a slide that you can show them so that they understand what you're going to program before you program it, right? And I think that that's like a very useful thing, right? And the thing that I'm worried about is that you do lose a lot of that sort of the casualness of it, right? Like, "Hey, we haven't thought that hard about it, but this is what you said and like, is this is a little bit more formal than what you said. Can you tell us if it's right?" But there are ideas, I don't have them in this talk, so I'm not really, they're not like fresh in my mind, but there is stuff like you can, if your code is good enough, you can show them, "Hey, this is a function, here are the inputs and it's going to return a thing, like am I missing an input," right? But then there's also stuff like you could visualize it in code, like you could take the data of your model and present it as some visual way because it's runnable, like you can do that. And what I mean is like, you get a graphics library and you like just make it generate graphics that represent what's going on inside. So those are the two things I've got off the top of my head, but it's totally, yeah, it's totally an important, important idea. If I recall correctly, that was part of the idea of the cucumber slash gherkin language stuff too in various languages where they're like, write your test in a form. That's English-like. Yeah. I sort of like the idea though of having code like prove you wrong, right? So like you can write stuff in gherkin, but you can't execute it. And I like, I really like this idea that you can take things like reductio ad absurdum and say like, look, no, this is the idea, I've implemented it, this is why it's not going to work or this is why it's going to work, then that kind of approach. I like it. And I'm just kind of thinking, trying to think how to. Yeah. Yeah. Yeah. Yeah. The, you know, this is also one of those difficult things where I don't know if I've ever had to present to a stakeholder, like this is what your software is going to do. Like, if you tell us to write it, you know, it's been much more of the like agile way where it's like, I don't think you know what you want. So I'm going to put a button and I'm going to see if you click it, right? And you tell me if it does what you expect. And like, if you needed to do something different and we'll work from there, you know, and you try to make it so that you can write that button in like an hour, as opposed to going through like a big cycle. That makes sense. Yeah. I think, I think writing the button in an hour is probably the best answer. Right. You just get something out there quick. Right. And get them to look at it right away too. Yeah. Yeah. Exactly. That's the, that's the change. Okay. Back to the slides. So this is what Claude was talking about, the type names and function signatures. You can do a lot of reasoning in the specification world, just with type names and function signatures. In the implementation world, you're going to have the type definition. So like when I say type names, like in the, in the example that I'm using in the book, you can just say, this is going to return a coffee. And I don't know how I'm going to store that in memory. Like, is it a class? Isn't it like if it's closure, it might be a hash map. Is it just a struct? I don't know yet. I'm not. That's too implementation specific right now. I just need something. I'm calling it a coffee. And then these functions are going to take coffees and return coffees. And I don't need to know exactly how they're built. And then I'm, and I don't know how the functions are going to work yet either. But I know that I know the types that they're taking as arguments, as inputs, and what they are going to return. So this is what it would look like. So you just have, this is like TypeScript, like cheating TypeScript. So you just have like these types called coffee add in an add in collection. And you say, well, I'm going to have some way, some function that can take a coffee and return me an add in collection. So the add ins are like, you know, the hazelnut syrup and all this stuff you can add into the coffee. I know it needs to be a collection because you can have more than one. It's pretty easy. So I'm just going to call it add in collection. I don't know how I'm going to store it yet. And same with add add in, I know I'm going to need to take a coffee and add an espresso to it and then get this modified coffee. And I don't, like I said, I don't know how I'm storing anything yet. But I can kind of see that these are things that satisfy my use cases, like the, I know the barista is going to have to press buttons on that screen to get to, you know, generate one of these. And then when you get into the implementation, it's got a lot more detail. Like there's a lot, just frankly, there's a lot more surface area, a lot more that could go wrong in this. And then you've got all the trade offs and consequences that you've got. So you want to avoid this as long as possible. Another thing is this idea of denotational semantics versus operational semantics. These are terms that I've been, I've been learning about recently in denotational semantics. It's this whole field of computer science. It's kind of not very popular right now, but the, the idea is you define the behavior of a programming language in terms of the meaning of the expressions. So you'll have some like primitive expressions that you'll maybe specify the meaning just in English. And then everything else is like built out of those, those primitive expressions. And you're, that's how you define your programming language. Uh, likewise, there's operational semantics, which is more like a compiler where you're saying this expression will compile into this kind of behavior, this byte code or, you know, some, some other thing that the behavior is defined. So it's, it's more like meaning versus behavior. So if we can stay in this meaning world, we can do stuff like this. So this is a denotationally defined factorial function. You'll notice that it, uh, it's, first of all, it's recursive. So it's defined in terms of itself. It's doing a little bit of math, but it's kind of at the same level of abstraction. It's just checking, it's my argument zero and I'll return one. Otherwise I do this expression. Whereas if you were to define it, uh, operationally, you might do a for loop and, and there's just a lot of stuff that's like not about factorial anymore. Like it's just about how do I calculate it? Like, you might, um, like when I say this, like the term that comes to mind is, um, declarative, right? But declarative is one of these things that like one person's declarative is another person's imperative, you know, like people say, Oh, maps and filters. Those are declarative. And I'm like, Oh, no, that's so imperative. Like I know exactly how it works because I've written them before, uh, so it's not, it's not exactly declarative, uh, but so this is a better term, denotational, it's a better term because it just means you're defining a function in terms of the meaning of other things that are well defined. As opposed to this, which is like the behavior. Okay. Um, so what this leads into is that we can separate out different kinds of implementations. And I don't have a good term for the, the bottom one for function implementation besides implementation, but function definition in the book, I'm trying to separate these out and say that a definition is where you define one domain operation in terms of other domain operations. So here's an example. We're defining the, how to calculate the price of a coffee. So just so we can see the signature, it takes a coffee and it returns a number, which is the price. And so this takes the, the, it gets the size of the coffee and it then calculates the price based on that size and it adds it to the price of all the add-ins. Okay. So notice, you know, there's a plus in there cause we're dealing with numbers. So it's kind of at the same abstraction level, but we're, we're not defining it operationally. This is very much in terms of the meaning of other domain operations. Now the definition of size might be really simple. Like if you actually, or the implementation, sorry, of size might be something like coffee dot size, right? Like it could be super, super dumb, right? Like it doesn't do anything, but coffee dot size encodes an implementation, right? It's because now we know something about the type, the structure of coffee, whereas this function, we could just stub it out and leave it, or just leave it as a, as a function signature. And so this is what an implementation of it would look like. We're getting the size price because, but we're encoding see the coffee dot size in there. And then coffee dot add-ins is like, we're assuming that structure, but then because we're using this four, sorry, yeah, this four of, that means it's got to be a hash map. So, so like now we're, we're talking about the implementation details in here. And so we much prefer this kind of function definition as opposed to this kind of function implementation. They both get the same answer, but this one is, there's much less commitment going on here. Besides being cleaner, oh, there we go, have all these things about it, what they assume. So this, this assumes the existence of four other functions, all in the domain. This one assumes two of those functions, but then also that the coffee dot size is a thing. So it must be an object that the add-ins are an object, and that there's this algorithm for calculating the price. It's not just this simple sum. Okay, try to move fast because I'm, I think I'm running out of time frequent and rich feedback. Oh, so I, we have this model right of the process. You want to make, you want to have more feedback, you will make better decisions if you can test your, your encoding against reality. And because of this model that we've got here, when you test your code and see what it does, you're actually testing your models like your understanding and the domain. There, if, if you've got a faithful abstraction and a faithful encoding of that abstraction, testing your code is also testing all the way back to your domain. So just a few things like work in memory, you stub things out, don't use a database, don't hit an API, work iteratively. This means that you're going from less to more correct. I don't know. This was very enlightening to me that there's a difference between iterative and incremental. Incremental means you build a thing in pieces and iterative means you build it more and more correct over time. I thought that was, that was really useful. So I put that in here. Okay, this is moving on to another domain. So it's another, sorry, another lens. So it's a good point to stop to see if there's any questions. One set of questions for you, kind of going back, Eric, do you consider a specification as under that, it would a mathematical lens be part of that, or was that a different lens where like, kind of the given some kind of inputs, they map to some set of outputs, kind of like the domain and range of my inputs, because we talk, you talk about it as types, but if it's not just like, Hey, it's a coffee, like here's what I can do, and doesn't make sense for maybe some of your initial abstractions and then memory to be just like a hash map of given these predefined values, I can return this result as a dumb, like a hash map as a dumb function that's memorized. Oh, I see, yeah, so like, I think I see what you're saying, but you're saying use a hash map as kind of a stub for a function and anything you can do. So I should, I should go back in the slides. So oh, that was too far. So when you've got this kind of thing, like you are going to have to eventually define all your functions or implement all your functions, or it won't run, right? You've got this size function that you never implement, like at some point JavaScript is going to say, Hey, like it's undefined. So you need to implement it some way. But this is trying to do is, is to minimize the number of functions that actually have an implementation that the other ones, you want to maximize the number that have a definition. So maximize the number that are defined in terms of other domain functions, and then have this small set of functions that say, okay, these are the ones that know how, you know, what, how coffee is represented. And so then you can stub those out with something that approximates what it's supposed to do. And hopefully it's a perfect approximation. And the book goes into data modeling, like, okay, a lot of the chapters are already online. If you want to read them, I don't have time to go into all that. But just keep that in mind, like this idea that I could change, if I have a bunch of functions like this, I could change whether coffee is implemented with a class or with a hash map or something, anything else. Because I have not this, this particular definition does not rely on that. Now this one might size might have to rely on that. But then I only have to change size if I change my mind about how it's implemented. And so you could say, visualize the coffee, maybe even create like a prototype of the, the POS that the barista will use, all in memory. And they could test it out and say, yeah, this is, this is, you know, ergonomic and it's going to work for us and it, you know, oh, but how do I remove a coffee or remove a soy after I add it, you know, if I'm doing hit it by mistake, they're going to ask you all these questions and that's useful feedback for what you might need to add to your model. But you can do all that like by implementing as little as possible in this sense of the word implementation. So yeah, stub it out as, as however you need to. All right. Any other questions? I feel like if clean code had to do over, they would say, yes, that's what we're trying to say. It's just that if you decomposing smaller, you get more of a specification than an implementation. Huh. I don't know if I should be happy or sad that you compared this to clean code. I hesitated to do so because I know that's getting canned right now and there's a lot of reasons why that is not a good. So without without commenting on the. I just want to say, I think you're crystallizing something that yes, people have been grasping for. I agree with that. I agree with that. I've been reading a lot of software design books to write this book. And the more I read, the more I realize that people are hinting at domain modeling. But they're talking about code, like they're explicitly saying, hey, we need to, you know, this code has this problem because like say, you know, usually it's something like, oh, it's hard to change or it's hard to read. And then they'll say, well, so we need to introduce a new function here. And then they'll, they might say like, well, the reason we know this is a, this is a function that has like a good underlying idea is that it's easy to name. And you're like, wait, wait, wait, wait. The whole thing about underlying idea, that's domain, that's the domain. You're, you're like hinting at like, we need to find these good domain concepts that are useful to model. And but that's the, that's the meat that I'm trying to like, we're talking so much about code. And whether it's clean or a, you know, easy to modify, easy to change. And we're missing the fact that the domain has all that information, like how, what do I need to represent and what are the operations that we're going to have? Like, that's all in the domain. And people are looking in the code and saying, like, oh, I can extract this as a method. And then it doesn't it look nice and like, it's not about looking nice. It's not about your code. It's about the domain. Anyway, rant, it's, it's like we're talking about, it's like if you are giving a writer advice and all you told them was style, like you're choosing the wrong words. You know, use fewer words, like, you know, you have all these style. Your tone is wrong. You have all these style suggestions, but you never tell them, like, oh, your character development sucks or like your plot is an interesting, like, that's, that's the meat of the story. Right? Like the style has to serve all of that other stuff. And as an industry, we're just talking about the style. Okay. Can I make a comment on that real quick? Yeah. You just, you just press body, but nice, which is that every discussion I see is software architecture per tends and it doesn't matter what you're doing. Yeah. Your domain is, and that's just me. After being so long in this business, that's just the craziest thing. It's like, how can you pick an architecture if you don't tell me what debate you're in? Like, right, tell me if you're writing, you know, real-time game or enterprise software. I mean, those are different things. That's right. That's right. And that's, that's the, this like bone picking I've been developing for, I don't know how many years now. It's just, it's just so hard to find software design material books or blog posts or talks or whatever that actually goes into something, like all these other choices, they, they just try to make it all about the code, you know, like, oh, the problem is you have too many classes. Like, how do you know you have too many, maybe you have the right amount of classes for your domain? Like, that should be like, like, there should be an objective way to know, does the domain require that many classes? And do you have the right number? Like, that's what I'm trying to do in the book is like, say there's some objective stuff, like go look in the domain before you like judge whether your function needs to have more than five lines, you know? So, anyway, thank you for that. That may be the key nugget from domain driven design is to understand the domain first. I agree, but then there's like 400 pages on some other stuff that I don't really. Oh, I mean, I didn't like the rest. Yeah, I mean, I watch talks from the domain driven design conferences. And first of all, I think it's, it's, it's very surprising that there's such a following of this thing. And I have ideas about why. But they're talking about stuff that I'm like, this is, is this in the book? Like how did you, I don't remember that. And you know, it, I guess it feels like I don't want to say this on a recorded talk. We'll talk about that after. All right. On a positive note, I think something that will set, sit well with you in reference to that infinity symbol and being able to go back and forth with the domain expert is a link to this classic from Prag Prague, an article called imagine a, okay, it just somehow snapped into my head in reference to the way you're talking about it. It's really old, but I, if my memory serves, it's got the notion of this loop of going back and forth and like figuring out what the core data structure or representation of what the domain expert wants is and letting them interact with it. I think there's a lot of value to this. And I think this, this is what rings true to me in the, in the domain driven design book is when they sit down with like, he's working on something like automotive parts, you know, and he sits down with the automotive engineer and he's like, look, I can, I can write this code and like, does this look right? Does this, this, this decomposition of the concept makes sense to you? And then there's like this back and forth. They're, you know, and they're technically enough that they're used to reading math and so they can read the code and be like, no, you know, these three things don't add up to that. There's like this intermediate thing in between, you know, and so he's like, oh, great. And he goes back and he codes that up and the next day he shows them, you know, and there's this fast iteration with the domain experts that, that to me is the, is the most valuable stuff. I mean, if nothing else, it really tries to break the notion that the people that want the software will tell you everything they need to tell you upfront, like that, because they can't, right, and we can't know that there are problems with it until we try to implement it. And it's easier to implement it in small bits because then you can keep that part in your head. And I think there's this, this other thing, which I'm trying to express strongly in the book, which is that we as programmers, because we have to satisfy the compiler, we can be a sort of formalizing force. The domain expert has this deep intuition. They're really, they really understand the domain. You could give them a problem. They could solve it right away. But if you ask them to just like, tell me all the rules, I'll write them down in code. Like they can't do that. And they might make, you know, all these simplifying assumptions that you don't like understand or whatever, like you can help them express this domain in a formal language that has to run. It has to type check like whatever, like systems you can set up to help formalize your code. Those will all help this process. And I believe that programmers can be this, I don't know, I'm calling it like a force, but you're helping the business formalize the understanding of the domain. And it could be a competitive advantage if other companies haven't done this. Other companies might be thinking in terms of features, like, oh, we need a button that launches the missile and we need a button that, you know, adds a wheel to the car. And you're like, how does a car, how does it even get put together and you model it? And then you can make any UI that puts cars together, right? Okay. Thank you. One other thing about the Anthony symbol that I didn't get. I forgot. I do, I do want to let Eric do his final slides. Yeah. Yeah. Because people are going to start. We have more time. Yeah. Let's do after. Yeah. All right. So the timelines. That was the runnable specification. This is the timelines. So the idea behind the timelines is remember, this is like another perspective to take on your domain to extract information about it. Every sophisticated model includes at least one notion of time. So this, this notion of time could be something like the timestamp of when the thing happened or it could be something more sophisticated, like, like an order of, or sophisticated is the wrong word, something more, maybe subtle, like, these things happened in this order, right? Maybe you don't know the exact wall clock time that they happened, but you know that this happened after that, and that's a notion of time as well. And so you look at something like accounting, like we looked at before accounting actually has two notions of time. So there's this notion of time of the order of the transactions that happen. You can record the date of the transaction as well. But then there's the, well, okay, so wait, there's the date of the transaction. So that's when did this transaction occur. But there's also the notion of when did we learn about the transaction. So like if you talk to an accountant, like around tax time, and they're like, hey, did you make any purchases for your business that you, you know, you forgot about? And then you're like, oh, yeah, I did buy this back in November. They're like, oh, you didn't write it in the book. They're going to back date that transaction. So they'll look at the receipt and say, oh, yeah, there it is. It actually goes in the tax year last year, but it, but I'm only writing it down today. You know, maybe it's February or March or whatever. And so there's two notions of time in accounting and every model as it gets more sophisticated starts to have some notion of time. And it might be because you need to be audited. I might have this in slides, right? So there's different notions of time. There's the, the just calendar date time. There's the order. There's this as of time. So like what was the state of the account on December 31st? You know, what, what was in there? You know what, like in terms of money or you need to do a history with an audit. So like how did it get to be the way it is now? We need to know if all those steps were legit. So the problem is when we build the naive models, we tend to just do update in place. We just throw away the past. We're all familiar with this. We don't think you have to dig into that, especially in a functional programming group. So in the book, I go over two models of history. One is the history of states and the one is the history of mutations. So in the history of states, you basically keep track of the every, every state of the system. So here, this is just keeping track of one coffee. So this is time, so from left to right, time is going forward. This big arrow is the current coffee, the current encoding of the coffee. So you can see we started with this coffee and it was size mega and roast burnt, no add-ins. And then we changed the roast to charcoal. And then we changed the, we added a soy and then we added espresso. And so we, that's how we got here. Now the cool thing is, if you want to do undo, you just drop the last thing. You could keep it in another array to have a redo, right? But you just can move back in your, you know, sequence or array of states. And that becomes the new state. And then if you need to move forward, like you need to redo, you just go forward or you can redo, you know, instead of redoing, you can just work from there and add almond to the one you're at, right? And so that becomes your history. Like how did I get here and you're kind of going back and forward and then forward in another direction, that kind of thing. There's the other one is history and mutations. This one's a little harder to implement, but we'll see it has some useful properties. Instead of recording the coffee and just keeping around the, all the old versions of the coffee, you have to encode in data the, some representation of the change. So this one is saying, okay, we're starting with this new default coffee. And then we're going to set the rows to charcoal. This is the same stuff is just shown differently as, as mutations. You're going to change, you're going to add an add in and then add another add in. And so this is the current version of it and I don't know if I have an animation to like go back. No, but if you went back, you would have to replay all of the stuff from the beginning to regenerate, so if you're on this one, this would be the current coffee, you have to replay everything up to there and it would have that version of the coffee. Right, okay. So we can compare these, the history of states is easiest to implement because you're already generating all those states. It's expensive to store in memory probably not because you're sharing a lot of structure with the, you know, the different states are sharing structure because you're not making a full deep copy each time. But it's expensive to store if you needed to like serialize it to disk or store it in a database, because then you're not sharing anymore. You're serializing it to JSON or something. And now it's just bytes and you're splatting it all out into bytes. So the longer it is, the bigger it gets. So the history of mutations is harder to set up because you have to, you have all these functions that operate on your, on your data representation. And now you have to convert them into data and then make a, an interpreter for that data that just calls the function that you already had, right? So it's not like hard, it's kind of mechanical. It's just like a big if statement to like wire up the data into the right functions. But it, it costs something, right? But it's cheaper to store because the, the data is smaller. It doesn't really grow as the size of the data grows. And it captures the intention. That's the thing that is the most useful about it. When we see this, we know what the intention was. The intention was to change the rows to charcoal. Intention was to add a soy shot. When you do this, you're going to have to, to reconstruct the intention, you have to do some kind of diffing and it's like never going to be as, as data rich as this is. Okay, I'm going to get through this lens and then we can just have a big free for all discussion. Okay, the domain lens. When I talked about this book, the ideas in the book, book is called "Runable Specifications", by the way. When I talked about it three years ago here, I made this mistake of teaching it as a process. I actually did have steps. And you know, I made all the caveats and I said, it's not really linear, but I'm going to do it linear just to teach it so that you understand. But really, there's a lot of loops going on. And still people were like, how do I let my manager do, let me do numbers two, step number two. And I was like, uh, like, it's, it's done in your head, like they can't tell you not to do it. I don't know. They were asking me process questions when it wasn't about process. And one of the things that I, another mistake I made was I was saying this lens was called or this, it wasn't lenses at that point, but I was this idea that became the domain lens. I was saying you have to look at the reality of, of coffee. And I can't remember who it was. Doesn't matter. Someone said, cause it is my fault, this is the way I explained it. Someone said, but in reality, you can't remove soy from a coffee, uh, because it's mixed in like it is, you can't unmix it. And so I had to go into this whole thing, but it, it, it made me think, no, this, this needs to be its own lens because even though the way I explained it caused this person to, to misinterpret what I was trying, what I intended to say, I do think that people jump to these kinds of conclusions, um, or not conclusions, they have these habits of modeling. So let's, let's see some habits of modeling. Um, so like, let's say I asked this question of people, what is the problem we're trying to solve with coffees? Um, we might find someone who says, well, we're just trying to represent a coffee. Okay. That's kind of vague to represent a coffee. Um, someone else might say, well, we need to model how coffees behave. Someone might say, oh, raise your hand if, if like, you know someone who might say something like this, this is maybe more interactive. Okay. Just kind of something vague, like, oh, we're just trying to, trying to represent coffee. Okay. What about this one? Model how coffees behave. Yeah. Um, okay. Anyone remember this from college? You have to turn the nouns into classes and the verbs into methods. Okay. Now, what about this one, you have to find the Isa and Hasa relationships? Yes. Okay. Uh, so this one is vague, representing a coffee that doesn't help. Um, this one is trying to capture this, this person who, um, mistook what I was saying. Like, you can't go from a coffee with soy to a coffee without soy. Um, so how can you remove soy from a coffee and your model? Right. Um, this one just to me is like crayons. It's like, it's for, it's for children. Uh, you know, maybe in university, like this, I remember this from university, it was one of the things they, they taught us. Maybe they knew that they were teaching us like finger painting, uh, and that we would outgrow it, but I still remember it and I still know people who are stuck there. And then this one is like the classic object oriented design and analysis. We need to like have some kind of hierarchy of, you know, a latte is a coffee and a coffee is a beverage and a coffee has a roast and a latte has a mill. You know, like whatever, like that's, um, it's, it's just not what we're doing. When it's not what we want to do when we model, but people have these, these sort of habits that they've developed over years and they're going to jump to one of these modeling things. And so what I'm trying to do in this domain lens is to get them to like kind of see past their own habits and their biases. So one, one technique we have to look past that is to actually just look at the situation where there's this process that your software is part of. This is a coffee shop. There's a lot going on in a coffee shop and there's like a computer that's like sitting on the cashier's desk that's doing something like let's put it into context. What is it doing? So the customer walks into the coffee shop, gives their order to the barista. The barista punches it in to the POS. And then the POS prints out a receipt for the other barista who's going to make the coffee. And also the POS is going to tell the barista like how much money it is then the customer gives them the money and all that. Okay. But we're actually trying to like program this machine that's like right in the middle of this process. We're not modeling the coffee over here. Like he's got his own thing for how to make a coffee. We're not really interacting much with the customer. In this case, it's really the barista who is interfacing with the software. And then the software has to print out a receipt or some kind of little paper that the barista is going to use to make the coffee. So it's kind of like this communication problem. Like the barista is tapping on a touch screen and then it just has to communicate to this guy over here who's just making coffees. So that's interesting to know, right? Like it's just about faithfully communicating to the barista. Now the interface has to faithfully capture through the barista what this customer wants, right? So that's interesting too because the customer might not know what they want. They might make a lot of mistakes like, oh, I want a grande. No, actually, we cannot make it small like what? What is a grande? It sounds big, but it's actually the small, I don't know. So like they're changing their mind. The barista has to like keep up with them and all that. They might tell you out of order, whereas the barista, this guy wants it in a certain order so that he knows how to make it the right way, right? So there's something else going on there that we have to capture. And then we also have to calculate the price. Now if we keep digging and we go to the rest of the business, we might find that like, hey, there's this store manager who needs to look at all the orders, like at the end of the week or at the end of the month and figure out like, are we going to need extra soy milk next month? Are we going to need more dark roast, whatever it is? And so they're doing some other work with this information. And then the guys in marketing are like, hey, did our promotion work when we sent out those coupons, did more people buy, you know, peppermint lattes than they did last month. So there's this other work that's going on too. And our software has to kind of do all these arrows here. That is the, that is where it fits in. So like mapping it out helps, helps see this that like, we don't need to have a, you know, a class that's the store manager. We just need to give the store manager some interface into the data, right? So like, we're not doing this, like, find all the nouns, find all the faces and like, make a class for each of them. But we have to, we have to like satisfy all of their needs with this software. Now more of those things we can put on the board at once. So if you had like a, like a board because you're like tracking a serial killer, you know, like you need to like, put it all out there so you can see the patterns and stuff. And the more that you can put out there at once, the better decisions you'll be able to make. So the other question that can kind of clear our mind of our habits is how would you do it with pencil and paper? Like a lot of problems, like you would solve it pretty simply. If you're just like, well, if I had to write down the order, I'd probably have like a pad of paper. And as they told me stuff, I would write it down and then I'd pass it to the guy and he would make it and like, okay, that's kind of simple actually like, can we, can we use that as inspiration? Like we don't need to like model the physics of coffee and how, how, you know, have some like infinitely flexible system. We just need to write down like, like three pieces of information, the size, the roast and what add-ins do they? Huh. Okay. That's, that's kind of nice. So this can kind of clear your mind too. We don't need to have a hierarchy of like a latte as a coffee and a coffee is a beverage. You don't need all that. Okay. The other one, this one, I don't know how to explain it, but you just zen out. You just sit there and you just stare into space and you're like, what is a coffee? And you're like, dude, whoa, what is a coffee, right? Um, now we're actually modeling the order of a coffee. That's something that you might do think about when you're zenning out. What is that? I can only give this other example. I wish I had an example of, you know, coffee orders, but like, there's this guy, Connell Elliot, very inspirational to me. He has a, um, a whole design methodology called denotational design and he gave this talk. It's like two and a half hours, wow, three hours of him explaining the thing, the process. And in it, he develops this kind of very simple because it's just, you know, on slides, but it's like a graphics, uh, library. And he starts with this question, what is an image? And so he asks the audience, like, give me some ideas, even bad ideas. I want them. And so people gave all these answers like it's a rectangular grid of RGBA values, right? That's probably what I would start with because that's what I think of an image is like just a, excuse me, like a big array of pixels. Some people said, well, that's a, that's a pixel, pixelated version, like a discrete version, you might want vector graphics that are like infinitely scalable. So you have like shapes, you know, like triangle and circle and rectangle. And then you'd kind of make a collection of those and some people said, well, it could just be like a program that draws, like you just drawing some, in some graphics library. But what he came up with was this last one, which was from zenning out, you know, what is a, what is an image? And it's just a mapping from 2D space to color. And so he had this function that's just like, oh, it takes a point and it returns a color. And at first it seems like, ah, that's got to be super inefficient to like represent an image as a, as a function. You should, you should do a rectangular grid because like you can, you know, you know how much memory it's going to take, whatever. But the more you think about it, I'm like, well, actually this one can represent all three. Right? There's something deeper about this. Like the rectangular grid cannot represent vector graphics because it's not scalable. Like once you have to zoom in, like your rectangular grid is useless. Like it's just going to, it doesn't, it doesn't have any more information to zoom in for. So like these three are like mutually exclusive, but this one can do all three. But then also there's all sorts of, um, optimizations that, I mean, he claims that he gets by looking at this very like, he's trying to start with the meaning, right? We're talking about denotational like we talked about before. Like what is the meaning of an image? And it's just, it's just this mapping from point to color. There's all sorts of optimizations that you can do that you couldn't do in needs, even though we kind of know like the behavior of these, he discovered a lot of those. So this is the kind of process you're doing like, what is a coffee order? And really it's just, it's just a way of, it's just a way of communicating to the barista what you want and a way of calculating a price so that you can charge money for it. It's like, this is kind of all it is. Okay. So if you want to see the chapters that are already done, there's about 250 pages already finished. You can go to this URL. You can see that there's four chapters left and an appendix where I'm going to put all the codes so you can see it all in one place. Oh, that, that's not centered. That's my newsletter. Get on the newsletter. It's weekly and I talk about this stuff. Okay. Done. Done with the slides. All right, thank you so much that this is, this has been great. I can, I can tell just watching people on zoom, people are very excited. So I'm going to turn it over for a question. I guess the first question I have is how much time do you have, Eric? I can go on. Yeah, I mean, as long as I have a voice, I guess I can keep talking. Okay. So we will open it up for questions. Should I stop sharing my screen or, or, um, I would, I would keep sharing it for right now because people might have questions right now that you want to go back. That's right. And then soon enough, yes. Go ahead. Makes sense. Are these recorded questions at this point? These are recorded questions at this point. So, you know, be polite. Yeah. Don't say anything you can get canceled for. On your denotational, uh, that's then out, uh, huh. Another thing, because I've mentioned before, we've started recording, we're kind of our, our CEOs pushing this a lot for us to, when our, when we're rebuilding a system, but it's kind of, what are the operations we can perform on it too, right? Mm hmm. So it's like the point to the point to, uh, color or whatever gives you a set of operations you can perform on that. Right. Because you have a coordinate, you have a mapping. So there's some coordinates that you could say, well, what if I wanted to, like, as I see book, what if I want to invert or mirror this image? That's right. You can flip it just by like multiplying the X coordinate by negative one, right? Yeah. Right. I guess that is, that is another way of thinking about the denotational, right, is what, what are my operations right that this thing makes available to me as part of my, what that's right. That's right. That's right. By working in this, like, by working in this, um, meaning space, so just the function from point to color. I don't know how it's implemented. I don't know what it does. You can start to think, well, I know that like translation, I'm going to need a move, you know, translate this around some point or whatever. You can make a new function that, or a higher order function that takes this function and transforms the argument to it, right? But it also takes a point and returns a color. So it is an image as well. And you can write that, you can define it already without even knowing how your image is implemented, and you're doing it in a denotational style, meaning it's all about meaning and, you know, defining one thing in terms of the meaning of another. As opposed to say, if you wanted to translate something in a rectangular grid of pixels, now it's like an algorithm, right? You're like, okay, I'm going to have to copy this pixel over here and look through all the pixels and copy each one to its neighbor. It's not even almost possible to define it denotationally. Yeah, thank you, Proctor. Eric, if I could jump back to what you were talking about, time, because there's a couple things that I've run into that I think are related to this. One of them is, if you don't have a concept of time, it's hard to tell the difference between a correction and a change. Right. And the other thing is sometimes you need to know that something is going to happen. Right. The future. Yes, or like a hypothetical situation, or, you know, like some counterfactual, yeah, what would happen if I did this? Like, there's all these things that, man, I have a talk from, I don't know how many years ago about this 10, 10 years ago now, but some of this stuff is really important. Like, if if you're calculating, say withholding tax for people in the US, they need to be able to tell you in advance when they're moving to a new state or a new taxing district. Right. And there's, I guess I've just worked on enough systems where because they didn't really have an understanding of time, it made things just way more complicated than it needs to be. Right. Right. So you're, I should actually put these in this list here. Because as of date is like, this is all the past, but there's stuff like, well, what would my taxes like if I moved to be, what would they look like if I moved to Texas? Because there's much lower taxes there, right? And so that's a, I haven't moved yet. It's a hypothetical, right? But I might want to know. And so I could calculate them in a state that I don't live in just to see. Or like, what if I considered, you know, there's, there's questions like, is this a business expense or not? Like, well, what would it look like if it was? What would it look like if it was not without committing to it? And I think, I think you're absolutely right. If you don't have this notion of time, which is kind of related to the, you know, immutability because you're capturing values at certain times. You can't answer these questions easily. They become like really hard to do. Another thing you said that I want to comment on is that there was, you mentioned that it's hard to tell the difference between a correction and an actual change. So in online, in an online discussion, I saw someone say like, you need immutable state because people can change their name, right? Like we have users and people can legally change their name. So like you need to have them, it needs to be mutable so that they can change it. And like it's exactly what you said, like, look, legally changing your name is very different from the name getting input incorrectly. And I'm just updating. I'm just correcting my name in the system because you don't want to forget the old name. All my old contracts are signed with the old name. So like I was called that before and now my name is different, like it's a very different situation from, you know, you you spelled my name wrong. And so yeah, we need to we need to capture that and you don't want to forget the past. And so that's why you don't want mutabilities because mutability forgets the past. The models have to be immutable. I don't even talk about that. I just assume that you're going to make an immutable model. Maybe I need to bring this up. But thank you for that, John. Where that gets even trickier, though, is the database because that's we're farther behind on making that natural to only record the changes instead of mutating in place. That's right. If you have datomic, then it's natural, right, but you have Postgres that's like, you have to do a lot of extra work to like record the history or just model it correctly, you know, like model like I'm only adding rows, right? Append only. There are a lot of formalisms that have been documented in the literature of like how to use a SQL database to only record. Right. The problem is the SQL queries get to be really hard. Yeah. It's awful. Yeah. And then add byte temporality and that gets even harder and I mean, actually, datomic doesn't completely help us with that. Datomic doesn't have byte temporality. But I see the so but that would be a great thing to add to the slide about, you know, thinking about at least one notion of time is just that I can rally us to always, right? Right. Yeah. And there's some research that's, I don't, I don't really understand by temporality in a database, but there's some research that, that the XTPB guys were saying, once you have two in your database, you can model N, right? You can model more than two. Somehow. I don't know how. I'd be interested to understand what that's talking. Yeah. Yeah. They're like, that's all you need is to. So I don't know how it works. It's like a coordinates that, because I thought it was just system time and as a, like, you might have something that gets recorded after the as of. And so you want to know that you didn't know it with that system boundary, but it's actually supposed to be effective as of a certain date according to the business logic, right? You also have a, as of in the future too. So I know something is going to change. There's going to be a new law on the book that takes effect at this. If I have a coffee order, I know that my sales tax is this today. It will be that in the future. And I can record that ahead of time and no, I know it now, even though it's not effective yet. So as of can be both past and forward looking to like an effective date, I'm going to add this now. I'm going to add the future, future and counterfactuals. I once, this is the other thing I wanted to say, I once was programming a mobile app and I made my own router and the router was all done with immutable data. And so to know what the title of the screen was, if you hit the back button, like you would just, you know, hit the back button in the library, but it would just generate a, you know, this is the data representation of that screen. You just read the title out of it. And so you could put the title in the button, like this is where you're going to go without actually going back as a counterfactual. If you went back, this is what, this is what you would get. So it does have useful practical things even in like GUI programming. Thank you for that question. So I had a question about in the domain lens, I'm not sure I'm going to be able to articulate this very clearly because I've got a bunch of different ideas going on here. You went through this list of like, you know, what domain modeling isn't and why it's sort of done so badly. And one of the things that I immediately thought about was especially about like, when like or teaching domain modeling, it is like modeling, like what is the coffee or what is the pizza and how many toppings can the pizza have or whatever, that type of thing. It's modeling the thing rather than the process, right, the process of taking a coffee order. And that made me think about sort of two separate things. And I don't know if these are related or not. So one is that as you went through that, you were talking about the coffee order, but then also the idea, this is where you started doing the serial killer chart of, oh, but it's also going to be connected to how much coffee do we have to order in the future and that type of thing. And so one question I had is, aren't those separate domains that are related in some way? Yes. Yes. Okay. And then, and speak more about that, but I want to get my other question in before I forget it is, you're also talking about time and how do you say it as any sophisticated model will include, include at least one notion of time. And then I'm thinking about like the process of ordering coffee is fundamentally temporal. And then I'm just wondering about, should our domains, if we're working in software, are they always processes? And yeah, I'll stop there if that makes sense. Yeah. So I, there's three things I'm going to try to keep track of them. So the first one you mentioned was this list here that's got the, the different like bad ways to model. One of the things that I guess I just have an example that I use because it's, it's humorous to me. But like, if you are modeling a grocery store, you know, people will say, uh, oh, it's great because you're, you're modeling the actual store, like an object in memory, a class and off, you know, an instance of an object of a class is actually representing a real world object. Right? Isn't that intuitive? But I have never sent a buy message to a broccoli. I bought many broccoli's, but I've never sent it a buy message. And that, you know, I, I'm trying to like just show how ridiculous it is to like think that this is some kind of, you know, there's some one to one correspondence between objects in the world and the code that we're writing. You're really building an information system. You're writing the, the software that checks someone and rings them up, right? It like reads a barcode, it keeps track of all the items that scan past it. And then it calculates the sum of all the prices and it maybe it talks to the inventory and it like docks out, you know, we need to buy broccoli. And that's what you're doing. There's a whole bunch of other stuff that's not modeled at all about walking around with a shopping cart and putting stuff in your, in your cart, like that's not in the software at all and it doesn't need to be. And you know, like knocking on a cantaloupe, you know, whatever you're doing in the supermarket, it's not captured and it doesn't need to be captured in the mall. So the second thing you said was about, was it, it was about the, the, the, this sort of diagram here where our, the question was, are these separate models? Yes, they are. These are separate domains. One domain is the price domain, right? Never doesn't really care what this guy's doing, I mean, in terms of the software and what, like, what the receipt looks like. He wants to get his coffee that he ordered the right way. And this guy doesn't care what this guy is doing. Like these are separate domains. The thing is that when you have these arrows, you're really thinking about information flows that this POS domain, which is about like kind of authoring a coffee order, right? Where you're making mistakes and you're, you're, you're taking it in like random order from the customer, like, oh, they said the roast first and then the size, like, you know, and then they changed their mind and, you know, you got to do all that, right? But then once it's finalized, it becomes like this piece of immutable data that can go to this guy, right? And then, but that also has to feed into his domain. And so maybe there's something in here that you have to capture that isn't relevant to him, but is relevant to him. So like there is some notion of like, it's got to, the data has to come from here because that's like the, that's the, that's where it gets into the system, right? And so yes, that's, it's true. This guy has his own domain. He is not changing the orders. You know, he's not saying, oh, they really ordered, you know, maki auto. And so I got to go in and change your, that's this person's job. He's just looking at what that data is like, you know, for inventory management, let's say. So yes, these are all separate domains with separate operations. But they're all, they all have to come from the same, like kind of original data model. You kind of touched on it in your presentation. Are you going to highlight it in the book that, well, we're not, we're not actually talking about coffee now. We realize, through this, we're talking about coffee orders. Coffee orders. Yes. We're coming first class in the book, because as you were talking about it, I was thinking through that is, yeah, it makes sense. You first think we're coffee, but let's, we're, we're part of your going back in your looking back at it through your inquiry side is like, wait, this isn't coffee is this is ordered because we want to look at, right? How many are modeling the broccoli or like how many things we're adding, we're asking those questions, right? We said, how many, what, what kind of ingredients do I need to project based off past orders and how many orders are in a month or things like that, right? That's right. That's right. Um, so I do talk about that. Yeah. Okay. So, so, um, and I can't remember if you've talked about this or maybe you haven't, I've missed it. What we're, what you're suggesting now and what I'm getting from Proctor is, okay. So you define the coffee order domain. These other domains, you're trying to map the relationships between them. And what I'm thinking about right now in this example, I don't know if this generalizes is what other domains sort of have a claim on the coffee order domain. And, and that might be a useful way for me to think about how these, how these domains interact because otherwise it can easily get into, well, all of these other things that are going on and I'm pointing at the screen, like you can see what I'm pointing at, um, they all get shoved into that domain, right? And what we're trying to do is separate those out and clearly distinguish the domains. This makes me think about like a relational database, um, and I do a lot of database stuff, but like, you know, references from one table to another, right, and that they have claims on each other. And that's what, you know, when you get into like cascading deletes and all these dependencies and that type of thing. Yeah, yeah, yeah, and it seems like these different domains that they are linked in some way. Right. And so there's, this is, this is a maybe a more just philosophical discussion. Um, but like in the, and I know in the domain driven design community, they have this idea of a bounded context, which, um, is, um, it's, it's very hard to define thing. But it's basically that the accountant or the store manager, when they're talking about order, they're not talking about it in the same way as this guy is talking about it. You know, and, and this guy is not talking about the same way either. And so yeah, they're all using the word order, but, um, you know, they're, they, they mean different things, which is very, this is too vague for me. Like I want them to say like they are subdomains or they're, they're different domains that happen to, you know, feed off of the same initial input, right. Um, and they have the, and by domains, they're going to have their own model, their own rules, their own operations, different scenarios that they're interested in, like use cases. And, um, I think that what's, what's interesting about the, the bounded context idea is that it helps people when they're modeling to like, say, we don't need the user class to have every single possible operation for all of these different domains. Right. Like we can have a user class that's just for this guy and a user class for the accountant and a youth, like, and they, but it's all the same person in the real world that they're talking about, but, uh, it lets you simplify and by having different classes, um, that they don't all have to, they don't all have to play nice. And it's might be hard to formalize it if it's got all these different things and it's easier to formalize just the price domain, you know, and then you formalize the, the coffee printing domain or whatever. Um, so, yeah, yeah, to, to troll the ML folks, that's closure's namespace keys and the speculation talk, right? Essentially, like, I don't need to, like, I don't need to describe everything. I can just say, Hey, it's got all these keys and then this context, it's got these keys for this. Right. But it might, it might, it's an open record kind of thing. And if you want to throw some other stuff into this record, it's still the same record. She might not care about those keys. Right. I'm not going that much into implementation. Yeah. I just, but conceptually in the closure world, that's part of the way we think you thought about that case. That's right. There's like an open world. Like there might be something that you don't know how to use that someone else does that they threw in there and like you shouldn't blow up because there's, they put it in there. Yeah. Um, right. So like, I guess what I, the concretely, like they don't have to have the same data. But the data has to come from this POS, right? Just by the way we mapped out this process. So like you might say, Oh, we got to put something in the interface just to satisfy this guy, you know, because it's got to translate or, you know, travel from here to here. Even though, you know, she doesn't really care about it. He doesn't really care about it. I don't know. Um, yeah. Now another thing that the bounded context folks might say is that these guys get their own databases, right? This is where you would make a microservice for him and a microservice for him. And they store it the way they need to store it to query it, right? That they're getting events, uh, from, you know, the POS and storing it their way. But in my, in my book, the only thing I'm going to say is like they're all, they're different domains. So they need different models. I guess one comment on this thread, uh, I noticed that you put an emphasis on how the data enters the system. And like the model was kind of couched in the data input, and maybe it might be influenced by who needs the ultimate output. But I guess I'm wondering if like that kind of generalizes, maybe that's where you like start of when you're thinking through this process. I mean, you alluded to it's not a process, but yeah, you know, I know, I see what you're saying. That's an interesting way to, um, to frame it because, um, I think the only reason I'm talking about that so much is because that's the example I chose to, to pick, um, from the beginning, because I feel like making a gooey is kind of like, uh, an interesting domain. Right? Like it's, it's visual so you can put it in a book and people can understand it. Um, and then it's going to have undo so you have a notion of time. Um, yeah, but I think I should in, in, in the, um, the domain lens chapter, I should talk about how there's, there's really multiple domains going on here. You should model them separately. Um, and then no, this was great. You had a third question. Right. Yeah. I was going to bring around to that. I can't remember. Uh, so it was about, um, if all sophisticated models include time are all, are all domains really processes. Oh, right. That's an interesting question. I don't know. They could be. You know that you're actually, you know, like an accounting system, it's like gathering information about overtime as transactions happen. Um, is the coupon domain that this marketer is, is working on? Is that like, a process, I don't know. I guess what that makes me think of is the pen and paper metaphor again. I'm like, this is ultimately an information system and if software on work part of a picture, some human would gather the data, transcribe it in paper, do something useful with it and output it somehow. And I think we're ultimately automating those processes and making them more efficient when we build software for it. Right. I, I'd like to think that yeah, processes is kind of like a something we hone in on. Mm hmm. Yeah, baby, I have the old Hollywood here old enough to have actually replaced a painted paper process with it, but I used to do that. Um, and I still think that's a really useful way of thinking about most business processes because almost everything can be done with painted paper. If you have enough pins and enough paper, right? And enough like secretaries to write it down. Well, go look at the old pictures of the Social Security Administration, but it wasn't just started. It's rooms and rooms full of women sitting at desks and painted paper. Yeah. I imagine. But on the other hand, there's at least one system I keep running into that I swear. We haven't improved our painted paper and that's at the diner, when you go and make your order at an old fashioned diner, I've run into, I've gone to the places that have it all computerized and they're never as efficient as the painted paper. No. No. Now, I don't know why that is, but man, there's something to be said of if you're building solutions rather than software, sometimes there's no software involved in your solution. That's right. That's right. It reminds me I was at a doing a job interview that's being interviewed and the problem that I was asked to solve was that there was this pizza shop and the orders were getting like delivered to the wrong address and they weren't being, they weren't able to keep up with orders. And so the first question I asked was, how many pizzas do you make in a night? And they were like, Oh, like 20 or 30. And I was like, you need to go to your kitchen and see what's happening. Like do not write songs wherever it is. Just look around. It will be an obvious problem right in 20 or 30 pizzas in one night. And that was the wrong answer. They were, they were like, uh, you're supposed to like tell me how to write a sequels statement that will create the model, the database model. And I was like, no, dude, and they're like, no, no, no, but don't worry about that. And I was like, okay, well, if I can do anything, because like this is already going to cost you hundreds of thousands of dollars to develop this software for your 30 pizzas tonight. If I can do anything, well, then like put a barcode on every pizza and like have a camera that's, or, you know, a barcode scanner and like tracking how the pizza is going through the process. And they were like, whoa, that's awesome. Like, oh, man, I didn't take the job, obviously. I love those interviews where you realize like from the questions, like this is not the place for me. That's right. Yeah. Well, they could not, they that whoever was interviewing me right then and there was not able to really judge like what a senior developer can actually do for a company. Right? Like, I can tell you not to write the software like that's a, that's useful. Okay. Sorry about that. Because I'm glad I didn't say any names. What any other questions? Well, especially since we're still recording. So any last questions for while we're recording or comments or anything and then we'll turn it off and then we can say names and be obnoxious and all of those things. I just wanted to add on the ampennamy diagram, one of the things I've found that is really interesting about whether or not your model is going well, is that if you take stuff from the domain experts and then you go through the cycle on the right where you've implemented some stuff and then you see what it does and then you start seeing that that code implies things that the experts never told you and you take that back to them and you say, is this true? And they say, yes. Okay. This model is becoming what it needs to be. Right. It's predicted. But if they say no, then you're like, okay, I need to. Yeah. So look for the all the things that it implies that you were never said and then go back and ask. It's, it can be a little tedious. I definitely been known for, it's like, oh, yeah, it's kind of like, because I'm trying to figure out the models, right? Uh-huh. Um, your thing, you might have to be annoying. Yeah, but I think it's worth it. And it's a sure sign that your model is going in the right or wrong direction, depending on whether or not you're getting the essence or no. Yeah. Yeah. Yeah. Yeah. Yeah. So that is the background. That is also, um, the argument for when you know that your, uh, scientific model is, uh, working is progressive. That's a progressive research program that it can explain things that you didn't originally intend to explain or it can explain things that occur in the future. Mm-hmm. So there is this parallel there versus a degenerating research program is one that essentially an anomaly occurs and then you have to sort of, oh, explain why it's not really an anomaly. Uh-huh. Yeah. Interesting. Yeah. Yeah. I mean, I, I look at this a lot like it's just the scientific method, right? Um, you're, you're building an abstraction about something happening in the world and you, uh, need to refine it over time to make it, to make it right and try to formalize it, you just have this, we just have this cool, this cool tool, the code that, um, I think, you know, even I, I, I think scientists should use it more because it forces forces it to be, uh, more, more, more formal. All right, I'm going to shut off the recording before I do. I just want to thank you, Eric, uh, once again, cause this was fantastic and, um, I think it's evident that we were all very excited by the talk and have lots of ideas and comments and all that. So thank you so much. Yeah. You're welcome. Thank you. This is, this is always great because it really helps me refine the ideas, not only because I have to sit down and make the slides and think about what I'm going to talk about. I really do use these as like notes for my chapters, um, but then all the discussion and everything and seeing what, what interests people and whether like the stuff I'm saying, like resonates with them, like, like your group is great for, for that. Thank you.