[0:01] All right, I assume everybody can hear [0:02] me. Do I need to talk a little louder? [0:04] Are we good? [0:06] Yeah. All right, great. Um, hi everyone. [0:10] Um, I've met some of you before. Uh, but [0:13] I'm Andrew Cassell. Uh, PHP developer. [0:16] I've been developing for about 10 years. [0:18] Um, I'm kind of local here. Uh, I live [0:21] in H. turn, which is about 10 miles away [0:26] or approximately 8 days travel uh during [0:28] DC rush hour. [0:30] Um [0:32] we're for a uh a nonprofit that's called [0:34] the Marine Spill Response Corporation [0:36] and uh we clean up uh oil spills. We're [0:39] a uh nonprofit um we're the largest in [0:42] the United States uh that does what we [0:44] do and we have all kinds of equipment [0:46] and people who are trained uh if there's [0:48] an environmental disaster to respond. [0:52] Uh I work um like I said at doing PHP [0:54] development there. I do mostly [0:56] applications. We also build their [0:58] website and I work as a uh part of a [1:01] three-man team. So um three developers, [1:03] small team. Uh, but I would put our [1:05] three developers up against a team of 10 [1:08] uh, any day. [1:11] Uh, I'm also the organizer of DCPHP. Uh, [1:13] so if you're local, uh, we'd love to see [1:15] you at our meetups. [1:18] Um, today, uh, hopefully it's going to [1:21] be a lot less formal than most [1:22] presentations. Um, this is a workshop, [1:25] so I intend it to be interactive. Um, [1:27] the video is going to be recorded. If [1:29] you guys need to refer to the slides [1:30] later, uh, I'll put them up on the [1:32] joined end. I'll also post them a link [1:35] to Twitter. Uh joined in is the uh [1:37] conference rating system that you guys [1:39] should uh you know write this talk [1:40] afterwards. Uh so the video is the [1:44] slides are going to be recorded but [1:45] nothing is going to be video recorded. [1:47] Um you know so you guys don't have to [1:48] worry about being up on camera or [1:50] anything like that if we as we do uh [1:52] stuff together here. Um I'm going to be [1:56] you know kind of presenting here for a [1:57] little while. Then we'll do some work [1:59] and then we'll present a little bit and [2:01] do a little work again. But while I'm [2:03] presenting because I want to try to keep [2:04] this informal, it's kind of a, you know, [2:06] small enough group we can do this. Just [2:07] raise your hand and if you have a [2:08] question, I'll stop and try to answer [2:09] your question and stuff like that. Um, I [2:11] really don't want to go any further [2:12] unless you're not, you know, you're [2:14] understanding something. [2:17] So, um, for also for today, you can [2:19] assume that all the code you're going to [2:20] see and do is around is PHP 7 or 7.1. [2:24] Uh, but that doesn't mean you can't use [2:26] PHP 5. have been doing this longer than [2:28] you know PHP5 is what we did it uh you [2:31] know for a long time before PHP7 came [2:33] out. So all of the code that you know [2:35] the examples and stuff you're going to [2:36] see the only differences will be type [2:38] hinting uh on the returns and stuff like [2:40] that that uh you know you'll see from [2:41] PHP7 but other than that nothing changes [2:43] to go back to PHP 5. Uh we're also going [2:47] to take a break in the middle um right [2:49] around 11 when they um the other session [2:51] gets out just you guys use the bathroom [2:53] get another cup of coffee or whatever. [2:56] Uh also you know as we're doing [2:58] exercises if you need to leave you know [3:00] whatever that's fine too. So [3:03] to get into you know why why are we here [3:06] today? Um why you know why are you here? [3:08] Why am I here? Because you know I'm here [3:09] for the same reasons. I want to become a [3:12] better developer. I want to be uh a [3:14] better resource for my organization. Um [3:16] you know I believe in becoming becoming [3:19] a craftsman meaning having better code [3:22] craftsmanship raising the level of my [3:24] code and becoming a more mature [3:26] developer and becoming a more mature [3:29] developer means um better understandings [3:31] of the problems that you're trying to [3:32] solve. Becoming uh you know more of a [3:35] value uh for the company that you work [3:37] for or for your customers. [3:41] One of the best ways that I know to [3:43] become a better developer is through [3:44] domain driven design [3:46] and domain domain driven design. It's [3:50] often referred to as DDD uh in the the [3:53] you know cool kids on the street call it [3:54] that. Um but it's a very very large [3:59] topic and there's no way I can teach you [4:01] everything in about two and a half hours [4:02] we have today. Uh but I'm going to try [4:04] to show you what I think are the [4:06] fundamentals and insights that everyone [4:08] uh can benefit from hearing. So um you [4:11] know anytime a presentation starts with [4:13] a survey or a definition definition I [4:15] immediately hate it. Uh but I am going [4:16] to start with a survey and a definition [4:19] because I want to kind of find gauge [4:20] this because it's gonna be you know kind [4:22] of a workshop. I want to know um couple [4:23] of questions here. So does anybody know [4:25] BDD or has experience with DDD at all? [4:29] One person. Okay. Do okay. [4:31] >> You've read it. Okay. So this will be [4:33] this will be fun. Um [4:36] yeah, it's going to be a very beginner [4:39] um introduction. I think it'll be good [4:40] for you and then I'm going to give you a [4:42] ton of resources at the end so you guys [4:44] can go and learn more and you know [4:45] obviously answer questions. So let me [4:48] tell you what DD is not. It is not drink [4:50] drive and develop but we are going to be [4:54] talking about beer today. So please [4:56] drink responsibly and code responsibly. [4:59] No. Uh so today's talk and today's [5:01] workshop is on common sense software [5:03] development and when I mean common sense [5:06] software development I mean you know [5:08] doing things that make sense as as it [5:10] says um you know to as every [5:13] presentation should steal a quote from [5:15] Steve Jobs um design is not just what it [5:18] looks like it's and feels like design is [5:21] how it works. If you look at the [5:23] circuitry of an Apple computer, you [5:26] know, the old ones, they're they're [5:27] beautiful compared to most, you know, [5:29] computers of the time. Uh, and your code [5:32] should be beautiful, too. There's not [5:33] much more effort to be put in in order [5:35] to make your code, you know, more repres [5:37] more more presentational. [5:40] So, um, because software to me is first [5:42] and foremost about problem solving. Now, [5:45] Freddy Krueger is an excellent problem [5:47] solver. He is designed to kill and is [5:49] very effective at it. But what I'm [5:51] saying is people will enjoy your [5:53] software much more if it's more like [5:54] James Bond. Still designed to kill [5:56] people, okay? But, you know, you're [5:59] going to want to hang out with James [6:00] Bond at a bar more, you know, and drink [6:01] a martini and things like that. So, you [6:03] want to get the job done, but do it in [6:06] an aesthetically pleasing manner to both [6:07] you and your clients. [6:11] So, the bulk of the information I'm [6:12] going to talk about today are from these [6:14] two seminal books on domain driven [6:16] design. Uh the first one domain driven [6:18] design uh was a book by Eric Evans. Uh [6:21] he wrote it in 2004. Um you can kind of [6:23] think of this uh as the Old Testament of [6:27] domain driven design. Uh the first time [6:29] I read it, I did not understand it at [6:31] all. Maybe I'm a little dense, but it's [6:33] a very very theoretical book and it but [6:37] once you understand more of the you know [6:39] experimental side of things and you go [6:40] back it makes a whole lot more sense. Uh [6:43] the second book uh was by Von Vernon. [6:45] People call it the uh the red book, you [6:47] know, kind of the new testament of [6:48] domain driven design. And this goes into [6:51] much more practical application of how [6:53] to uh build your code uh using domain [6:55] driven design. There's been plenty of [6:58] books afterwards once everybody got on [6:59] the gravy train of domain driven design. [7:01] Um you know, if you want to learn more [7:03] about the techniques and things like [7:04] that or um you know, if you just you [7:06] were like me in high school and just [7:07] read the cliff notes, the domain driven [7:09] design books on the end in PHP and do [7:12] domain driven design quickly. um those [7:14] were, you know, good good uh source [7:17] material to get going quicker. [7:20] But, um first off, like when I'm talking [7:23] about the code and patterns and stuff [7:25] like this, none of this stuff is new. [7:27] Nothing that the domain driven design [7:28] people um created was new. It was all [7:31] looking at patterns that had already [7:32] existed in software development for a [7:33] long time, whether that's repository [7:35] patterns and object-oriented program um [7:38] things like that. And you know, most of [7:39] this comes from books that are even [7:41] older than the books that I just talked [7:42] about. [7:43] Uh, a couple people that I want to thank [7:46] real quick from the PHP community is [7:47] Matteas Reyes and Bo Simonson. They've [7:49] been um, you know, fantastic uh, pushers [7:52] of DDD and PHP and couldn't do this [7:56] presentation without them. Okay, so for [8:00] those of you who haven't heard about do [8:02] main driven design, this is your [8:04] definition. So if you read the Wikipedia [8:06] definition of it, um, you kind of get an [8:08] idea. uh DDD is about focusing on the [8:10] core business problems that you're [8:12] trying to solve, developing a valuable [8:15] collaboration with the other people who [8:17] have a stake in the process or in the [8:19] project that you're you know you're [8:20] building and then trying to model uh the [8:23] objects in your software in a way that [8:25] is both understandable and maintainable. [8:29] So DDD is really meant um to help you [8:33] tackle really complicated problems much [8:35] like putting together IKEA furniture but [8:37] for software. Um so you know we're going [8:40] to be trying to figure out the model, [8:42] how to model what the business is trying [8:43] to do it and then figure out how to [8:45] apply that model to code. [8:49] So, if you don't have a good grasp on [8:50] object-oriented programming um so far, I [8:53] apologize. Uh but this is going to be [8:56] very object-oriented uh heavy. And when [8:59] I mean object-oriented programming, I [9:00] don't mean how they teach you [9:02] object-oriented programming about how [9:04] you know dogs drive and cars bark and [9:06] those kind of things. Um this is [9:08] object-oriented programming how it was [9:09] meant to be. If you go back and read [9:11] some of the older books on [9:12] object-oriented programming from small [9:13] talk and things like that, um you're [9:17] gonna this is where the DDD people, you [9:19] know, read this and applied it to new [9:22] software practices. [9:24] So to summarize DDD, we're going to be [9:26] talking about encapsulation. So [9:28] encapsulating business rules and things [9:29] like that in logic, immutability, [9:32] um something that's going to make your [9:34] software much easier to maintain and [9:36] write, modeling. So, we're going to talk [9:38] about modeling objects and entities and [9:41] uh stuff like that and behavior and [9:43] encoding the behavior of the business or [9:44] the process that you're trying to model [9:46] in into your software. [9:49] So, when I when I say the word domain, [9:51] I'm talking about the problem we're [9:52] trying to solve. So, or the problem [9:54] space is it's kind of a universal word [9:56] in the sense it's either the problem or [9:57] the this problem space. So, for me, my [10:00] domain is, you know, oil spill response, [10:02] but that's probably not very exciting to [10:04] you guys. So, we're going to talk about [10:06] something I'm much more excited about, [10:08] which is beer. So, uh I'm sure many of [10:11] you have been to a brewery. Um do any of [10:13] you home brew or veryware know how to [10:16] brew beer? [10:18] Great. So, we got at least a couple of [10:20] domain experts in the room here. Um I've [10:23] been brewing for 15 years and I'm 34. [10:27] So, do the math. [10:31] I I found out you could buy all the [10:33] ingredients in college and you know they [10:35] don't stop you. [10:37] Um so we're gonna we're going to try to [10:39] model the process of uh you know doing a [10:41] brewery. I sent you all a handout out um [10:43] it's got some stuff in it about brewing [10:45] and whatnot. Um but my first job out of [10:48] college uh or sorry in college still as [10:50] a co-op was in the beverage industry. I [10:52] worked for a company that built um [10:54] high-speed packaging equipment uh for [10:56] Budweiser and Heineken and stuff like [10:57] that and they could package 300 cases of [10:59] beer a minute. So it's an industry that [11:02] I you know familiar with um on both [11:04] sides you know and so we were we were [11:06] writing and I can't show you the screens [11:07] that we were writing but um you know we [11:10] were writing human machine interfaces uh [11:13] you know for those big giant machines. [11:16] Again, I hope that, you know, this [11:18] presentation is both going to get you [11:19] wanting to do domain driven design and [11:21] brew your own beer at home. But I I you [11:23] know, domain driven design is very safe. [11:25] You don't have to worry about it. But [11:26] brewing can be dangerous. There's hot [11:27] liquids, there's steam, things like [11:29] that. Please, if you're going to go into [11:30] it, be safe. Be careful. Um care about [11:33] your safety very much. Uh if you want to [11:36] learn how to brew, first thing is grow a [11:37] very big beard. Uh no, that's actually [11:40] not necessary. I can't. So, but I'm [11:42] doing fine. Um there is a book that's [11:44] out there that's called How to Brew. [11:45] It's kind of the seinal uh knowledge [11:47] that's out there. But uh on the first [11:49] page of your handout, I've got this [11:51] diagram and you kind of refer to that uh [11:54] today, you know, as we do some of the [11:55] process modeling, things like that. Um [11:58] this is my favorite diagram of the [11:59] brewing process. Um because one I think [12:01] it it shows you that you know the things [12:03] are going into the process but it also [12:05] um has two features that I really like [12:07] is that you know it everything goes [12:09] through the process of milling the grain [12:11] and mashing the grain which is like when [12:13] you you put the grain in at 150 degrees [12:15] 158 degrees of water that's like 65 C if [12:18] anybody's international or not [12:21] imperialist. um to put the the grain in [12:24] the mash ton um which is this container [12:27] right here and it steeps for like an [12:29] hour depending on how long you're [12:31] needing to do it. You separate the grain [12:34] from the water and that's called spent [12:36] grain comes out and then um you take the [12:39] liquid that's left over from the grain [12:41] and then that's what you boil and that's [12:42] what you throw in the hops which is what [12:44] gives beer that bitterness and that that [12:46] flavor. You boil that, you cool it down, [12:49] you put it in a a fermenttor, which is [12:51] either a giant stainless steel vessel or [12:53] a bucket. You put um an air lock on it, [12:55] so you separate it from the outside [12:57] environment, so no back bad bacteria and [12:59] things like that get in. You add your [13:02] yeast, which is usually um a brewer's [13:05] yeast, which you can buy at a, you know, [13:07] a shop, and it usually fermentss maybe [13:10] two weeks, three weeks, depending on [13:11] what you're making. Um, some beers you [13:14] can make at room temperature. Others [13:15] like loggers you need to do cooler. So, [13:17] there's some, you know, there's a lot of [13:18] things you can you can do with this [13:19] process to make different types of beer. [13:22] And then usually it comes out of the the [13:23] ferment into a keg or into bottles and [13:25] is carbonated either using force [13:27] carbonation or if you add a little bit [13:29] more sugar back into the beer, you can [13:32] get uh, you know, it can condition in [13:34] the bottle so it can carbonate it. So, [13:35] yeast when they eat sugar, there's two [13:38] things that come out. There's CO2 and [13:39] alcohol. few and a few other things, but [13:41] for the most part CO2 and alcohol, which [13:43] is, you know, the things we really like. [13:45] But the reason I really like this [13:47] diagram is that, you know, as the [13:48] process goes through this way, on one [13:49] end you get beer, and on the other end [13:51] of the spent grain, you get bacon. So, [13:54] those are two really good things. [13:58] So, just to show you some of the [13:59] ingredients that um you know, these are [14:01] this is barley. Um I've got some the [14:03] ingredients up front you guys can take a [14:05] look at. Um then you you know malt the [14:07] barley as I said you know it look a bit [14:10] closer look after it molts it turns you [14:11] know brown a little bit toasted. This is [14:13] a picture of the mash tun where they're [14:14] mixing the grain and the water. These [14:18] are hops. Um you don't usually see hops [14:20] in wild most places. So they're grown in [14:24] big farms for the most part. Um that's [14:25] what a hop looks like. Um you know [14:27] they're about that big or so. And then [14:30] it goes into the boil kettles. So you [14:32] can either do loose leaf hops like this [14:33] or you can buy it in pellets. So, this [14:35] is um boiling the the liquid that came [14:38] off of the grain that was separated from [14:39] the grain with the hops. And that helps [14:42] extract some of the flavors and stuff [14:43] from the hops. And then you cool it [14:46] down, add your yeast, which is uh the [14:48] little bugs, which we want bugs in our [14:50] beer, but not in our software. And then [14:52] put it in a ferment, and out comes beer. [14:56] So, you know, and everybody hopefully [14:58] likes beer, but if you don't, I [14:59] apologize. Uh these are a couple beers [15:01] that I brewed. Uh so you know why am I [15:04] talking so much about beer? Well, we're [15:06] going to be making beer brewing software [15:08] here today and there there are plenty of [15:09] examples of uh beer brewing software. Um [15:12] this is one that I use a lot. Uh it's [15:15] called uh brewer's friend. It's okay. Um [15:18] this is a recipe uh that I made uh for [15:21] the conference here. It's the Northeast [15:22] IPA. [15:24] So um we will be uh I'm not going to [15:27] have any during the workshop because you [15:29] know I want guys to stay focused. But I [15:31] do I did bring some bottles of it with [15:33] me. I also have my heavites [15:35] uh with me as well so we can sample that [15:37] later. There's plenty of software out [15:38] there already. So we got some good [15:40] examples to look at if we need to. Uh [15:41] beer smmith is probably the most widely [15:44] used. Um it is very complicated and I [15:46] realize that picture is kind of blurry [15:48] but it doesn't matter because there are [15:50] so many knobs and switches and [15:52] everything in the software. It's [15:53] ridiculous. [15:54] Um this is uh supposed to be the easy [15:58] water calculator. um very very many [16:01] fields in an Excel spreadsheet to fill [16:03] out. Um this is the not easy uh water [16:06] calculator. So when you're putting your [16:08] water in your beer, you want to kind of [16:09] adjust um you know various minerals in [16:11] it and stuff like that to uh try to [16:13] figure it out. And you tend to have to [16:15] use like multiple pieces of software all [16:16] together. Uh and then you know people [16:18] can get um 16,000 views on YouTube for [16:22] how do you use the two pieces of [16:24] software together because it's really [16:25] complicated. Um you know and I mentioned [16:28] Brewer's Friend. This is one that I've [16:30] used that's not terrible. Um, there's [16:32] another one, a brewer wall that's more [16:34] like calculations and stuff like that. [16:36] It's kind of useful. Um, so I've got in [16:39] my head the last like month or so. I'm [16:41] going to write a new piece of software [16:43] and I'm kind of using it to do some, you [16:45] know, the examples here and you know, I [16:47] told my wife I need time to work on [16:48] software, but it's for the conference. [16:50] Don't, you know, it's not for this [16:52] stupid hobby of mine. Um, that costs way [16:55] too much money. But anyway, uh, so [16:58] beeriously is what I'm calling it. And, [17:00] um, hopefully you learn if you're [17:02] writing beer software. I don't if you've [17:03] seen this XKCD comic or not, but it [17:06] talks about programming seal with the [17:08] amount of blood alcohol concentration. [17:10] And they call it the bomber peak. So, if [17:12] you get it right around a 0.12, [17:15] you're um, you're an excellent [17:16] programmer. So, that's what I would [17:17] highly recommend everybody try. So, [17:20] that's enough about about how you know [17:23] the process of brewing and stuff like I [17:24] just want to get you guys familiar with [17:25] it. Um, but you know, if you're going to [17:28] build software to manage a brewery and [17:31] you know, say that, you know, you've [17:32] walked into a brewery and they've asked [17:35] you, okay, you're going to build [17:36] software for you. Now, most developers [17:38] when they start thinking about software, [17:40] um, you know, they start thinking about [17:41] the data that the software is going to [17:43] have. So, they're they're worried about, [17:44] okay, we're going to need a recipe table [17:45] because obviously this brewery needs [17:48] recipes. We need a we need a hop table [17:50] because we're going to store like, you [17:51] know, data about hops and things like [17:52] that. need a grain table. You know, [17:54] we're identifying the data and stuff [17:57] like that. And that's kind of how our [17:59] developer repa reptile brains work. You [18:02] start thinking about data and the [18:04] infrastructure and things like that. You [18:05] know, okay, we need a hop inventory uh [18:07] database. You know, are we going to use [18:08] NoSQL or MongoDB? You know, these kind [18:10] of questions start popping into your [18:12] head. I don't know if it's the ADB [18:13] kicking in or if it's just all [18:14] developers. But I mean, I think that's, [18:16] you know, kind of how our brain starts [18:17] working. We just start flying off the [18:18] handle. We haven't even, you know, [18:20] thought about the problem we're trying [18:21] to solve. We're already starting to [18:22] think table table. You know, what's the [18:24] events? Oh, we're going to use events, [18:26] things like that. We have a Q. We need [18:27] uh you know, are we going to get rabbit [18:28] MQ? How are we going to do these cues [18:30] and things like this? You know, maybe if [18:31] you're a Symphony developer, you're [18:32] going to um you're already thinking [18:34] about, okay, roll user, how are we going [18:35] to do the permissions, things like that? [18:37] You know, I can't stress this enough, [18:39] but you know, and this is kind of what [18:41] the beginning of this presentation is [18:42] about is just slow down. Try to [18:45] understand the problem you're trying to [18:47] solve. Um, most of us, and I'm, you [18:49] know, guilty myself, is we don't [18:50] actually take the time to try to figure [18:51] out what the problem is. We have, we're [18:53] all these, you know, super intelligent [18:55] beings that have brains that work at a [18:56] thousand kilometers an hour. Um, but, [18:58] you know, you have to stop and think [18:59] about the problem you're trying to [19:00] solve. So, you know, what I'm saying is [19:03] that the imple implementation is [19:04] important. How you implement your code, [19:06] what frameworks you use, stuff like that [19:07] is important, but that's often the first [19:09] thing we start thinking about as [19:10] developers or it's how we identify the [19:12] developers. I'm a Symphfony developer. [19:13] I'm a Laravel developer. I'm a Zen [19:15] developer. No, we're we're here to solve [19:17] problems. It doesn't matter which one of [19:18] these frameworks they use. They're all [19:20] fine except for one. I'm not going to [19:22] tell you which one. No, just kidding. [19:24] Um, see, I could already get people [19:26] hating if I just picked one. No. [19:28] So, um, yeah, there's this saying uh [19:31] people uh don't want to buy a [19:33] quarterinch drill. They want a [19:34] quarterinch hole. They they don't want [19:36] to hire you. Honestly, they don't want [19:37] to pay you money. Why would they want to [19:38] pay you money? What they want is they [19:40] want their problem solved. So, you have [19:42] to identify the problem space. you know, [19:44] you have to work with the people that [19:45] you're going to be working for and [19:46] actually identify is what you're trying [19:48] to solve a problem in the first place. [19:50] Put your, you know, the value that you [19:52] can give to a company, you know, to the [19:54] right place. Make sure you're solving [19:55] the right problem. And remind yourself [19:58] that unless you work for yourself in [19:59] your own consultant, which then, you [20:00] know, your money is made in being part [20:02] of the problem. Remind yourself that [20:04] your your job is to make a pile of money [20:06] or save a pile of money for your company [20:08] through software. So maybe writing your [20:11] own DI container, writing your own [20:12] framework, writing your own session [20:13] management, doing password resets and [20:15] stuff like that and not focusing on the [20:17] core business problems is dragging the [20:19] company down a little bit. So you know [20:21] really just relying on frameworks to do [20:23] the things that frameworks do well is [20:24] very important because you're going to [20:26] have enough problems dealing with your [20:27] own code and dealing with the problems [20:28] of the business. [20:32] I like this tweet. I just saw this the [20:33] other day so I added it. But um you know [20:35] despite what newcomers think [20:37] understanding a language framework or [20:38] even algorithms is not the hard part of [20:40] building software and I agree with that [20:43] and I would remind everybody that you [20:45] know we're all probably all using PHP [20:48] today. That's probably not going to be [20:50] the case in 20 years. Hopefully I know I [20:52] still want to be doing my job in 20 [20:53] years. Might be even PHP might be [20:55] another language. You don't know. I mean [20:57] the tools change. We we've all seen the [20:59] tools change in our careers in our [21:01] lifetime. [21:02] the practices and how you approach [21:04] problems that doesn't change. You get [21:06] better and better at this and you learn [21:07] a way of meth a method of approaching [21:08] problems. Your your skills can apply to [21:11] any language or any job. There's a a [21:14] whole methodology of I don't want to you [21:16] know bore you too much um but there's [21:18] this whole methodology of trying to [21:19] figure out what is the problem you're [21:20] going to solve. It's jobs.org and you [21:22] know he has this whole spiel that he [21:25] does like a telemarketer or something [21:26] like that about you know milkshakes that [21:28] you can hire them. Um but you know [21:31] really the whole the whole idea is um [21:35] you know why why is the person using [21:37] your software Monday at 8 a.m. you know [21:40] try to understand them and get in their [21:42] mindset and not try to just you know [21:44] build feature feature feature feature [21:45] feature feature that may not be actually [21:47] what they need try to under understand [21:49] the problem that they're doing or the [21:51] problem that they have you know and try [21:53] to put yourself in their shoes. One way [21:55] you can do that and this is from you [21:56] know from them the jobs to be done is [21:57] the five W's and the problem is here if [22:01] you're the people that you're working [22:02] for are probably not software developers [22:03] they're probably not software designers. [22:06] So you know if you show them something [22:08] and the first thing they see they're [22:09] like wow that's awesome you know you've [22:12] impressed them sure but maybe you [22:14] haven't actually solved their problems. [22:16] So [22:17] what we want to do is go from somebody [22:19] saying like wow that's great to of [22:21] course that's how it should be. So that [22:23] that's where we want to end up with with [22:25] our software is of course that's how it [22:27] should be. [22:29] Otherwise you might end up with you know [22:30] a beautiful app but it delivers artisal [22:32] toast or something like that something [22:33] silly. We want to solve a real problem [22:35] here. So an example of the five W's. [22:37] Like let's say you walked in the brewery [22:39] and I'm going to suggest that you do a [22:41] drink for every Y here as part of the [22:43] plan here. Um but say you know the [22:46] brewer says you know oh I need a list of [22:47] grain in inventory. So, okay, you know, [22:50] if you're the the quick and easy [22:51] developer, you're just going to say, [22:52] "Yep, I'll give you a list of out of the [22:54] database. Select all." You know, you [22:56] know, whatever. But, you know, if you're [22:58] thinking, you're going to ask that [22:58] brewer, why do you need this list? And, [23:00] you know, the brewer is going to say, [23:01] "Well, because, you know, I need to be [23:03] able to sort the list of grain to see [23:05] the inventory to see which one I'm [23:07] running low on." Well, if you ask him [23:09] why again, he's going to say, "Well, [23:11] because, you know, when we formulate a [23:12] recipe, we need to check and see how [23:14] much of a particular grain we have on [23:16] hand." Then I have to figure out, okay, [23:18] how much do I need to brew that recipe? [23:21] I'm going to do the little math in my [23:22] head and figure it out. So, at this [23:23] point, maybe you're thinking, oh, you [23:24] know, I can build a search mechanism out [23:26] of that list. I can list the inventory [23:28] right there. But if you don't keep [23:30] asking why, you're not actually going to [23:31] get to a better solution. So, if we ask [23:33] them a why, well, why don't we [23:35] automatically calculate how much grain [23:36] is needed to order? you know on the [23:38] brewery recipe creation process that's [23:40] you know handled by the brew master um [23:43] you know in the ordering may be a [23:45] completely separate department but you [23:46] know if you ask the questions why you [23:48] might figure out that you know why can't [23:51] we just automate the process why can't [23:52] we say when like you know recipes [23:54] designed and it's we're scheduled the [23:56] brew session we just automatically order [23:58] the stuff if you don't ask the why why [24:01] why you know you start up with you know [24:03] what is maybe the simplest solution it [24:05] will take you least amount of time but [24:06] you end up with automation and what is [24:08] real powerful software that's going to, [24:10] you know, save the businesses tons and [24:11] tons of time, perhaps tons and tons of [24:13] money. [24:16] So, you know, DDD, just to kind of [24:19] phrase it all over, is not about the [24:21] patterns. It's not about, you know, [24:22] you're going to hear things about CQS [24:24] and event sourcing, all these fancy [24:25] things in DDD. They don't matter. Um, [24:27] it's not about adding tons and tons of [24:29] complexity to problems. If you have a [24:30] simple problem, you know, keep it [24:32] simple. So, DDD is not for every [24:35] project. It's not even for every part of [24:38] a software application perhaps you know [24:40] um we're trying to keep a um things [24:43] simple you know as Kiss keep it simple [24:45] stupid but so don't use what I'm you [24:48] know kind of teaching you here for you [24:49] know things that are simple crud like [24:52] you have a data entry form and you need [24:53] to display that like don't don't bother [24:56] this you know use Laravel or something [24:58] like that it's going to be much faster [25:00] um you know don't use it for content [25:01] sites or websites like we have like I [25:03] said I I build applications for the [25:04] company I work [25:05] We didn't use DDD at all on our website. [25:07] Like it, you know, a little bit for some [25:09] of the stuff, like pieces of it, but for [25:11] the most part, it was just, you know, [25:12] it's content. It's not it's not worth [25:14] it. Um, you know, don't use it where [25:17] you're doing functional programming [25:18] things like that. Um, if you take it to [25:21] the extreme, you end up with, and this [25:22] is a great GitHub project to go check [25:24] out. It's enterprise quality coding, the [25:26] Fsbuzz Enterprise Edition. I think it [25:29] solves the FSBuzz problem in like 8,000 [25:31] lines of code or something. I can't [25:32] remember exactly but and you know just [25:36] to kind of iterate it or sorry to [25:38] finalize it you know that DDD is not the [25:40] one true way to build software that is [25:42] obviously Ruby on Rails. [25:47] Okay so all of the normal solid [25:48] principles apply for doing good code. Um [25:51] you know if you don't you not have a [25:52] good grasp on this you know maybe you [25:53] spend a little time and read about it. [25:56] But what we're concerned about today is [25:58] the quality of the software and quality [26:01] software. Um if you look at you know [26:04] research about you know what is good [26:05] quality software. Carnegie Melon uh has [26:07] a great uh training program for that. Um [26:10] we talk about you know what are the [26:12] things that make good software good and [26:15] I'm going to pick like five out of these [26:17] you know big giant uh list of software [26:20] quality. And you know that's what I [26:23] think are the most important is [26:24] correctness meaning the software you [26:26] know works as expected testability [26:29] usability [26:31] maintainability and modifiability. So [26:33] you know just what I think are the five [26:35] most important things about good [26:36] software. And we're going to compare a [26:39] DDD app domain driven design app against [26:41] you know your usual CRUD app what mo [26:43] most of us learned how to develop uh [26:45] doing [26:47] uh Mattas Reyes who I mentioned earlier [26:49] has a lot of great blog posts but this [26:50] is a good one. It's CRUD is an [26:52] antiattern um you know designing your [26:56] software to modify data in a database [26:58] but not creating software for behavior [27:01] um will cause you problems over time. [27:03] Um, people in the DDD [27:06] world, you know, they don't they don't [27:07] call it CRUD apps. They have another [27:09] name for it. It's called the big ball of [27:10] mud app. And I'll get into kind of [27:13] explaining that in a minute. Um, but if [27:15] you were to um, you know, compare like [27:17] what kind of apps you should use in DDD, [27:19] even in a brewery versus CRUD, like I [27:21] said, if you're going to do recipe [27:23] building and brewing sessions and [27:24] calculations, that's all going to be [27:25] good stuff for DDD. The crud mud side of [27:28] things might be the inventory because [27:29] it's just, you know, it's basically [27:30] read, update, and delete the beer menu. [27:32] You're just adjusting prices and things [27:34] like that. It's probably not very [27:35] important to the business um to, you [27:37] know, have good modeling and good [27:39] practices in place. [27:43] So, who is responsible um for this this [27:46] software being good? You know, who's [27:48] going to be responsible for this? Well, [27:50] it's both you and the domain experts. [27:52] you know, Lord Business here or, you [27:54] know, as we call them, the the product [27:55] owners, the domain experts, you know, so [27:57] in the brewing case, you're going to be [27:58] talking to the brew master. You're gonna [28:00] be building a software for him or her. [28:02] That's the person whose problems you're [28:03] trying to solve. [28:05] Now, you're going to have to work with [28:07] that person because, you know, maybe he [28:09] or she is not, you know, a big software [28:11] developer, doesn't know what's possible. [28:12] You guys are all very intelligent. Very [28:15] intelligent. And you know what is [28:17] technically feasible in software. They [28:19] they don't know what's possible both [28:20] from Yeah. that that's completely [28:22] impossible. We could never do that to [28:24] yeah, that's going to take me 10 [28:26] minutes. And they're absolutely amazed. [28:27] You know, they have they have no clue. [28:28] They're not technology experts. And you [28:31] also use the internet a lot. So, you see [28:33] um you know, more software, great [28:35] software, you kind of know what software [28:36] you like to use, what is good software, [28:38] what is bad software. [28:41] But you know when you're talking to [28:42] these um these domain experts and I like [28:44] this tweet a lot and it says you know [28:46] what the biggest strategy in software [28:47] engineering um you know talking crud uh [28:50] to the people you're you're meeting with [28:53] um we open the blue book which I [28:54] mentioned was the you know the first [28:56] book like in page 24 of a it's 500 pages [28:59] it's roughly 500 page book so page 24 [29:01] you open basically right up after the [29:03] preamble the first topic that comes up [29:05] is ubiquitous language and ubiquitous [29:09] language is the ultimate power of domain [29:11] driven design. That's if you leave here [29:13] today, there's going to be like two big [29:15] things that I'm going to try to, you [29:16] know, focus on. Ubiquitous language is [29:18] probably the number one. It's not [29:19] necessarily the most important, but it's [29:21] probably the most important. Um, this [29:24] ubiquitous language is a shared language [29:26] that your development team and the [29:28] domain experts agree to speak. Everyone [29:30] on the same page, same word. What a word [29:32] means means the same um to them and you. [29:36] Um the power of DDD here is [29:38] understanding the business mindset, the [29:40] language and solutions, understanding [29:42] how the business implements the [29:44] solutions to its problems. So like I [29:45] mentioned that process of brewing beer. [29:47] If you don't understand that process, [29:49] you're not going to be able to write [29:50] software that builds that. You know, if [29:51] you're just editing fields in a [29:53] database, you're not actually building [29:55] software that's going to solve problems. [29:57] Um you know, some examples of language [29:59] that you're going to try to share with a [30:00] brewer. You know, brewers call them [30:03] sessions or session beers. We have [30:05] session database sessions, things like [30:07] that. You know, user sessions and [30:08] cookies. You know, if we start saying [30:10] sessions and they start saying sessions [30:12] and we're not saying the same word, it's [30:13] going to be confusing later. Um, [30:17] you know, this this ubiquitous language [30:18] again, it's one of those things that, [30:20] you know, as tools change, when you [30:21] switch from PHP to JavaScript, stuff [30:22] like that, this will stick around. This [30:25] is lifetime guarantee stuff. I mean, [30:26] once you learn how to use this and apply [30:28] it effectively, um, you know, it's going [30:30] to be a skill that you can keep forever. [30:31] Um you know as von Vernon says in the [30:33] red book DDD is primarily about [30:35] discussing listening understanding [30:38] um it's about discovery you know finding [30:40] out what what is going on in the problem [30:42] and creating in your codebase a [30:45] centralized knowledge uh for the [30:46] business. So your code should accurately [30:48] reflect the business's problems and the [30:51] solutions to those problems and you're [30:53] going to see speak the same language. So [30:55] everything that's in the you know how [30:57] the business works should be in your [30:58] code. you know, it should be a one to [31:00] one mapping. Um, you know, so the what [31:03] I'm saying kind of is that domain driven [31:04] design in the ubiquitous language should [31:06] be speaking an idiomatic language. So [31:08] whatever the business calls something is [31:09] what you should be calling something. [31:11] Um, I'm guilty of this too, but you [31:13] know, you have a you have a user table [31:15] probably in your database somewhere. So [31:17] you have a user object. Well, they don't [31:19] call them users. The only people who [31:20] call things users are drug dealers and [31:22] developers. [31:24] you know, [31:25] they refer to people as brewers or [31:27] employees or tasters or customers. So, [31:30] you know, is it really that much hard [31:32] effort on your part to rename the class [31:33] to brewer? I mean, it's not that big of [31:35] a deal. Um, so when you go to talk to [31:37] them, you're saying the same words that [31:38] they're saying. I mean, it's it's so [31:40] much simpler. Um, guys, I'm sure aware [31:42] aware of David Letterman. He has, you [31:44] know, the top 10 lists. Um this is the [31:46] binary version of the top you know two [31:48] reasons that programming is hard is [31:51] naming things cache invalidation and off [31:53] by one errors. [31:55] So the end result of this is that um the [31:59] naming things should be really easy like [32:02] you should never have that problem [32:03] again. If you understand the business's [32:05] problem you talk to them and you share [32:06] the same language they they are pretty [32:08] much going to name the things for you. [32:10] You'll you know be able to apply this [32:11] directly to your code. [32:14] So, I'm not picking on Laravel at all [32:17] here. Um, they're fine. But, you know, [32:20] most of us developers have at one point [32:23] probably written code like this where [32:24] you're just pulling stuff off of the [32:26] database. Um, you know, find or fail [32:28] where name equals something. Take one [32:32] get recipe hops array contains hop ID. [32:35] If, you know, we have this if check in [32:36] this if not right here, this exclamation [32:39] point. Hops array attach hop ID and then [32:42] maybe some data. And then you have to [32:43] save. Now, imagine if you showed a [32:45] brewer this code. You know, their [32:48] reaction would probably be, "Huh? What?" [32:52] You know, you don't um take a hop [32:57] off the hop repo. You know, they go and [32:59] they get it out of the grain out of the [33:01] storage, the cooler. They don't take it [33:03] and then get it. Like, that doesn't make [33:04] any sense. Um, you know, the recipe [33:06] doesn't have a hops array. That's that's [33:08] not something that means something to [33:09] them. They don't attach a hop to a [33:11] recipe. that's that's not how they're [33:13] thinking. But for some reason, we've [33:14] written code like this and that's just [33:16] how we've siloed ourselves in the world. [33:18] We've completely ignored how everybody [33:20] else thinks. [33:22] So kind of, you know, and this is like [33:24] it's going to seem to you completely um [33:26] simple because it is, [33:29] but when they say to you, we need to be [33:30] able to add a measured amount of grain [33:32] to a recipe, you should have a method on [33:33] your recipe object called add grains. [33:36] Sorry, pushed the wrong button. You [33:38] should have a method called add grains [33:40] or add grain. [33:42] You know, we need to be able to [33:43] calculate an estimated uh that's alcohol [33:45] by volume for a recipe. They'll say ABV. [33:47] So, you know, if you need to kind of not [33:50] remember, you can't remember what ABV is [33:52] all the time. Maybe they have some, you [33:53] know, specific words that they use, put [33:56] those in a method together. You know, [33:57] recipe, get estimated alcohol by volume [34:00] ABV. You know, put the words that [34:02] they're using in your methods and in [34:03] your objects. [34:07] you know, we need to know how much [34:08] winter wheat is in our storage silo [34:11] number four. Well, we'll go to the sto, [34:14] you know, you can say new storage [34:16] facilities. Okay, that's, you know, we [34:17] have to do that kind of stuff because [34:18] that's how peachy works. We have to have [34:19] some, you know, constructs and things [34:21] like that. But they could probably [34:23] understand this. You know, you're going [34:24] to you look at the storage facilities [34:25] and find the storage facility by name, [34:27] silo number four, and then storage, how [34:30] much grain of type, new grain type, [34:32] winter wheat. So, you know, they can [34:34] kind of get this. I think it's starting [34:36] to get more technical, but it's still [34:38] much more understandable with somebody [34:39] just looking at this. [34:42] You know, things get much more [34:43] complicated, you know, in this kind of [34:44] brewing software and I'm sure in your [34:46] software packages, you know, we need to [34:47] add 02 ounces of a 12 ounce 12% alpha [34:50] acid per gallon of Simco hops to recipes [34:53] at a 7day after the boil is complete. [34:55] And that's called dry hopping. So, um, [34:58] you know, the bottom here kind of [34:59] showing you as things get more [35:01] complicated, but it's still readable. [35:04] If you're probably already, you know, [35:05] your brain's already thinking, but um [35:08] can you imagine this is not very [35:09] difficult code to write. Like there's [35:11] not much change between what I showed [35:12] you before and what I'm showing you now, [35:14] but it's all in the naming and how [35:15] you're going to apply things. And later [35:17] when you're like they're like, "Oh, we [35:19] want to see how that dry hopping thing [35:20] works in the software." You go, "Oh, [35:22] yeah. Let me find the dry hop method." [35:23] You know, search your whole entire [35:24] codebase for dry hop. It's all going to [35:26] come up. [35:28] Oh, by the way, if if there's anything [35:30] you're not understanding, on the back of [35:31] that packet, I have a glossery. So like [35:34] the last page if I'm using words in [35:35] brewing industry that you know like dry [35:37] hopping that's that's adding uh hops in [35:39] after the fermentation. So boil is [35:41] already done. Beer's almost ready to [35:43] drink. You're adding the hops in right [35:44] before it's uh consumed. So um but you [35:49] know maybe if you're using be hot or [35:50] girkin languages and things like that [35:52] you're already doing this but you don't [35:53] realize it. You're putting these in your [35:54] scenarios and features. You know a user [35:56] should be able to dry hop a recipe. User [35:59] adds dry hops. You know right there is [36:01] where you know that's your method names. [36:02] you're not realizing it, things like [36:04] that. But if you're not, you know, [36:06] you're just applying this, you know, you [36:08] know, if you go in here and you, you [36:09] know, in BOD, if you like tell it to [36:11] generate a step definition, it's [36:12] actually going to generate a step [36:13] definition like a user should add, you [36:15] know, dry hopping, you know, whatever. [36:17] And that's exactly what the method [36:19] should be, you know, on your objects [36:20] later. [36:22] And as I mentioned, this ubiquitous [36:23] language, it's something that you both [36:24] agree u to speak. So they call it dry [36:28] hop. You know, you're going to have a [36:29] method called dry hop. Maybe they have [36:30] they're like, "Oh, we just, you know, [36:31] get a bunch of ingredients. We throw [36:32] them together. So you have your [36:33] ingredient, you know, uh adding it to a [36:35] boil. We add we added it to a boil [36:37] kettle, you know, it's just different [36:38] ways that you know, some of you know the [36:40] people that you're working with talk, [36:41] you know, and what they speak, maybe [36:43] where you're from, you know, what [36:44] country, you know, maybe you wanted to [36:45] use some of the words that are local, [36:46] but understand their language, speak the [36:49] same language and apply it directly to [36:50] your code. And, you know, we're going to [36:52] get into um some of like building [36:54] business rules and things like that [36:56] using, you know, this language. So like [36:58] the last one, you know, we could have a [36:59] recipe add to mash ton and there's no [37:02] reason you should put be putting hops in [37:04] that part. It's just the grain. You [37:06] know, we're going to build some of these [37:07] log this logic in here to you know, fail [37:08] on things like that. [37:11] So you know, you're going to have um you [37:14] know, this wouldn't be all all one [37:15] method, but you know, just to kind of [37:17] you know, summarize the whole thing [37:19] about naming your stuff. Um, you know, [37:21] for the most part, a brewer should be [37:23] able to understand this and figure out [37:25] what is going on. Even if they're not a [37:27] software developer, it pretty much reads [37:28] like English. And, you know, when you're [37:31] talking about them about the software, [37:33] um, I don't know how many do does [37:34] anybody here speak a foreign language? [37:36] Like, does anybody learn Spanish or [37:38] German? So, I learned German. And when I [37:40] first started learning the language um [37:42] you know you have to think about what is [37:44] the German word for tree you know it's [37:46] it's bal town and bal that means you [37:49] know whatever you so you have to think [37:51] about the word what is tree eventually [37:53] as you get better at speaking German you [37:55] stop thinking about what is the English [37:57] word for this thing now it's just like [37:59] in your software if you're speaking the [38:01] same language as the person that you're [38:03] developing software for. I don't have to [38:04] think, oh, you know, the the hops uh [38:07] array is actually the number of hops in [38:09] the recipe. Like, I don't have to do [38:10] this translation in my head. You're [38:11] speaking the same language. It's going [38:13] to flow easier and be much easier to [38:15] understand later. [38:20] So, if if you're comparing, you know, [38:22] what is a CredMod app versus DDD? um [38:24] kind of these objects and this naming [38:26] and stuff like that. You know, your [38:28] Cudmud app is going to have users and [38:29] strings and integers and floats and [38:31] arrays of OM objects and things like [38:33] beer inventory repository interface. Um [38:37] DDD app, you know, you should expect to [38:38] see objects called brewer, like a brewer [38:40] or brewers, like a collection of brewers [38:42] would be, you know, brewers. You're [38:44] gonna have an object called recipe name [38:45] that represents the name of the recipe. [38:47] Things like IBUS, which are how bitter a [38:49] beer is, um alpha acids, things like [38:51] that. You're gonna expect to see these [38:52] objects. [38:54] um in a thing in a in the in the [38:56] software. Now, one last topic on the [38:58] ubiquitous language before we start [39:00] getting into you know actually doing an [39:01] exercise is the um natural [39:04] identification of things in your [39:06] software. Now hopefully if you're not [39:08] using UU ids as your database I you know [39:11] definitely recommend [39:13] stop start using UU IDs for all your [39:16] primary keys on your database. make your [39:17] lives so much easier uh as you're [39:19] developing software. But those UU IDs, [39:22] as I'm sure you're aware, are big j long [39:24] giant strings that don't mean anything [39:27] to anybody else other than us. So those [39:29] are our primary keys of our database. [39:31] Most of what you're developing software [39:33] for probably already has natural [39:34] identification built in. So if you're, [39:36] you know, building software for a [39:38] library and books, you know, there's [39:40] already an ISBN number on there. You [39:42] don't have to use that necessarily as [39:43] your database primary key, but all of [39:45] your lookups and things like that should [39:46] be done based on the natural [39:48] identification. Um, it's going to make [39:50] understanding your software later a lot [39:52] easier. Now, you're still going to have [39:54] queries that are by ID, you know, in [39:56] controllers and things like that, but [39:57] when you're actually building uh [39:59] business logic and looking for things, [40:00] try to use natural identifiers. So, if [40:02] we're looking at a bag of hops, which I [40:04] brought some bags and ingredients and [40:05] stuff like that for you guys to look at [40:06] later, you know, there's already some [40:08] natural identifiers on here. They've [40:10] already got a lot number here in the [40:12] bottom of the package. So you can [40:13] identify off of that. The name is a, you [40:16] know, a unique name. Centennial hops is [40:18] a unique, you know, flavor of hops. So [40:21] you know, look at your business and, [40:24] you know, when you're when you're [40:25] finding things out of the repository for [40:27] people, you know, you can find it by [40:28] name by, you know, the string that you [40:29] take in or things like that. You don't [40:30] have to use UIDs everywhere in your [40:33] software. [40:35] All right. To sum up all of this, and [40:37] this is kind of an older book, structure [40:38] of inter uh interpretation of computer [40:40] programs. One I was probably supposed to [40:42] read in my computer engineering [40:45] uh one of my classes at Penn State, but [40:48] you know, I went to a state school, so I [40:49] I learned more about beer than I did [40:51] programming probably. Um but the most [40:53] important thing, and this is a great [40:55] quote, is programs must be written for [40:57] people to read and only incidentally for [40:59] machines to execute. I've been at the [41:01] same place that I worked for for 10 [41:03] years, and I looked back at the code [41:04] that I wrote [41:06] last week. No, I mean seven, eight years [41:08] ago and it's just it's it's almost [41:10] garbage. It's pretty much throw away [41:12] because it's all ORM based. It's [41:14] database driven. Modifying any of that [41:16] is terrifying. Like it some most of it [41:18] doesn't have tests because that was [41:20] before we started testing everything. Um [41:22] but you know to try to make a change it [41:25] it could take you you know a week to [41:27] make a very very small change because [41:29] nothing is encapsulated. Everything is [41:31] just, you know, scripts everywhere and [41:33] doing updates and reads and deletes and, [41:36] you know, you delete one thing one [41:38] someplace and you don't make the updates [41:39] in the other and stuff gets haywire that [41:42] bad things happen. You know, I'm going [41:43] to try to push you guys into a place [41:45] where um, you know, building software [41:47] that's, you know, better and, you know, [41:50] it's more correct. It's going to stay [41:51] correct longer and be, you know, easier [41:53] to change and things like that. All [41:55] right, real quick. you know, as the [41:58] business evolves, um, you know, the [41:59] language evolves, too. Um, so, you know, [42:01] if they decide they're going to start [42:03] changing the names of things, um, change [42:05] them in your software. You know, move [42:06] along with the business. Don't, you [42:08] know, you can't just, you know, stay, [42:10] you know, stuck in the the, [42:12] you know, 20 years ago. You know, we [42:14] don't we don't brew like we brewed in [42:16] the 1600s. Um, because, you know, people [42:19] got sick all the time of stuff like that [42:20] from infections. Um, but oddly enough, u [42:24] beer is very, very safe to drink. almost [42:26] cannot be poisoned um from beer. The [42:28] only thing you have to worry about [42:29] really is um [42:31] what is it? Uh whatever. It's a very [42:34] minor infection. It's in none of my [42:37] beer. Uh I should have wrote it in my [42:39] notes here. Um but anyway, uh you know, [42:43] beer, the alcohol in beer kills almost [42:45] everything. So, it's very safe to drink. [42:47] Um so, even you know, back in the 1600s, [42:48] that's why people drank beer so much [42:50] because it was, you know, safe. The [42:51] water was terrible. Beer was still safe [42:53] to drink. But processes have changed. [42:55] You know, we have giant stainless steel [42:56] fermenters now. We don't they don't use [42:58] barrels, you know, from the 1600s to [43:00] make their beer still. There probably [43:01] are places that do, but most breweries [43:04] don't. So, evolve with your company. [43:06] Evolve, you know, with technology. You [43:08] know, you're you're going to see things [43:09] in the technology side of things that's [43:11] going to change how the business is [43:13] going to operate. It's your duty to go [43:14] to the business experts or the domain [43:16] experts and update the ubiquitous [43:19] language there, too. You know, if you're [43:20] operating a theater, you're not going to [43:22] have a ticket counter forever. You know, [43:24] now there's online ordering, things like [43:25] that. You have to go to the business and [43:26] they're going to they're going to have [43:27] to change, too. You know, that's [43:29] ubiquitous language. It's a two-way [43:30] street. It's not one way them telling [43:31] you what to do. It's, you know, both [43:33] ways. [43:35] All right. This is I promise the last [43:37] thing about ubiquitous language. And [43:39] when I mean ubiquitous, it's not across [43:42] the entire universe. It's not, you know, [43:43] what they call a hop may not be the same [43:46] thing across the entire universe. It's [43:47] not even across the entire organization. [43:50] It could just be that one project that [43:51] you're working on with one team in the [43:53] organization. So, you know, if you have [43:54] many u parts of your brewery or [43:56] whatever, marketing and finance and [43:58] production and inventory, what they [44:00] refer to as a hop may be something [44:01] completely different. So, for marketing, [44:02] it's a you know, it's a flavor. It's [44:04] they're going to market it as something [44:05] that's flavorful and things like that. [44:06] For finance, it's an expenditure. You [44:08] know, it's just something we have to pay [44:09] for it. It's awful. You know, for [44:11] production, that's an ingredient. You [44:12] know, they're building, they're making [44:13] the beer. They're, you know, they're [44:14] dumping it in. For the inventory people, [44:17] it's just, you know, a quantity of a [44:19] thing at a location. That's all they [44:20] care about. So, you know, when you're [44:21] building the inventory system, you're [44:23] going to refer to those hops [44:24] differently. You're going to have [44:25] different methods and you're going to [44:26] namespace like PHP has now, which is [44:28] great. You can namespace those hop [44:30] things into the inventory namespace. So, [44:32] you're going to separate your [44:33] application either through namespacing [44:35] or if you're big enough maybe [44:36] microservices. Not something I would [44:38] recommend you run out and try to do as [44:39] microservices. It gets very complex. But [44:42] even if you have what you know they call [44:43] the majestic monolith big giant [44:45] application that has like I do you know [44:46] we have I don't go I don't know how many [44:48] classes we have in lines it's huge but [44:51] we still break it down you you still [44:53] have to solve one little problem at a [44:54] time so when you go to talk to the [44:56] inventory people you're talking about [44:58] hops you know you might still be [44:59] referencing databases that are similar [45:01] that are used shared across data that's [45:03] shared across but you're going to build [45:04] separate code base you're going to build [45:06] stuff to their language that it's [45:08] understandable by them and [45:09] understandable you and you're speaking [45:10] the same language at the [45:11] Because if you're like me and I've you [45:13] know I've been there for 10 years like I [45:14] said I built software for somebody five [45:16] years ago and then five years now we [45:18] come and we look at it and try to [45:21] understand it again it's going to be a [45:22] lot easier if it's written in this [45:24] language. [45:25] What I'm talking about in domain driven [45:27] design is they call it bounded context. [45:29] So, like I said, we're going to [45:30] separate, we're going to silo our code, [45:31] into the recipe section, into the [45:33] inventory section, the brew house [45:34] section, because in what they call the [45:37] big ball of mud, that's the CRUD app [45:39] that's just got data and updates and [45:41] sets and everything everywhere going on [45:43] that's totally incomprehensible or [45:45] spaghetti code or shanty town code, [45:47] however you want to look at it. Um, you [45:49] know, that that's what you end up with [45:51] if you don't keep things separate. Um [45:53] the way that I recommend that you do if [45:55] you're when you're going to separate [45:56] your code and you know obviously you [45:58] know the brew house is going to have to [45:59] talk to the inventory system. You know [46:01] if you do that spaghetti code you got [46:03] stuff you know flying everywhere objects [46:05] calling methods and other sections and [46:07] stuff like that. If you do that and you [46:09] go to update your system it's not going [46:10] to be modifiable because you want to [46:12] change say you know it's been five years [46:13] and you haven't touched the inventory [46:14] system you want to make an update. Well [46:16] if you've got all these methods that are [46:17] being called in the brew house from the [46:19] inventory system now you have to touch [46:21] both code bases. [46:23] Keep everything siloed, keep everything [46:24] separate. And the way to do that is to [46:26] pass messages between the different [46:28] domains. And you know, you can do that [46:31] however you you know, you feel like you [46:33] use, you know, if you're using Symphony, [46:34] use the event publisher, build your own [46:36] queue, you know, do what do whatever you [46:38] know, your implementation, you know, [46:40] makes it easiest for you to do. But [46:41] you're going to pass these as messages [46:43] or events. You're going to publish an [46:44] event and let for people, you know, [46:45] listen. And, you know, in DDD, we call [46:47] this a a domain event, you know. So, [46:50] we're going to pass these domain things [46:52] that happen in say in inventory, you [46:54] know, uh uh ingredients received. You [46:59] know, it's going to fire up an event and [47:00] now the brew house knows, hey, the [47:01] ingredients have been received. We can [47:03] start brewing. So, we're going to pass [47:04] this message of ingredient that [47:06] ingredients were received. Brew House is [47:08] going to pick that up and then move on [47:10] to its next thing. All right, [47:12] we're just about ready to stop talking [47:15] and start doing, but I wanted to stop [47:16] real quick. Does anybody have any [47:17] questions uh about the ubiquitous [47:20] language and what we've been talking [47:22] about? We're going to start how do you [47:23] actually you know work with a domain [47:25] expert and build this ubicous language [47:27] through an exercise. But does anybody [47:29] have any questions before we do that? [47:42] >> Yeah. Um, so what what you want to do [47:45] there, um, so if you're trying to build [47:47] like a generic app that works for [47:48] multiple people, is that what you're [47:50] saying? Like, so you have like let's [47:51] just say it's a purchasing app and you [47:53] have three companies that want to use [47:54] it, something like that, right? Um, what [47:56] you'll typically want to do is build [47:58] your interfaces like class interfaces in [48:01] the domain language. So what you [48:02] understand is the domain, your [48:04] understanding of the domain. Those will [48:06] be your interfaces. So when you're [48:07] applying or using those interfaces when [48:09] I if I don't know experience level here [48:10] of classes but you have you know you [48:11] have classes which are concrete objects [48:13] you have interfaces which just define [48:15] what a what a class can do. So you want [48:18] to build those interfaces in your domain [48:19] language. Then you'll probably have to [48:21] build custom classes that you know [48:23] implement things differently but [48:25] implement that interface so you can kind [48:28] of keep things separate and you actually [48:30] you know namespace those implementations [48:32] per the client name. They're that [48:34] specific. Um, we have things in our [48:36] company where certain rules are for only [48:38] certain regions in the company. So, you [48:41] know, we want to put that in there [48:42] because you want to know why the heck is [48:44] this doing this? Well, it's because they [48:45] asked us to do it, you know. So, we know [48:46] who asked us kind of thing. So, [48:56] >> yeah, [49:03] pretty much. [49:07] Yeah. Um, definitely naming things like [49:09] that. But what I'm saying is like if you [49:10] have an app where like they're they're [49:12] typing in uh let's say like in a brewery [49:15] they have a QA program where they just [49:16] record values like oh how much [49:18] carbonation was in this? How much acid, [49:20] you know, what was the pH? Things like [49:22] that. You don't really have to build [49:23] that domain driven design. You can let [49:25] Laravel or Symphony or Doctrine generate [49:27] forms for you generate stuff. You know, [49:29] they type it in, they hit save. There's [49:31] not really any business logic there. [49:33] It's just recording. So that would be an [49:34] instance where don't it's a little bit [49:37] more overhead to do DDD stuff because [49:39] you're going to spend more time [49:40] modeling. You're going to spend time you [49:41] know figuring out the language and stuff [49:42] like that. If it's not it doesn't matter [49:44] just do it. I mean it's a balance. [49:57] >> Yeah. [50:07] same thing. [50:16] >> Yeah. I mean, I look at, you know, cons [50:19] like p publishing versus subscribing. Uh [50:21] like kind of like what you're saying, [50:22] like you're you're pushing to an API. um [50:25] that that is code that you're writing [50:27] and you're you're responsible for [50:28] testing that code when you're consuming [50:30] APIs and things like that. Um publishing [50:33] an event out to the system kind of like [50:35] you know wiping your hands clean and [50:37] walking away um from it. So it tends to [50:40] if you have very separate systems it [50:43] tends to work better for things that are [50:44] happening that other systems need to [50:46] respond to. Now again like you're saying [50:48] you may have an API to the inventory [50:49] system or a service that can you know if [50:51] the brew house needs information from [50:53] the inventory system. Yeah. Build what [50:55] they call um so I'll get into this [50:57] hopefully later hexogonal architecture. [50:59] And it talks about what they call ports [51:00] and adapters. And really what you want [51:02] to do is you have a very simple [51:03] interface that's between the inventory [51:04] system and the brew house. So your [51:06] methods very clear. It's kind an API or [51:09] you know again it's a microser you're [51:10] going to separate that into a completely [51:12] different web server. But you want to [51:14] have these very tiny classes that [51:16] transfer those messages across just like [51:17] publishing an event. So you know you can [51:19] still talk to other domains but it's [51:21] done through a very restricted channel [51:23] so that you know when one changes and [51:24] the other needs to be updated you don't [51:26] have to update both sets code bases. You [51:28] just have to update the adapter. [51:31] Okay. [51:42] No, I haven't because I'm usually I [51:44] would usually defer to the business [51:46] because it's their problem you're [51:47] solving. I mean, it's, you know, you can [51:49] convince them otherwise. [51:51] All right. Um, [51:54] any other questions? I'm going to pass [51:55] out some treats. There's a tradition in [51:57] the brewing industry for uh these nut [51:59] rolls. So you guys that ask questions, [52:02] you get a anybody allergic to peanuts [52:04] that I just asked a question. [52:11] Yeah. Yeah. No, too late. I'll have [52:15] extras at the end. All right. So, we got [52:17] a few minutes before the the first the [52:19] break here. [52:21] Um what we're going to build the [52:23] ubiquitous language through is an [52:25] exercise. It's called eventtorming. And [52:27] uh this was done by Albert created by [52:28] Alberto Randolini. [52:31] Um but when you you're building this [52:33] ubiquitous language and this this thing [52:34] you want to go out and actually meet [52:36] with the domain experts. You know having [52:38] somebody spec pass you the specs is not [52:40] the way to build software. You know a [52:42] million tickets in Jira and have a [52:44] burndown chart is not the way to build [52:46] proper software. Um this is me out on [52:49] one of our ships you know meeting with [52:50] the crews and stuff learning how uh to [52:52] build software. UX professionals, they [52:54] call this ethnographic research. It's [52:56] fancy word for saying get yourself out [52:58] from behind your fancy desk that goes up [53:00] and down and get out there and learn. [53:02] You know, in a brewery, that's that's [53:04] actually probably pretty fun, but on a [53:06] ship, it's just smelly and dangerous. [53:08] So, [53:10] and it makes you seasick. Um, you know, [53:12] you'll hear this thing about user [53:14] experience talking about personas. You [53:16] know, don't worry about personas. You [53:18] shouldn't be thinking about personas. [53:20] You know, I love this example of [53:22] personas. It's like, oh, you know, we're [53:23] going to build software for a brewer and [53:26] he loves poetry or she has a library [53:29] science degree and just got a job at the [53:30] brewery. No, you know what? Actually, [53:32] these are all the same people. Um, [53:33] they're just all in different makeup and [53:36] disguises. Um, yeah, that that persona [53:39] doesn't matter quite as much. It's kind [53:40] of something that's been created by UX [53:42] professionals so that developers don't [53:43] have to talk to the clients. I think um [53:46] you know, a lot of times like you build [53:47] these personas, you end up building [53:49] either a racist or a stereotypical piece [53:50] of software. You know, I I love this [53:53] example here, but you know, it's a [53:54] computer, but why does it have to be [53:55] pink? Because it's for a girl. It [53:57] doesn't doesn't make any sense. Or [53:58] you're building software for women. It [53:59] doesn't need to be pink. You know, um I [54:02] read a great quote. It's like, please [54:04] remove age, gender, ethnicity, locations [54:05] from personas. None of that makes any [54:07] difference. As these guys that have nut [54:10] rolls, no, it didn't matter where you [54:11] came from, what your age is, what your [54:13] experience is. You're hungry and you [54:14] wanted a nut roll. That's why you wanted [54:15] to ask that question. [54:18] Solve the problem that you have. I mean [54:19] there's a great book that's user [54:20] experience that's uh talking about user [54:22] research and [54:24] uh you go read that about getting in the [54:26] mental model of the person when you're [54:28] meeting with a stakeholder and building [54:29] ubiquitous language you know talked [54:31] about the five wise you know this [54:33] understanding the business problem when [54:35] we do this exercise I don't want anybody [54:37] to be to using what I call the seven [54:39] dirty words of meeting with a domain [54:40] expert that's just like George Carlin [54:42] words but these are worse session [54:44] repository abstract interface class [54:46] database foreign key those are really [54:47] words that nobody else understands [54:49] except for all of us. Don't use those [54:50] words. All right. So, what you're going [54:52] to do is you're going to get your your [54:53] sticky pads out and your pens and [54:55] markers. And we're not going to build [54:58] any kind of user interfaces yet. We're [54:59] just going to try to understand the [55:00] problem. And the reason you use sticky [55:02] pads, markers, and pens is that not [55:04] everybody else is as good as using [55:06] computers as we are. You know, they're [55:08] maybe not as technically inclined. You [55:09] know, I had a meeting one time. I was [55:11] scrolling through software so fast. The [55:12] guy said, "Hey, you're making my eyes [55:14] roll back in my head. I can't read. you [55:16] know, as fast as you can. So, we're [55:19] going to get low tech here. We're going [55:20] to use sticky pads and pens, markers, [55:22] and stuff like that. And we're gonna [55:24] build uh a model of the problem that [55:27] we're trying to solve. And you have [55:29] colored things um and your your little [55:31] stickies there. We're just going to [55:32] create like basically a legend of what [55:34] things are. We have a domain event, [55:36] which I'm going to explain, a command, a [55:38] model, and an actor in your software. A [55:41] domain event is something that happens [55:42] in the software. It's past tense. um [55:44] like beer was brewed, grain was added, [55:47] hops were added, brewer changed email [55:50] address, things like that, things that [55:51] happened um you know or will have [55:53] happened in the past once the software [55:55] is working and you just start building a [55:57] chain of these events um as you go [55:59] through. So recipe was created, the [56:01] grain bill was added to the software, [56:05] you start building a huge chain of [56:07] events. Eventually the chain gets so [56:09] long you realize, oh, we're talking [56:10] about recipes and brewing. That's where [56:12] you can start identifying your about in [56:14] context when things get too far and too [56:15] big and complex. So, you know, we split [56:17] it down. We just look at maybe we'll [56:19] just look at the the recipe context [56:20] here. Um, so these are the things you're [56:22] starting to get about building a recipe. [56:24] You're going to be adding grain, adding [56:25] yeast, adding hops. You know, as you you [56:28] know, go through the I'm just going to [56:30] speed through this here, but um you [56:32] know, you look through the um the [56:34] different events that happen in the [56:35] system. So, I'm done talking promise for [56:39] a while. Why this is not going forward? [56:48] Yeah. All right. Promise done talking. [56:52] Um, you don't have to listen to anymore. [56:54] We're going to take a little quick [56:55] break. Let's, you know, try to give it [56:56] like five minutes or so. Get your [56:57] coffee, use the bathroom, whatever. Uh, [57:00] come back and we're going to start [57:01] working on this uh uh event storming. [57:06] When you go back to your companies and [57:07] and do this, I'm going to do the same [57:09] thing. um recommend that you know as you [57:11] start the session you put up the first [57:13] orange cards which are the events that [57:15] have happened in the system. You write [57:16] the first ones get the ball rolling. You [57:18] may not be right that's fine but at [57:19] least if everybody's just sitting there [57:21] staring at each other they're not going [57:22] to know what to do. So I've created um [57:24] the first four things in your um you [57:27] know if you're looking at this diagram [57:28] that I gave you earlier. These are the [57:30] first four things that happens. You know [57:31] brewery plans a session they make a [57:34] yeast starter which you don't have to [57:35] worry about too much. You know they [57:36] measure the grain and then the grain [57:38] they mill. That's the first one of the [57:41] first things there is the grain is mil [57:43] here and then it's put in the mesh mesh [57:47] in. So those are the events that we're [57:48] going to talk about and you guys are [57:49] going to come when you get back we'll [57:51] we'll start working on that. So soon as [57:52] you get back just start working [57:55] I'll be around to answer questions. [58:03] reason, you know, we're writing these in [58:04] the past tense and present tense is um [58:08] that's how they're going to translate to [58:09] the code. Other than that, there's not [58:11] really a really good reason. So, [58:13] examples of foods, you know, if you're [58:15] looking at the the brewing stuff, it's [58:16] like a brew session was started. You [58:18] know, start a brew session, you know, [58:19] add grain to recipe, add hops to [58:22] ferment, those are the things you're [58:23] going to be adding. Now, um so, you [58:26] know, recipe was created, your command [58:27] is going to be called create recipe. You [58:29] know, the grain bill was added, the [58:31] command is going to be called add grain. [58:33] you know, water profile is selected. [58:34] However you guys have, you know, kind of [58:36] come up with this, you know, you you [58:38] guys are your own domain experts. So, [58:39] however you did it is correct. So, go [58:42] ahead, take the blue stickies, translate [58:44] your event into a command. Should take [58:47] you just a couple minutes. [58:54] Can keep adding your commands if you [58:55] need to. But, um, moving on, the next [58:58] thing is the models. So now is when you [59:01] can kick in your developer brain a [59:02] little bit and start thinking about the [59:04] objects and stuff that you're going to [59:06] be relating to. So this is the things [59:08] that the commands are done upon and that [59:10] might be both you know in your case the [59:13] um the model that you're looking at like [59:15] the recipe or the ingredient or the [59:16] brewer. It might be related stuff you [59:18] know so if you're doing the recipe [59:19] context create recipe that deals with [59:21] the recipe adding grain that might be [59:23] the recipe and the grain kind of you're [59:25] just trying to figure out what's all [59:26] involved. So take a couple minutes and [59:28] work that out. [59:36] You don't need to write grain 17 times [59:38] if you can remember. You know, [59:43] it's not necessarily the data. It is the [59:45] the things that you're acting upon. So, [59:48] you know, you're you're interfacing with [59:50] a brew kettle that could be on there. [59:52] You know, your objects that it's the [59:53] things in the world that your software [59:55] is trying to model. Don't don't worry [59:57] about okay, we need to know for grain. [59:59] We need to know its name and its weight [60:00] and its things like that. Don't worry [60:02] about that kind of stuff. [60:12] Okay, so I think you guys are you're far [60:15] enough long on that one. Um the last [60:17] thing and we're kind of actually done [60:19] because the la the last one is the actor [60:23] and that is you know who did the [60:25] command, who did the action. Um, in this [60:28] case, you know, we probably have like [60:29] one person, the brew master or the [60:30] brewer. So, it's probably going to have, [60:32] you know, the same person on every task. [60:35] So, I'm not going to make you um, you [60:37] know, put green sticky on each one. Um, [60:40] but, you know, I do have to congratulate [60:41] you guys. Guys, diagrams are pretty [60:44] pretty pretty good. Um, they're [60:47] terrible. No, I'm just kidding. Um, so [60:50] you covers kind of, you know, building [60:52] the um ubiquitous language. [60:55] Um, does anybody have any, you know, [60:57] questions about the process? The only [60:58] thing I I would say that I've noticed, [60:59] you guys did a good job naming all your [61:01] stuff. Um, some of the things you're [61:03] going to have problems with in code. So, [61:04] if you called something grain and then [61:06] you had an object that's called mil [61:07] grain. Now, that's fine when you're [61:09] building this, but you're going to have [61:10] a problem. You're going to have problems [61:11] transitioning objects with PHP. It's [61:13] difficult unless you separate them into [61:15] different bounded contexts. When you you [61:17] have an object called grain and you have [61:19] a function called mill, you can't change [61:22] that type of object. So it can't [61:24] translate into a new kind of object. You [61:26] have to create another object called mil [61:28] grain gets a little complex. So [61:30] sometimes you may want to store the [61:31] state of the grain as a you know a [61:33] property of that object not having a new [61:34] object called mil grain. But you know it [61:37] might be important enough that maybe [61:38] they're dealing in one section with just [61:40] milk grain. So you may have an object [61:41] called milk grain. It's possible. Does [61:43] anybody have any questions about this? [61:48] Yeah. Uh sure. It so it's basically the [61:51] who did it. So, um, later when we look [61:55] at the command, it's going to be the [61:56] person who, you know, punched the button [61:58] on the software that said add grain. You [62:00] know, the grain was added. It's going to [62:02] be tied to the event. You know, they're [62:04] going to they're going to be a model in [62:06] your in your somewhere in your software. [62:08] You're going to have an object called [62:09] brewer. You know, that's going to be the [62:11] person logging into your software and [62:12] using it. So, you know, they're they're [62:15] not exactly a bounded context. They're [62:16] not really part of any of uh one [62:19] specific particular bounded context. [62:22] what's called a supporting valid [62:23] context. So they're going to show up [62:24] everywhere in your software. There's not [62:26] really a way to avoid that. Um other [62:28] than you can if you know it's complex [62:30] enough, you may want to create a [62:32] inventory user interface or something [62:34] like that. So that way you have a [62:35] limited set of functions on the user in [62:37] that um area of the software. That may [62:39] help keep things a little bit better [62:41] organized. Or if you have very distinct [62:43] teams that are working on different [62:44] parts of the software, you're more [62:46] likely to do that where you have your [62:47] user which is like a symphony user [62:49] Laravel user and that might end up [62:51] implementing like 15 different [62:53] interfaces from different namespaces. [62:56] That answer your question. [63:02] Yeah. [63:06] >> Yeah. [63:09] Event storming. Event storming. Yeah. Um [63:15] there's other ways you can do it and and [63:17] I'll kind of touch at those real quick. [63:18] Um you know, you guys started building [63:20] diagrams. You can see they're already [63:21] getting kind of large. Um you're going [63:23] to want to break those down into bounded [63:25] context like I mentioned as the thing [63:26] gets larger. Um you know, you start [63:28] circling them off. If you're doing it, [63:29] do this on a whiteboard or a big giant [63:31] long sheet of paper so you can you start [63:33] doing it over and separate the stuff [63:35] out. Um, you know, these, like I [63:37] mentioned, these events are going to be [63:38] pushed around to the different contexts. [63:39] So, like the inventory context needs to [63:42] know when a brew session is planned to [63:43] make sure the ingredients are there or [63:44] something like that. You know, we're [63:45] going to order the grain form [63:47] automatically or something like that. [63:48] And it might be, you know, multiple [63:50] events from the same bound context that [63:51] are coming to it. Um, if you're really [63:54] having problems understanding the [63:55] process, the business process and stuff [63:57] like that, um, there's a couple other [63:58] techniques you can use from user [64:00] experience side of things. Uh, one's [64:02] called business origami and um, learned [64:04] about this at 2011 uh, in 2011 at UX [64:06] week. Um, there's a handsome guy in the [64:08] background there, [64:11] but basically you make these fancy [64:12] little cards uh, and you actually [64:14] physically um, let me jump ahead a [64:16] little bit here. You'll see. But like if [64:17] you're building like an e-commerce [64:19] thing, you actually physically move the [64:20] people around the um, you know, origami [64:24] uh, store so to speak buying things. So [64:26] that way you can identify which cards to [64:28] to write on the process. So it might be [64:31] um useful to actually build a physical [64:33] model of the real world in paper or [64:35] something like that in order to figure [64:36] out oh what cards you know do we to have [64:38] in our um event storming session. [64:42] There's other ways to do this too like [64:44] they call it user story mapping and it's [64:46] kind of the same thing. You build like a [64:47] big long list of um events and then you [64:50] try to find you know the different [64:52] things that you're going to do and break [64:54] it up into you know planned releases and [64:55] stuff like that. But I you know I think [64:56] it's the idea here is that we're going [64:59] to identify the behavior first. You know [65:01] people think about software they don't [65:03] think about database models like I was [65:04] mentioning. They think about what does [65:05] the software need to do for me. So [65:07] they're thinking that you know I need to [65:08] be able to add grain to this. I need to [65:09] be able to you know do things. Those are [65:11] the events. So starting with the events [65:13] and starting with the things that have [65:14] to happen in the software is a much [65:16] better way to to build software other [65:18] than starting with the databases and the [65:20] data. Um so I would give this you know a [65:23] correctness and usability much higher as [65:26] compared to you know CRUD code. [65:29] All right. So, we're going to start [65:31] talking about actual code. [65:34] How do you implement this ubiquitous [65:36] language and how do you, you know, make [65:38] software that is maybe completely [65:39] different from how you guys are writing [65:40] it today. And um you what I mentioned [65:43] earlier is going to be heavy on the [65:44] object-oriented uh side of things. Um [65:47] but it's hopefully not too difficult to [65:49] understand. In domain driven design, we [65:52] have pretty much four basic uh kinds of [65:55] entities and objects in our system. We [65:57] have value objects which are going to [65:59] represent um small things in our system, [66:02] pieces of information. Domain events, [66:04] those are the orange cards that you put [66:06] in your event storming uh session there. [66:08] Those going to translate exactly to [66:10] objects in your system. Entities, those [66:12] are your yellow ones, those are the [66:14] models. Um you know that you had a you [66:17] know you have a grain model that's going [66:19] to become an entity. Aggregates um those [66:22] are your fancy um models and I'll get [66:24] into that. They basically contain child [66:26] entities. So [66:28] um you know a value object like I [66:29] mentioned is the smallest pieces of your [66:31] software. Um biggest thing about them is [66:33] they're going to be immutable. Um they [66:35] have no identity. I'll get into that. [66:37] But examples of value objects in the [66:39] brewing thing is like a hop name, an [66:41] amount paid, a temperature, things like [66:42] that. They're they're values. They're [66:44] not um things that have uh things that [66:47] are stangeable about them. Entities are [66:50] things that are identifiable and they're [66:51] mutable and they have a life cycle and [66:53] they're going to operate on those [66:55] smaller value objects and I'll get into [66:57] that later. But an example of models [66:59] might be a line item in a in invoice. [67:02] You know, you could change the quantity [67:04] or change the price. You know, that that [67:06] that could change over time or you could [67:07] delete the line item. So that has a you [67:09] know life cycle. Brewers, the names [67:11] change. They come and they go, they're [67:12] fired. They're hired. Water chemistry, [67:15] you know, you might have a model for [67:16] your your water chemistry. Well, your [67:18] city water changes, you know, daily. So, [67:20] if you're measuring it, you're going to [67:21] be constantly updating your your water [67:23] supply. [67:24] An aggregate. So, an aggregate is [67:26] basically a fancy entity, a bigger [67:28] entity, and it is responsible for [67:30] managing smaller entities, and it's [67:33] primary job. It's going to have business [67:34] logic for sure. Um, but it's going to be [67:37] the um larger, more identifiable objects [67:40] in your thing. So if you had um things [67:42] on your uh eventtorming session like [67:44] brew session um you know that's going to [67:46] be controlling some things as far as [67:48] what state we are in the process and [67:49] stuff like that. the recipe recipe is [67:51] gonna if you flip to the the recipe that [67:53] I gave you in the packet there it has [67:55] hops it has grains it has yeast you know [67:58] it's got to contain all these other [67:59] models so it's got to manage and it's [68:01] got to hold them all together to build [68:02] one giant thing called a recipe that's [68:05] an aggregate [68:08] but if of all those things value objects [68:11] are by far the most important [68:14] so um the value objects again we were [68:18] talking about out of kind of this the [68:19] brewing You might have an email address [68:21] for a brewer. I don't know. That's kind [68:22] of an easy example. A recipe name. Um [68:24] the date we brewed the beer on. That's [68:26] an example of a value in the system that [68:28] is immutable. You can't change when we [68:30] brewed it on. The weight of grain you [68:32] might have, you know, that's a 13 pounds [68:34] is 13 pounds. You can't you can change, [68:37] you know, how much grain you've weighed [68:38] from 13 to 15 pounds, but the value of [68:41] 13 pounds does not change. It's that is [68:43] 13 pounds. You know, 70 degrees uh [68:46] Fahrenheit is 70 degrees Fahrenheit. [68:48] There's no changing that. If you change [68:49] to 71 degrees, that's as a new [68:51] temperature. [68:53] And all these value objects in the [68:54] system are going to come directly from [68:55] the ubiquitous language that you know [68:57] when somebody if they call it, you know, [69:00] uh the date we brewed on, yeah, you [69:02] might want to shorten that to brood on [69:03] in your code or something like that. But [69:04] if they call it a recipe name, it's a [69:06] recipe name in your code. [69:09] And we're going to have classes that map [69:11] directly to um the classes or we're [69:14] going to have classes that map that you [69:16] look at this language directly to the [69:18] objects in our software. So if you're [69:20] talking about temperature in the brewery [69:22] that you're building software for it [69:24] does everything in Fahrenheit, well [69:25] you're going to have a class called [69:26] degrees Fahrenheit that's going to [69:27] represent that. Um there's no reason to, [69:29] you know, build it out in Kelvin. There [69:31] just brewers don't talk in Kelvin. They [69:33] don't, you know, think about in, you [69:34] know, Kelvin or even maybe degrees [69:35] Celsius depending where they're from. So [69:37] have a degrees Fahrenheit class because [69:39] that's how they're going to class in [69:40] your software because that's how they're [69:41] going to have to put information in. [69:42] They're they're going to want to use [69:43] degrees Fahrenheit and everything. [69:44] They're not going to have to convert. [69:47] And you know these objects are not just [69:49] about creating uh classes that do static [69:52] typing, meaning type hitting in your [69:53] functions. That's not the point of them. [69:55] Um there's studies that have shown that [69:56] you know just the variable names is [69:58] enough to keep you from swapping [69:59] parameters. That's not the whole point. [70:01] Um the point of value objects is to [70:03] reduce complexity and reduce um checking [70:06] in your software. So value objects I [70:09] mentioned are immutable meaning they do [70:11] not change. Um there's no in there's no [70:14] factor of time involved in a in a value [70:16] object. You know the temperature doesn't [70:18] change over time. 70 degrees Fahrenheit [70:20] is 7 degrees Fahrenheit regardless of [70:22] when it is. The other reason um you want [70:25] to have as many objects in your system [70:27] uh immutable in your software is because [70:30] PHP passes objects by reference and if [70:33] you pass an object to a function that is [70:36] mutable. So um that function could [70:38] change something on that object and you [70:40] don't know that. So when that object [70:41] that you pass in could be changed. Now [70:43] if it's an immutable object like a value [70:45] object and you pass that to that [70:46] function you don't have to worry about [70:47] that object being changed. So if I pass [70:49] 70 degrees Fahrenheit to a function, I [70:51] don't have to worry about it coming back [70:52] as 68 degrees. It's not possible. That [70:54] object is locked and it's immutable. [70:56] There's no possible way to do it. [70:59] The other way um the other thing that [71:01] helps you in your software here is your [71:02] your value objects will always be in a [71:04] valid state. Now they don't have state, [71:05] but what I mean by that is they're [71:08] always valid. So 70 degrees Fahrenheit [71:10] is a valid temperature. Now if anybody [71:14] remembers from high school physics, [71:15] there's something called absolute zero. [71:17] you know, you can't be below what 273 [71:19] degrees Celsius. You know, 300 degrees [71:22] negative Celsius is not a valid [71:24] temperature. So, we're going to prevent [71:26] that uh in this uh value object class. [71:28] So, anywhere you deal in temperatures, [71:30] you know, it's always a valid [71:31] temperature. [71:33] Value objects become like the thin candy [71:35] shell uh in your application where [71:37] everything stops and keeps everything [71:39] from hitting the nice um creamy center [71:40] in the middle of your application. the [71:42] earlier you can solve problems in value [71:44] objects um the easier you're going to [71:46] have time uh building software [71:49] if you're not doing software uh you're [71:51] not doing test-driven development now [71:53] value objects are a gateway drug to test [71:55] driven development they um are by far [71:57] the easiest to develop doing test driven [71:59] methods [72:01] #my tests don't pass [72:05] so what are value objects they're like I [72:07] mentioned they're just small little [72:08] classes that have one purpose they're [72:10] plain PHP objects [72:12] Um they don't necessarily have to [72:14] inherit from anything or be part of [72:15] something else. They're called call them [72:17] popos. I mean a plain old PHP object. Um [72:21] they're all their properties are [72:24] private. There's no public way to change [72:26] anything about them. Um there's no [72:29] setters on them. Like I said, you can't [72:30] change anything about them. They're [72:32] mutable. U they don't hold references to [72:34] mutable objects. Um, so you know like uh [72:39] a grain for example, you can't have that [72:41] as a value object because the grain [72:44] could actually change like different [72:45] acids and stuff like that or enzymes [72:47] could be different in the grain. So you [72:48] can't hold a value object and have an [72:50] entity inside of it that can change. [72:52] It's not possible. That value object if [72:54] it's 70 degrees Fahrenheit, like I said, [72:56] should be 70 degrees Fahrenheit forever. [72:57] There's no change to it. The biggest [72:59] difference um in domain driven design [73:02] code versus most code is um we're going [73:04] to throw as many exceptions as possible [73:06] in the construction of these objects. [73:08] And exceptions are going to be your [73:09] friend. You're going to catch these [73:10] exceptions when you need to to react to [73:12] it. But for the most part um you know a [73:14] lot of your validation is going to come [73:16] from throwing exceptions in the [73:17] constructor. [73:20] And like I said, value objects only [73:22] depend on scalers and other value [73:24] objects. Um so like I said, you can't [73:25] pass an ID to a value object and hold [73:27] it. um 70 degrees Fahrenheit. To hold [73:30] that, you need maybe a float that's 70 [73:33] and a unit that's Fahrenheit. So there [73:35] might be two values you need to hold. [73:36] Those don't change. Um that's all the [73:38] dependencies that this this value object [73:40] is going to have. Um and they're not [73:42] dependencies that you have to inject [73:44] either. Um so you know, sure, if you're [73:46] following Solid Principles, you know, [73:48] dependency injection, things like that, [73:49] if you have repositories and services [73:52] and stuff like that, you don't want to [73:53] just be littering those willy-nilly in [73:55] your code. That's that's a bad practice. [73:57] Value objects are a little bit [73:58] different. Um they're pretty much like [74:00] scalar types. Like do you worry about [74:01] having integers in your code anywhere or [74:04] strings? No, you don't. You don't worry [74:05] about that. These are pretty much just [74:06] an extension of the scalar types. So [74:09] don't worry about saying new temperature [74:11] in anywhere in your code. It's it [74:13] doesn't have any dependencies. It's [74:14] designed that way. Uh it's going to be [74:16] perfectly fine to have those new uh [74:18] things happening in your code. You may [74:20] um you know value object gets very [74:22] complex. You may need a factory which [74:24] you know if you guys are familiar with [74:25] patterns you may need a factory to build [74:28] that uh value object sure you might want [74:30] to inject that in that case but for the [74:32] most part value objects you just put [74:34] them wherever you need to put them and [74:35] use them. All right enough talking about [74:39] value objects let's look at an example [74:40] and I put this example in the packet [74:42] that I put out just so you guys can see [74:44] it a little bit closer. Um but let's [74:46] talk about you know the business rules. [74:48] Uh we're going to apply those directly [74:50] to our code. So the brewers have told us [74:52] that yeah we name all our recipes and [74:54] they have to be nice creative witty [74:55] names um that we put up on the board and [74:58] everybody smirks at and they they sniff [75:00] it first and drink it. No, I mean so [75:02] important thing is to have you know some [75:04] business rules associated with this [75:06] recipe name. And basically the business [75:07] rule is that a recipe name cannot be [75:10] empty. So if I if I create a new recipe [75:13] name object and I pass an empty value in [75:16] it should blow up. So it's going to [75:17] throw an exception. you know, if I add [75:20] if I pass in a valid name, it should [75:22] give it back to me in the getter. So, [75:24] it's get value. It's kind of a simple [75:25] way of saying, you know, give me back [75:27] the value out of this object. [75:29] A lot of times I like to do on these [75:31] simple value objects, if you can cast [75:33] into strings, we'll put a two-string [75:35] method in that'll just cast it. So, you [75:37] don't have to have get value everywhere [75:38] in your code. Uh, can get a little [75:40] verbose. Hopefully, those are nice witty [75:42] names like iphpa and recursive viton. [75:46] So, uh, like I mentioned the recipe [75:48] test, I think you guys can see that I [75:50] printed it out. [75:52] So, um, like I said, we're doing [75:54] test-driven development. We've added our [75:56] test. Let's run it. And everything fails [75:58] because the class doesn't exist. The [75:59] method's not found, all of that. So, [76:02] let's start, uh, by building that class. [76:04] And like I mentioned, the thing that [76:05] we're going to do most of the time in [76:07] these value objects is throw an [76:08] exception in the constructor when things [76:10] fail. So, when you're building your [76:12] value objects, you're going to try to [76:13] identify the failure points for these [76:15] value objects. So, if the value that's [76:17] passed in is a string, we don't have to [76:19] test if it's string because we're using [76:20] PHP 7.1. Um, if we're using PHP 5, you [76:24] couldn't type hint that string there. If [76:26] it was value, so you'd have an [76:27] additional check like if uh not is [76:31] string in PHP, you would then throw an [76:32] exception saying this is not a valid [76:34] string. Um, but yeah, I mean, if it's [76:37] empty, we throw an invalid recipe name [76:39] exception. In this case, I've created an [76:40] exception class because maybe you need [76:42] to deal with that exception specially. [76:43] If you don't need to deal with the [76:44] exceptions especially in this case throw [76:46] an invalid argument exception which is [76:48] in the root you know base name space of [76:50] PHP that that's perfectly fine I I do [76:52] that in some of the examples and then we [76:54] hold the value and [76:57] that you know that is enough to pass our [76:58] first test in that uh recipe test thing [77:01] where it's testing to make sure we pass [77:03] an empty string [77:05] it fails. [77:08] Next thing we have to do is we just add [77:09] a get value function and that returns [77:11] the value back out of the value object [77:14] again. Run the next test pass test [77:16] passes and then the uh tworing that's [77:19] really easy to implement. You just get [77:21] the value back. You could also just wrap [77:22] the the get value function. Um you know [77:25] internally you could just call that [77:27] public function internally. Not a big [77:28] deal. Um, I mean, again, I don't I [77:31] wouldn't stress too bad or too much [77:34] about the value objects and how you [77:35] implement them. As long as you're [77:36] testing them and you're um, you know, [77:38] you're wrapping things in test and [77:39] you're identifying the fault points. The [77:41] internal code, if you want to, you know, [77:43] get fancy with your implementation [77:44] there, that's fine. Do whatever you [77:45] want. Important thing is you test, [77:47] lights are green, tests are clean. It's [77:50] in the trap. You know, thing is it's [77:52] locked down. So now you know as we look [77:54] at this recipe name class anywhere I use [77:57] this in the system I'm guaranteed that [77:59] the recipe name is valid. So it's kind [78:01] of a different way of looking at code is [78:03] you no longer ever have to check on this [78:05] recipe name throughout everywhere in [78:07] your code. Recipe name is now valid. [78:09] It's now a valid object. It's not [78:11] possible for somebody to create an [78:12] invalid recipe name. [78:14] Look at another example. Get get a [78:16] little bit more advanced. Um so a brewed [78:19] on like when was the recipe brewed on? [78:21] you know, we write a test for that. [78:22] We're just going to create a new [78:23] datetime, and it should give us back, [78:25] you know, a datetime uh immutable uh [78:28] value. So, you know, you just hold it. [78:30] Datetime already does the validation for [78:32] you. You know, it's going to throw an [78:34] exception if it's an invalid date. So, [78:35] for the most part, you're done. Um but, [78:38] you know, if you want to add some [78:39] business rules in there, maybe to catch [78:41] edge cases and things like that, you [78:42] can. You know, like, oh, you know, it's [78:44] not possible because we're writing the [78:45] software today for there to be a date [78:47] that's less than, you know, 2017 [78:49] November 15th. It's not possible. the [78:50] software didn't exist. So throw an [78:52] exception if the date's too far in the [78:54] past or you know oh maybe this we know [78:55] this software is only going to last a [78:57] year so we put it in the future you know [78:59] things like that you know it you want to [79:00] try to stop anything you identify that [79:03] are problems with that uh object in the [79:06] constructor [79:08] another example of pounds you know um we [79:11] can test that value uh like I mentioned [79:13] make sure it's a float um you know it's [79:16] not really possible to have a negative [79:17] weight you know unless we discover [79:19] antimatter weight is always positive So [79:22] you can treat pounds as you know [79:23] positive in your system and throw like [79:26] at the bottom one here test negative [79:27] throws exception you know it's easy to [79:29] check that um you know value is less [79:31] than zero uh may not be negative now [79:35] because PHP can be screwy sometimes you [79:38] want to identify like I said pounds [79:39] always must be positive you want to [79:41] identify a way that that makes sense to [79:43] both you and the business of what this [79:45] object is going to represent. PHP has [79:47] this nasty thing of a negative zero. [79:51] What is negative zero? It doesn't make [79:52] any sense. Let's eliminate that from our [79:54] domain. Um, you know, so we can just [79:56] cast it to a regular zero if we have [79:58] negative. That way, if they print it out [80:00] and it's zero pounds, it doesn't [80:01] accidentally show up as negative 0 [80:03] pounds and confuse the hell out of them. [80:05] You know, your two string in this case, [80:07] you know, maybe the breweries decide [80:09] that, you know, they don't have to worry [80:10] about anything less than, you know, [80:11] 0.0001 ounce, you know, pounds. Do your [80:14] formatting and your value objects. do [80:15] your rounding. You know, you might want [80:17] to hold the entire value. If it's like a [80:19] long float, you may want to hold that. [80:20] But when you get the value out or we [80:22] display it to them, you handle your [80:23] formatting here. Now, that's only for [80:25] simple things, uh, like, you know, [80:27] pounds and stuff like that. If you have [80:28] dates and more complex objects and you [80:31] need to format it, again, looking at [80:32] solid principles, it's a good idea to [80:34] separate your formatterers into another [80:35] class or into a template, things like [80:37] that. Again, those policies apply. [80:41] The the thing I mentioned about [80:43] immutable in the value objects doesn't [80:45] mean that you can't have behavioral [80:46] functions on a in a value object. That [80:49] is definitely possible. The trick is [80:51] though is we're going to return a new [80:53] object um if you change something. So if [80:56] we had 11 pound or 10 sorry 10 pounds [80:59] and we want to reduce that amount by 6.1 [81:02] pounds, we expect a value of 3.9. Now [81:04] what that is actually going to return is [81:06] a new pounds object with 3.9 pounds in [81:10] it. As I mentioned that that original [81:12] one we 10 10 we passed it's not mutable. [81:14] So it cannot change. It will return a [81:16] new object. [81:20] So like I mentioned biggest thing about [81:22] value objects is it eliminates checking. [81:25] So the pounds object decrease by [81:28] function. A little bit hard to see maybe [81:30] there at the bottom. Um but yeah like I [81:32] said the first thing you're going to do [81:33] there is new self [81:37] in your object. So you're going to [81:38] return a pounds object because like I [81:40] said the value objects are not are [81:41] immutable. You cannot change them. And [81:43] you're just going to say this value [81:45] minus decrease by pounds get value. You [81:47] don't have to check and see if the [81:48] pounds are negative or like in case the [81:50] recipe name. You don't have to check if [81:51] it's a string or anything like that. [81:52] It's all done. I don't even have to [81:54] check that when I'm subtracting, you [81:57] know, say have six pounds and I try to [81:58] subtract 10. I don't have to check that [82:00] here because it's not possible. the [82:02] constructor will catch that because this [82:04] will come in as a negative value and [82:06] it'll be neg3 and the exception will be [82:07] thrown weight cannot be negative. So a [82:10] lot of your checking and if logics and [82:12] stuff like that can be handled by the [82:13] the the um value objects you know like [82:15] mentioned the 70 degrees if you try to [82:18] subtract 400 degrees from that it's not [82:20] possible the absolute zero is going to [82:21] catch that you have a question [82:42] >> Yeah, that that's perfectly fine. Like [82:44] um yeah, if you had a weight object in [82:46] and say it's you just want to deal [82:47] because you're dealing in many [82:48] measurements like let's say that not [82:49] like a brewery where it's all pounds [82:50] because it's in the US. Um yeah, you [82:52] have a weight object and you're going to [82:54] have to store I'm going to get into this [82:55] in a second, but it's they call it a [82:57] composite value object. So weight is [82:59] going to contain two diff distinct value [83:01] objects probably maybe in the case [83:03] probably just a float just a regular you [83:05] know PHP object float for the and then a [83:08] string or a unit of measure object that [83:11] represents the unit. So then anytime [83:14] like this if you're like decrease like [83:16] let's say it's kilograms you try to [83:17] decrease it by pounds in your you know [83:20] you can throw exceptions there and say [83:22] like hey you know what the units don't [83:24] match or you can do the conversion if [83:25] that's business is like yeah we get [83:27] stuff randomly all the time we want to [83:28] do the conversion automatically be nice [83:30] and do it for them don't throw an [83:31] exception say oh you must put this in [83:33] pounds you know build these rules into [83:35] your business build intelligence into [83:36] your software you know like I mentioned [83:38] before the factories if it's difficult [83:40] to create an object from a string or [83:42] something like Feel free to build a [83:44] factory if that's the way you want to do [83:45] it. I mean, it's fine. However you [83:47] operate, you know, building your code [83:48] now is probably for the most part fine. [83:50] It's mostly just naming and [83:51] understanding that these value objects [83:53] are going to be immutable and always in [83:55] always valid. [83:57] Um, one of the things I like to do on [83:59] stuff is like static constructors on [84:01] these value objects. Go ahead real [84:02] quick. [84:07] >> Yeah. [84:13] Now, now PHP especially five, you know, [84:18] five or 54 up objects are incredibly [84:22] easy to generate. The only time you'll [84:24] run into a problem is if you build um [84:28] recursive [84:30] like issues where okay um you know I [84:33] want to make sure that the Fahrenheit [84:35] object can't be below absolute zero. [84:38] Well, I can't build a absolute zero [84:41] Fahrenheit object that extends [84:43] Fahrenheit because it's not possible for [84:45] it to be absolute zero. It's just not, [84:47] you know, so you end up having to make [84:49] sure you kind of separate things a [84:50] little bit. But objects are cheap. PHP [84:53] objects are very very cheap. So don't [84:55] don't be afraid of creating all these [84:56] objects and stuff. [84:58] Good question. Okay. Um, so static [85:01] constructors and I like to call these [85:02] natural language constructors. They're, [85:04] you know, they're coming from the [85:05] ubiquitous language. coming from what [85:07] you know um somebody talks about you [85:09] know maybe in the example here we have [85:11] pounds but we want to sometimes we get [85:12] stuff in that's metric in kilograms um [85:15] you know you have a function that's [85:16] static function from kilograms and this [85:18] will return a a new pounds object and do [85:21] the math for you now your software is [85:23] just dealing in pounds not worrying [85:24] about kilograms and stuff like that but [85:26] we know that that weight is always valid [85:30] so [85:31] um [85:33] yeah I mean you might have to do you may [85:35] even want something like from string. So [85:37] if somebody writes like 2.0 lbs, um you [85:40] may have you may want to write some [85:41] parsing logic there that does some reax [85:43] or something fancy and does that. [85:49] I think I've um you know done the [85:51] temperature example here a few times. Um [85:54] you get the you know the formulas and [85:56] stuff like that. I was going to do an [85:57] example but I think I'm going to move [85:58] past that. Does everybody kind of get [85:59] the idea that we're, you know, you're [86:01] creating these objects, they're [86:02] immutable, and um, you know, you do all [86:04] the validation in the constructor? Just [86:05] think everybody got that? [86:13] >> No. [86:15] >> Yeah. Do whatever you need to do. Um, [86:16] like I was saying, like it's two float, [86:18] pounds a string, something like that [86:19] unit of measure. And I'm just about to [86:20] go into like composits of these. So, um, [86:24] but you know, like I was saying, the the [86:26] units are important getting those right. [86:28] You know, if you've heard stories about [86:29] the Mars Climate Orbiter that crashed [86:31] into Mars because they were working in [86:33] miles and kilograms, you know, things [86:35] like that. Um there was a the plane [86:37] called the Gimly Glider that um you [86:39] know, they they weighed the the fuel in [86:42] kilograms instead of pounds. It didn't [86:44] have enough like, you know, had half you [86:46] know, whatever was less than half the [86:48] fuel it was supposed to had to, you [86:49] know, crash land. Luckily, nobody was [86:50] hurt. Um you know, these are the kind of [86:54] things you can eliminate by using these [86:55] value objects. um and making sure that [86:57] you know it's not possible to have [86:58] invalid state in your app. All right, so [87:02] composite value objects um easy example [87:06] would be a brewer's name. So a brewer [87:09] full name, you know, might consist of a [87:11] first name and a last name. If we look [87:14] at the the full name object, [87:17] uh there's really nothing to validate [87:19] here other than the fact that there is a [87:21] first name and a last name because first [87:23] name is a value object. It's just going [87:24] to make sure it's not empty just like [87:25] the recipe name. Last name value object, [87:28] it's going to make sure it's not empty. [87:29] So the full name, we know now passing [87:32] that around anywhere in our system, we [87:34] know exactly what a full name is always [87:36] valid. It's not possible to have empty [87:37] strings. And right here, we can [87:39] implement the two string method of how [87:41] to represent that in the system. So if [87:43] later you decide to add middle names and [87:45] suffixes, prefix and stuff like that, um [87:47] you don't have to worry about where [87:48] you've, you know, said, you know, two [87:50] string or get value on a full name or [87:52] formatted that. It's, you know, you just [87:54] have to update the constructor and where [87:55] you've used it and stuff like that. Um, [87:57] but yeah, I mean, we've eliminated a lot [87:59] of checking here. There's no checking to [88:01] make sure first name is not empty and [88:02] last name is not empty. We're relying on [88:04] these value objects to compose [88:05] themselves. [88:07] We're going to, you know, the goal here [88:09] is to encapsulate as much of our [88:10] business logic in the value objects as [88:12] possible. Like I mentioned, the [88:13] temperature thing. Um, you can get very [88:15] complex with these value objects. So, [88:18] one of the things that a brewery is very [88:20] concerned with is the amount of alcohol [88:21] that is in a beer. Um, you know, they [88:24] have to put it up on their board. They [88:25] have to tell you by law how much alcohol [88:27] is in a beer. And, uh, they call it ABV. [88:30] If you see that up on the board, that'll [88:32] tell you, you know, alcohol by volume, [88:33] it's 7% alcohol. Um, you know, that's [88:36] kind of a stronger beer. So, don't [88:38] drink, you know, 10 of them. But the way [88:41] you find out how much alcohol is in a [88:43] beer, you can obviously send it out to a [88:45] lab and spend a ton of money, have it [88:47] analyzed, um, or you can just calculate [88:49] it using some measurements. And if you [88:52] know about the brewing process there, [88:54] like I was telling you, if sugar and [88:55] yeast turn alcohol and uh CO2 out the [88:59] other side, um there's actually a [89:01] chemical equation for this, but I'm not [89:02] going to bore you to death with that. [89:04] But if we're trying to calculate the [89:05] amount of alcohol that comes out, we [89:06] know we don't care about CO2 and we [89:08] don't care about the yeast. That doesn't [89:09] affect the amount of alcohol that comes [89:10] out at all. Well, we care about the [89:12] sugar and the sugar, the amount of sugar [89:14] we start with and the amount of sugar [89:15] that we end with. Now, like I said, [89:17] yeast consumed sugar. So if we know how [89:19] much sugar the yeast consumed, we know [89:21] roughly how much alcohol a yeast [89:23] produces when it eats that sugar. We can [89:25] calculate how much alcohol is in the [89:27] solution. So we get alcohol by volume. [89:30] By dividing those two things um you know [89:33] subtracted from each other. Now you [89:35] measure that um amount of sugar in a [89:38] thing called specific gravity, but it's [89:39] basically the density of the sample [89:41] versus the density of water. And you can [89:42] do that very expensively. If you're a [89:43] professional brewer, you probably buy, [89:45] you know, a machine that to do that. Um, [89:48] but many craft breweries and every home [89:50] brewer does, and I have one of these up [89:52] there here if you want to look at it [89:53] later. It's a hydrometer and basically [89:55] it you put it in the water or you put it [89:57] in the the W that came out of the boil [89:59] kettle and you measure how far it [90:01] floats. And um, you know, so it floats [90:04] in the solution. It has a little scale [90:05] on it so you can measure, you know, how [90:07] much it goes up and down. And if you [90:09] know anything about chemistry, the [90:11] density of something lowers as it heats [90:13] up. Things expand. Like water actually [90:16] grows. I think it's like 5% from cold to [90:19] boiling like the volume of water grows [90:21] um in a solution. So, um when you're [90:25] measuring that specific gravity, you [90:26] have to know exactly what temperature [90:27] you're measuring that specific gravity [90:29] at because um like I showed you earlier, [90:32] that hydrometer has been scaled and [90:34] measured exactly a certain temperature. [90:36] So, in my case here, I have a 60°ree [90:39] hydrometer. So, that scale is meant for [90:41] 60° uh Fahrenheit. [90:44] And you can look it up on a table and [90:46] figure out how much to move, you know, [90:48] the the temperature uh with specific [90:50] gravity. Um or you can try to you can [90:52] calculate it very easily. So I look at [90:54] um I put a thermometer in when I do the [90:56] measurement. So I know like in this case [90:58] it was it's kind of hard to see there, [90:59] but 66 uh degrees and I measured the [91:03] specific gravity and my you know my [91:05] hydrometer's set at 60. Do a little bit [91:08] of math and it's actually kind of [91:10] complex math but you can calculate you [91:13] know what it was supposed to be reading. [91:14] So if it read 1.040, we know it's [91:16] actually 1.041 because the temperature [91:19] adjusted it slightly. And it's not a [91:21] very hard calculation to do. So kind of [91:23] use this as an example with the [91:24] composite value objects to do this. So [91:27] the hydrometer test, you know, we're [91:29] going to look at the um building a test [91:30] for this first because I said like I [91:32] mentioned u testing value objects is [91:34] pretty easy. I just pulled values from [91:36] that table and you know when the [91:38] temperature is exactly the temperature [91:40] of the hydrometer, everything should [91:41] match up. That's an easy test, right? Uh [91:44] then we do maybe a test a bit higher, [91:46] put some values in there, you know, do a [91:49] test a bit lower, do the same thing. And [91:52] we're going to end up building a [91:54] composite value object that's called a [91:57] gravity or original gravity. In this [91:58] case, if you're measuring it before the [92:00] the yeast has eaten the sugar out of the [92:03] the wart, it's called the original [92:04] gravity. So, we're going to call we're [92:05] going to create a value object that's [92:06] called original gravity. And to read the [92:09] gravity reading, like I mentioned, you [92:10] read the gravity reading off the [92:11] hydrometer. So that's a float value [92:13] object that we've made sure is within a [92:15] reasonable range. And a temperature that [92:16] we know is within a reasonable range as [92:18] well. So um [92:21] you know, we we know that we can verify [92:23] that the hydrometer, you know, class [92:25] here can value object can tell you, you [92:27] know, you can't read a value above or [92:28] below the the scale. And you know, we [92:30] can do the logic right here to correct [92:32] the gravity for the temperature. So it's [92:34] like I said, a big long equation. um but [92:37] it's all centralized in this value [92:39] object. So the business rules and the [92:40] business, you know, uh the way they're [92:43] they do things, we're putting as much as [92:45] we can in the value objects. [92:50] So like I said, we want to um find the [92:52] uh gravity here, you know, the alcohol [92:54] by volume. This is the formula right [92:56] here. There's our readings. Original [92:58] gravity is OG and final gravity would be [93:01] after the yeast eats it. And that's the [93:02] formula for creating it. Now we can also [93:05] create a composite value object out of [93:06] that. We can have a gravity range. So [93:09] gravity range value object becomes a [93:11] original gravity and a final gravity. [93:13] Now we can make sure right in this value [93:15] object that the original gravity is [93:17] lower than the or sorry is lower than [93:19] the final gravity because as the yeast [93:21] eats sugar the amount of sugar in there [93:23] becomes less. The gravity actually [93:25] becomes lower. Um so we can verify that [93:27] you know somebody is putting in stuff [93:29] properly and that's all this object [93:31] needs to be. It just needs to be a [93:32] holder of you know those values perhaps [93:35] and then you know the class when we [93:37] write the alcohol by weight and the [93:38] alcohol by volume can work from that [93:41] gravity range. So this is again another [93:42] value object that has a static [93:44] constructor that creates itself from [93:46] another value object and the formula is [93:48] right in here. So I don't have to [93:49] validate anything you know as far as the [93:51] gravity ranges go. All that's been [93:53] validated for me temperatures the [93:54] readings all that stuff's validated. I [93:56] just have to worry about building the [93:57] formula here and doing the math and to [94:00] actually calculate ABV then you know we [94:02] do that final function equation there [94:05] and we end up with another value object [94:07] that is the alcohol by volume. So you [94:08] can guarantee everywhere in the software [94:10] that the alcohol by volume has been [94:12] validated nothing to do no checking. I [94:15] want to contrast that you know real [94:16] quick with u I mentioned that brewer [94:18] wall and that that's a PHP software [94:20] application but if you look and this is [94:22] just one class of calculations they have [94:25] um you know they have ABV OG and final [94:27] gravity um you know they're checking is [94:30] the original gravity more than the final [94:32] gravity is it a numeric value is it a [94:34] numeric value you know they're doing [94:35] that and if you look through that one [94:37] class um you know as they do it they do [94:39] it over and over over again they [94:40] actually you can't see because it's [94:41] getting cut off the top of the projector [94:43] here but they check og greater than [94:45] final gravity five times in one class. [94:48] So right there um you know you're [94:50] repeating code. That's one of the first [94:51] things we learn is don't repeat [94:52] yourself. Don't repeat yourself. Don't [94:54] repeat yourself. Don't repeat yourself. [94:55] Don't repeat yourself. Um it's a big [94:57] thing in code. You know the is numeric [94:59] checks. Not having those value objects [95:00] that represent a float knowing that a [95:02] final gravity is accurate. They did that [95:04] 39 times in one class. [95:07] Passing these value objects around you [95:09] know eliminates a huge amount of [95:10] checking in your software. Um, you know, [95:13] you've put all of that checking into [95:14] small little classes that are very, [95:16] very, very easy to test. Now, like we [95:19] mentioned earlier, not doing things in [95:20] DDD. Some things are CRUD. Even things [95:22] that are CRUD, I still use value objects [95:23] a lot because it makes that stuff a lot [95:25] lot easier. [95:27] So, like I mentioned, you know, DDD, we [95:29] have these objects. Recipe name, [95:30] temperature, date brood, those are all [95:32] valid. We know they're valid. CRUD, you [95:34] know, like I said, strings, floats, you [95:35] don't know what they are. Functions, [95:36] validations testability usability I [95:39] think is, you know, a lot higher. You [95:40] don't have to worry. the users don't [95:41] have to worry about accidentally [95:42] screwing formulas up, things like that. [95:45] Um, another check there. And of course, [95:47] you know, we all test our code. So, all [95:49] the time. [95:52] No. Uh, but if it's obvious that you're [95:55] not going to have time to test [95:56] everything. Um, but value objects, I [95:58] would say absolutely test them and [96:00] because those are the like I said, the [96:01] very first thing that your your [96:03] application you put as much logic as you [96:05] can into them and focus on them. um [96:08] because [96:09] when you're building entities and these [96:11] are the models I was talking about, [96:12] you're going to rely heavily on those [96:14] those value objects. So um those [96:17] entities like I said they're [96:18] identifiable, they have state, they're [96:19] mutable. Um but they operate on the [96:21] value objects. They use those value [96:22] objects in order to store values and um [96:25] you know change over time. Um ideally [96:28] they're storage agnostic. Now that's not [96:29] always possible uh depending on what you [96:31] know frameworks you're using, stuff like [96:33] that. Laravel. Um, sorry. You may not be [96:37] able to do that quite as easily, but if [96:38] you're using Doctrine and stuff like [96:40] that, um, you know, it makes a little [96:41] bit easier to just keep your stuff [96:42] storage agnostic and then do mapping [96:44] later. But, um, do as much as you can in [96:47] the value objects. Put as little as [96:48] possible in the entities. Your entity [96:50] should just be storing values and [96:51] holding state. Um, you know, use those [96:54] doctrine mappings, doc annotations. Lar, [96:56] if you're Laravel developers, I'm sure [96:57] there's a few of you in the crowd. [96:58] Nothing wrong with that. Um, you'll do [97:00] this a little bit differently. I'm going [97:01] to show examples in doctrine. Um, but [97:04] Laravel, you probably will use your ORM [97:06] objects to hold state. So, you're going [97:08] to pass those to your entities and hold [97:09] state. That way, your entities can kind [97:12] of worry about business logic that's [97:13] associated with it. So, you're still [97:14] going to you're going to map in and out [97:15] of value objects in order to do your [97:17] mapping um through the OM [97:20] behavior first, storage second. So, like [97:23] I made you guys do the event storming, [97:25] thought about modeling, we weren't [97:26] worried about data and stuff like that. [97:28] entities again I mentioned earlier [97:30] single entity aggregates contain other [97:32] entities just to kind of um you know [97:35] keep those two in your head the code [97:37] behind them is almost identical it's [97:39] just that the aggregates store you know [97:41] multiple entities and if you're doing [97:43] transactional stuff um your transaction [97:46] boundaries are going to be around the [97:48] greater aggregates so when you save a [97:50] recipe you want to save all the hops and [97:53] grains associated with it all at the [97:54] same time um if you have a recipe and a [97:57] brew session together and you're [97:59] operating those in the same controller [98:00] because you've done too much in one [98:01] place. That happens, you know, has to [98:03] happen sometimes. Persist the recipe, [98:05] then persist the brew session. You could [98:07] do that as all one big transaction, but [98:08] put each one in its own transaction as [98:10] well. Uh if possible, it'll just make [98:13] your life easier because you're already [98:14] dealing with enough. Um like I [98:16] mentioned, uh you just how you make an [98:18] entity. It has an ID. Again, recommend [98:21] using EU ids. has functions like change [98:24] name, change email. [98:27] Um, it's going to be mutations on that. [98:29] So, we're going to try to avoid setters. [98:31] Now, these are kind of like setters. Uh, [98:33] but I'll kind of get into some more [98:34] behavior that we're going to have. Um, [98:37] if you look at the constructor of a [98:39] brewer, you know, what is required for a [98:41] brewer? You need a username, a full [98:42] name, an email address, and a password [98:44] maybe to store it login or something [98:46] like that. You we don't have to validate [98:48] any of this. This is basically our um, [98:50] you know, our entity. We've we've [98:51] validated it. There's nothing to do [98:52] here. We know the full name is valid. We [98:54] know the username is valid. Um, your [98:56] entities become quite simple. They're [98:58] just storage contain, you know, storage [98:59] of stuff. [99:01] And like I mentioned, centers are bad in [99:03] entities. Um, we want to avoid uh what [99:06] they call anemic modeling. Um, if you [99:08] look at an ORM, like I've written one in [99:10] the past, it's terrible, but um, Cropel [99:13] is a good example because, um, more [99:15] people know it. So you know you say new [99:17] book and then you set title set price [99:20] you know new author set set [99:24] at no point you know do you know exactly [99:26] when the book is in a valid state you [99:28] know if you if you don't have you know [99:30] is price required like you don't know [99:32] like until you go to persist to the [99:34] database you know is this book in a [99:36] valid state your entities should always [99:37] be in a valid state if possible now [99:39] there's going to be some times where you [99:40] can't do that necessarily and you need [99:41] to try to contain that as much as [99:43] possible but you know in the case of a [99:45] book If it requires a title and a pi [99:47] price, put those in the constructor of [99:49] that object and have them be valid [99:51] object value objects so you know that [99:53] it's a valid title, a valid price. Um [99:55] there's no reason to like have this be [99:56] in limbo anywhere throughout your app. [100:01] If you're calling two setters on in a [100:03] row on an object, um you're probably [100:05] missing a domain concept. So if um you [100:09] know your the mash thing that we're [100:10] talking about if it's like set [100:12] temperature and set quantity set this [100:14] set that you're probably missing some [100:16] some concepts there in your domain that [100:18] you need to look at. Um but basically [100:20] calling any two methods in a row on the [100:21] same object. You might be missing [100:23] something there. It's just kind of it's [100:25] certainly possible you might do that but [100:27] something to keep in mind um passing [100:29] more than one parameter you know passing [100:31] multiple value objects. If you passed [100:32] around final gravity and original [100:34] gravity all the time, uh, you know, [100:37] maybe you should think about creating [100:38] that gravity range object that holds the [100:40] two together so you only have one object [100:41] to pass around. Just simplifies your [100:44] code a little bit. [100:46] Look at another entity. Um, we're going [100:47] to look at this. You know, you have [100:49] grain. It has a name. It has a type. [100:51] Maybe it's, you know, wheat or something [100:53] like that. Love a bond. That's the the [100:55] color of grain. like how dark of a color [100:58] it is in in the brewery brewing uh [101:00] language degrees lintner um that's a how [101:04] great is it at converting from grain to [101:06] sugar you know those are things that [101:07] brewers care about we're going to put [101:08] those into value objects and we're going [101:09] to store those in the grain [101:12] I mentioned behavior is the most [101:14] important thing but I know the the [101:15] developer reptile brains are spinning [101:17] how do we deal with storage and all this [101:18] stuff um if you're doing doctrine I [101:20] recommend doing the doctrine annotations [101:22] or doing the ammo doesn't matter um but [101:24] you know you're going to end up storing [101:26] these back to tables in your database. [101:27] They're just entities just like you do [101:29] usual ORM objects. Um the only thing [101:33] with doctrine is, you know, doctrine [101:34] doesn't know how to store these value [101:36] objects necessarily. And you can write [101:38] um [101:40] embedibles and doctrine and do all that, [101:42] but it's kind of a pain in the ass. Um [101:44] so I recommend, you know, just um cast [101:45] those back to strings and integers, your [101:47] value objects. You should have a git [101:49] value off of that that can give you the [101:50] primitive that you can store in your [101:51] database easily. And then your getters [101:53] that you pull off of that, well, when [101:55] you call get name, put it back into the [101:57] value object so that all of your getters [101:59] on the entities that you need return [102:00] value objects. All the methods on an [102:03] entity should either return a value [102:04] object or another entity if it needs to. [102:06] So an aggregate entity is going to [102:08] return another entity. [102:12] Uh Brewer, I'm not going to go through [102:13] this because that's another just another [102:15] example of how to store it. You guys can [102:16] see this in the slides later. [102:26] Sorry, it's slow. [102:31] But yeah, I mean the reason we're using [102:32] value objects is so when you call get [102:34] full name or get email, you don't have [102:36] to worry about checking that anywhere. [102:38] You know, the email is always valid. Uh [102:40] so changing values you know you're going [102:42] to whatever the the you know the uh [102:45] domain experts call it you know if it's [102:47] changing email address in the example of [102:48] a brewer you know call the function that [102:51] uh in your recipe you know it's add [102:52] grain add have a function called add [102:54] grain and pass a grain entity or pass [102:56] you know grain value object there. Um [103:00] remember the grounded context again uh [103:02] recipes inventory and brewing house [103:04] bounded context. You may have multiple [103:06] grain entities uh throughout your [103:08] system. So you have recipe grain, you [103:10] have inventory grain, you have brewing [103:11] session grain. They're all uh different. [103:13] Don't try to use one object across your [103:15] entire system. Like I said earlier, [103:17] brewers are entities, but they're part [103:18] of a supporting B context. You're going [103:20] to see everywhere. The aggregates that I [103:22] mentioned um kind of going through this [103:24] quickly, but you know, they're the ones [103:25] that manage child entities. I kind of [103:26] already went over those. Um building [103:29] entities is uh you know, you guys [103:32] probably saw these. The first things you [103:33] saw were the, you know, grain and [103:35] recipe. The aggregates are the easiest [103:37] to identify in your system. You know, [103:38] recipe is pretty easy to find. You know, [103:40] you're obvious that you know, recipes [103:41] are going to be needed. Modeling the [103:42] other entities, the the child entities [103:44] is a little bit tough. You know, that [103:45] can be uh difficult. You know, do we we [103:47] have a grain entity, you know, or do we [103:50] need to, you know, how we have to model [103:51] it? That's that's really where the the [103:52] rubber meets the road when you're trying [103:54] to figure out the modeling. Um [103:57] but again, your names come from the [103:58] event storming session. So a um [104:01] aggregate you know a recipe uh if you're [104:03] using doctrine it's going to have this [104:04] big annotation with the grain you know [104:06] relation and stuff like that. Laravel [104:08] you're going to have you know the array [104:10] and things like you're mapping to. Um [104:13] but I don't want you to think about [104:14] storage anymore. We're done talking [104:15] about storage. Um you know let's just [104:17] look at a regular aggregate and you like [104:19] I mentioned you have grain add grain. [104:21] Now you can just store that in array. Um [104:24] but you know think about you know what [104:26] possible business rules could you have [104:28] with you know adding grain to this [104:29] entity. Well um there's this thing in [104:31] brewing um that you have to have a [104:33] minimum amount of diastatic power and [104:35] that was that degrees lintner value that [104:37] I mentioned earlier and if it's less [104:39] than 40 the recipe will not work. It's [104:41] an invalid recipe. So we can actually um [104:44] you know throw an exception uh in our [104:46] function here that the grain is not [104:47] valid. Now if you're passing grains in [104:49] you know to the constructor you could [104:50] validate it there. uh but you can do the [104:53] math right here in your entity uh and [104:55] throw an exception. Now what I would [104:57] recommend like I said is put as much [104:59] logic in value objects as possible. So [105:02] you know instead of doing um this method [105:04] in the um entity let's create a new [105:07] value object called grain bill. That's [105:09] how brewers refer to the amount of grain [105:10] that's going to go in a recipe. So we [105:12] create an immutable array of objects. [105:15] Again value objects are immutable. Uh [105:17] and all the grain objects would then be [105:18] immutable inside of it as you're holding [105:20] them. and you add a grain and it can do [105:22] the math right there. So um your entity [105:26] becomes much much simpler. Again all [105:28] you're doing is holding collections and [105:29] holding on to it. So add grain it just [105:31] calls this grains add grain and I [105:33] remember that's a value object. It [105:34] returns a copy of it a new copy of [105:36] itself. So you set this grains equal to [105:37] it and that becomes your array [105:39] collection and you know do laravel knows [105:41] how to persist that. So again, if you [105:44] have logic in entity, try to move it to [105:46] a value object. And as I mentioned [105:49] before, the aggregates are your [105:50] transactional boundaries for database [105:52] transactions and stuff like that. Again, [105:54] you can read a lot more about that, but [105:56] I hope you're seeing that, you know, [105:57] this kind of code that you're doing is [105:59] much more maintainable, much more [106:00] modifiable. [106:03] This kind of gets to a user experience [106:05] point. Now, we've done all this [106:07] eventtorming. We're building our objects [106:08] with the naming and stuff like that. [106:10] it's going to force you to stop thinking [106:12] about the data. Now, that's I'm, you [106:15] know, kind of an application designer as [106:16] well. This is what they call a tax task [106:19] based user interface. Now, if you've [106:21] seen the HBO show Silicon Valley, um, [106:23] Hide Piper had what they call the [106:25] programmer's interface. Every switch, [106:26] knob, bezel, bevel, everything on there [106:29] possible that you could possibly want to [106:31] change. And this user goes to use this, [106:34] they're totally confused. And but this [106:36] lets you, if you're thinking data first, [106:37] this is the kind of interface that you [106:38] build. And this is an example I built [106:41] for a library system. And [106:44] you know, when a librarian would go to [106:46] use a library system, they don't think [106:47] about editing a book and deleting a [106:49] book. That doesn't make any sense. You [106:50] know, your your functions on a library [106:53] system are like renew a book. You know, [106:55] return a book, replace a book, things [106:56] like that. You know, these these actions [106:59] that you guys wrote, these commands, [107:01] those are the things that people think [107:02] about. Those are the buttons that should [107:03] be in your software. That's going to map [107:05] directly to your functions on your [107:06] entities. So when you're thinking about [107:07] it from the events, you're thinking [107:09] about the entities, you're thinking [107:10] about the B, you know, the bounded [107:11] context, the ubiquitous language, it's [107:14] going to force you to build better [107:15] software. You're not going to be [107:16] thinking about the data first. So [107:18] usability goes up. [107:21] Um, DDD has like very little to do with [107:23] security. Again, that's like, you know, [107:25] kind of concern for every um, [107:27] application, but you know, DDD is just a [107:30] layer as far as, you know, DD uh, [107:32] security is just a layer as far as DDD [107:34] is concerned. um unless that is your [107:36] domain but for the most part most of us [107:37] are just you know putting security in as [107:39] a layer and DDD you know there's [107:41] different ways of calling this layered [107:43] architecture onion architecture the DDD [107:45] way of saying it is hexagonal [107:47] architecture and the idea here is that [107:49] your controllers and security and [107:51] templates are a very thin layer on the [107:53] outside and your core domain business [107:55] logic is what you focus the most on and [107:58] let the framework do the outside pieces [108:00] as much as possible like I said don't [108:02] build your own uh you [108:06] uh login controllers and things like [108:07] that. You know, let the frameworks do [108:09] that for you. Um you know, focusing on [108:12] that core domain uh is, you know, what [108:14] you want to spend your time. You know, [108:15] I've been at the same company um for 10 [108:17] years and doing code maintenance and [108:20] that kind of stuff is not fun. And I [108:23] felt like the first few years I was [108:24] working there, I didn't realize it, but [108:25] I was digging my own grave. You know, we [108:27] built it, we built software that we [108:28] built fast, we built um you know, with [108:31] using crowd apps and stuff like that. [108:32] And now we're trying to maintain it much [108:34] much slower to maintain over time a CRUD [108:36] app than it is to maintain a DDD app [108:38] because everything is encapsulated in [108:40] the DDD apps and it's much easier to [108:42] understand when you go back and look at [108:43] it 5 years later. If you work for a [108:44] consultant agency and you hit it and [108:46] quit it, whatever. You probably don't [108:47] have to worry about this stuff. [108:49] The other reason to do this hexagonal [108:51] architecture and try to separate things [108:52] as much as possible is you know the [108:54] frameworks change much much faster than [108:56] your domain logic. you know the brewing [108:58] logic that you're going to write today [109:00] that's going to be good for I don't know [109:02] 1600 you know started brewing in 1600s [109:04] it's probably good for another 500 to a [109:06] thousand years symphony or Laravel you [109:08] know symphony is going to change every [109:10] six months Laravel changes whenever it [109:12] changes I don't know but you know you to [109:15] keep up with that you're going to have [109:17] maintenance to do on the framework and [109:18] the controllers and things like that you [109:19] want to keep that separate from your [109:20] domain logic you don't want to tie your [109:22] domain logic to your framework code and [109:24] things like that you want to keep it [109:25] separate keep it namespaced and stay [109:26] away from your domain main logic. I'll [109:28] point you to a talk by Mattas Reyes. He [109:30] gave it laron in 2014. Um, decoupling [109:34] the model from the framework and I'm [109:36] going to post these slides up later on [109:37] the joined in. Uh, Ruby Midwest, uh, [109:40] Uncle Bob Martin, uh, has a great talk, [109:43] architecture, the lost years. Another [109:46] one you should watch definitely about [109:47] keeping your domain logic separate. Gist [109:49] of that is if you open your folder of [109:51] your code and this is the example uh [109:54] GitHub project I have for this workshop [109:57] and [109:58] you know you probably can't tell what it [110:00] is necessarily but when you open the [110:02] domain folder up you should sure as hell [110:04] be able to tell what the software is [110:06] doing um versus organizing everything [110:08] into entities and controllers and [110:10] repositories and things like that. Like [110:12] if your code is organized like that you [110:13] you look at those folders and you have [110:15] no idea of cohesion across the you know [110:17] entire app. [110:20] So again thin controllers uh persistence [110:24] things like that are all helping to the [110:25] outside you have an event bus and a [110:27] command bus maybe that you know kind of [110:29] taking application services you have [110:31] those kind of things it's impossible but [110:32] like I mentioned earlier the ports and [110:34] adapters try not to um you know have [110:36] your domain logic depend on the [110:38] framework have try not to have the [110:39] framework depend on the domain logic if [110:41] possible that will definitely help with [110:43] your maintainability. [110:45] All right, so a couple more things to [110:46] mention uh just to get you, you know, [110:48] going in the DDD domain events. Um those [110:52] are just basically mutable value [110:53] objects. Uh part of the core domain when [110:56] I had you write the orange things, I had [110:57] them write you write them in the past [110:59] tense. An event always happened in the [111:01] past tense. When you put it in your [111:02] software, it's already happened. It's [111:03] not possible to have an event that's [111:05] scheduled for the future. That's not an [111:06] event. Um you can create them in [111:09] entities. fine as like you know it's [111:11] happening there but um they don't [111:14] contain the entities so you're going to [111:15] map values out of the entities into [111:17] value objects and store them there you [111:19] know the example was uh brew session was [111:21] planned was one of the events that maybe [111:23] another context is caring about it's [111:25] going to pass it um you know you take [111:27] whatever you wrote in your orange code [111:29] smush it together like one big German [111:31] word and brew session was planned and [111:33] that becomes your event class so like I [111:35] said they've handled the naming for you [111:37] um and Those are just big composite [111:40] value objects that you're going to pass [111:42] around everywhere in the system. You can [111:43] depend on this event. Everything is good [111:45] on it. No checking. You know, kind of [111:47] repeating itself, but you get the idea. [111:51] You know, if you're asking yourself [111:52] where where do these events come from [111:54] right now. Um most of the time you're [111:56] going to come from event from your [111:57] entities or from services or maybe just [111:59] somewhere in your application layer. Um [112:02] one of the things I like to do with [112:03] entities is uh have this trait that we [112:06] use. It's called event recorder. And all [112:08] it does is hold an array of events. So [112:10] that way an object can um as you do [112:12] things in the object you just hold that [112:13] array of events and then uh the [112:16] controllers are using that entity can [112:18] just ask the entity hey what events [112:19] happened and publish those up. Um so an [112:22] example of that is like the yeast [112:24] starter we talked about building a yeast [112:26] starter uh before it goes into the from [112:29] um event recorder. the constructor of [112:31] that will create a event starter was [112:35] made big composite value object record [112:38] it um wherever you're using that you're [112:41] creating that new yeast starter then ask [112:43] it for the events that were created and [112:44] publish them back up to your application [112:47] you know when it's the yeast starter is [112:49] finished you're going to measure the [112:50] specific gravity so you can figure out [112:51] how much yeast you created you're going [112:53] to record that it was finished and [112:55] you're going to publish that up because [112:56] you know maybe somebody cares somebody [112:58] doesn't um but you might as well publish [113:00] the events [113:02] So if you're looking at a controller or [113:04] service or wherever the wherever you're [113:06] doing this this logic on your entities [113:09] um and you have a function that's maybe [113:10] creating it you know like I said you're [113:12] going to create the new entity that [113:13] you're doing um you got to persist your [113:16] entity if you're using doctrine and you [113:17] have to flush it everything should be [113:20] persisted and flush it flushed before [113:22] you fire the event because other pieces [113:24] of the software you don't know where [113:25] they're going to be are going to rely on [113:26] that data to be there it has to be there [113:28] you don't know it someday you might [113:30] decide Oh, we can't publish our events [113:32] right away and act on them because it [113:33] takes too long. We're going to push them [113:34] to a queue. Well, if you've persisted [113:36] your entities before you publish, you [113:38] don't have to worry about that because [113:39] it can happen later. It's not a big [113:40] deal. Um, so yeah, just use an event [113:43] publisher that comes with your framework [113:44] and publish the events. [113:47] Uh, and then you'll build listeners like [113:48] I said and that is other bounded [113:49] context. You have a listener that just [113:51] listens for this event to be come across [113:54] the stream and you know maybe in this [113:56] case it's a inventory automatic [113:58] purchasing listener. So, it's going to [114:00] say, "Oh, you know, Bruce Sesser is [114:01] planned. We better make sure we have all [114:02] the grain handy and order it if it [114:04] doesn't." And again, your value objects [114:06] make this kind of stuff um you know, [114:08] kind of a lot simpler. This could be a [114:10] very complex piece of software, but you [114:12] know, we can we can distill it all the [114:13] way down to a value object that's a [114:15] minimum grain order and make sure you [114:17] know, oh, if it's less than zero, it's [114:18] not possible to be negative. You know, [114:20] we have a lot of things that are all [114:21] happening because these value objects [114:22] are doing the work for us. [114:25] using domain events passing on messages [114:27] and stuff like that make uh things a lot [114:29] more modifiable. [114:31] All right. So um you know there's other [114:34] things in domain driven design like [114:35] specific specifications um building [114:37] business rules in a specification um [114:40] like I mentioned earlier um you know you [114:43] may have grain that you have a certain [114:44] amount of degrees lintner that's [114:46] required. So if you look at your grain [114:48] bill for a piece of uh recipe you're [114:51] going to store this in the database you [114:52] have all these float values and stuff [114:53] like that. um and you want to build a [114:57] repository that's going to return you [114:58] grain that's possible to self-convert [115:00] stuff like that, you're going to use [115:02] these specifications. The specifications [115:04] are basically business rules to still do [115:05] a class and that's going to return a yes [115:07] or no answer. And you're going to use [115:09] those and um we can do an example real [115:12] quick. If you flip through your your [115:14] your uh packet there, um you see I have [115:18] like a uh is it minimum diatic power [115:22] specification. [115:25] Now um that's probably going to operate [115:28] on a grain and I don't I don't want to [115:30] spend any time filling this out. I kind [115:31] of didn't plan that very well. But um [115:35] you know that specification is going to [115:36] return a yes or no answer. of the [115:38] repository. You don't have to build [115:40] these queries into your repositories [115:41] necessarily. If you have a very small [115:44] data set, you don't need to build tons [115:46] and tons of criterias and quer queries [115:48] and all kinds of stuff in your database. [115:50] You can just return all the grain and [115:52] then filter through a specification and [115:54] filter that down uh using a filter [115:57] class. And um you know specifications [116:00] become more important as um business [116:04] rules become more more complex. So we'll [116:06] have specifications that rely on other [116:08] specifications. So a constructor of a [116:10] specification may have five [116:11] specifications with it and you know we [116:14] just use that giant one in one place. We [116:16] say yeah is this uh satisfied by this [116:18] specification. Now if the business rules [116:20] change we don't have to go and update [116:21] the controller code and all this stuff. [116:23] We just update the specification. You [116:24] can test that a lot easier than trying [116:26] to end test everything. Um [116:28] specifications are a very uh important [116:30] thing. So [116:32] everything is awesome right? You guys [116:33] are feeling it. You're feeling the vibe. [116:35] Anybody have any questions on the [116:36] entities and aggregates and stuff? [116:39] No. [116:47] >> Both actually. Yeah. So, um a good [116:50] example would be like uh Brewer was [116:53] fired say, right? Um there might be [116:57] application concerns like we need to [116:59] clear his sessions, you know, we need to [117:00] log him out immediately. we need to um [117:03] you know delete his account from the [117:04] directory. Uh we need to delete his uh [117:07] open directory account. We need to do [117:08] things that are like infrastructure [117:10] concerns. Then there's probably domain [117:12] concerns as well like oh he's in the [117:15] middle of a brew session. We need to let [117:16] somebody know to take over because you [117:18] know he was responsible for this but [117:20] he's gone now. So you're going to have [117:22] both listeners on both sides. Yeah. And [117:25] you probably you want to make your [117:26] listeners um you don't want to have one [117:28] listener that listens for brew brew is [117:30] fired. You may have five listeners. So [117:32] you're kind of spreading out the logic. [117:34] In every bounded context, you'd have a [117:36] separate listener that's listening. [117:40] >> Yeah. [117:59] Yeah. [118:08] >> Yeah. I mean, that's going to be a [118:09] business type rule. So, you're gonna So, [118:11] you know, if you have that problem, [118:13] you're going to have to notify somebody [118:14] or something like, you know, or um you [118:17] could throw an exception. I mean that [118:18] could be the case that you know you're [118:20] um you know when you have a controller [118:23] at least if you're doing stuff in your [118:24] Laravel you can wrap that on a [118:25] transaction and you know throw an [118:28] exception in your listener and the [118:29] transaction won't um even though you've [118:31] flushed and persisted the transaction [118:34] wrapper around the whole thing will make [118:35] the whole thing blow up all at once. [118:37] >> Yeah. And it's kind of um there's some I [118:40] didn't cover this at all but there's [118:41] something when you get kind of further [118:42] into the domain driven design stuff they [118:43] call it sagas or process handlers. And [118:46] it's basically a way of mapping out that [118:48] kind of business flow where it's like [118:49] okay yeah we got to make sure this is in [118:50] place that you know the example is like [118:52] a McDonald's or Burger King when they're [118:55] making your sandwich they gota make sure [118:56] you have the bun the hamburger patty the [118:57] cheese lettuce they don't have to make [118:59] all those at the same time or Starbucks [119:01] for example you know the process can be [119:03] done in parallel but it all needs to end [119:04] up at the same place so you're kind of [119:06] dealing you can do those kind of you can [119:07] model that you know in a class make sure [119:09] that this needs to happen and this needs [119:10] to happen if it doesn't throw an [119:11] exception catch it [119:15] Okay. Um, we got about 10 minutes. I [119:18] want to cover two other subjects that as [119:20] soon as you get into DDD, you're going [119:21] to see and I don't want to conf be I [119:23] don't want you to be totally confused or [119:25] assume that you need to run out and do [119:26] this stuff because um it's designed for [119:29] very very large apps. So again, DDD it's [119:32] you know the people from enterprise [119:34] software people are liking this a lot [119:36] more than your you know small software [119:39] development shop. um you you don't need [119:42] to do these things and one is uh command [119:44] query responsibility segregation CQRS [119:47] you don't need to do this unless you [119:48] have a very big app and you have a lot [119:49] of complex stuff um but a lot of people [119:52] you know they see fancy um ways of [119:55] implementing or fancy frameworks they [119:56] want to jump in and use them uh they [119:58] call this CQRS and it's a fancy way of [120:01] saying we're going to keep the right [120:02] side separate from the read side now um [120:05] what you end up is you have write models [120:07] and you have read models your right side [120:09] becomes is more of your domain model and [120:11] your read side becomes projections and [120:14] um [120:16] you know you kind of can separate you [120:18] know what it is to see like a list of [120:19] grain uh separately from everything you [120:22] could do to grain. So you don't have to [120:23] when you're building your views and [120:24] things like that you don't have to worry [120:25] about all the functionality that can [120:27] happen. You can just read from the [120:28] database and display it. And if you have [120:30] a large team or a big product and or you [120:32] need to cache data things like that the [120:35] secrets may help with stuff where you're [120:36] building projections of data and you're [120:38] trying to cach it. Um the way that kind [120:40] of works and this is kind of like [120:42] together command query response [120:44] declaration. You have a controller and [120:46] you have a command bus. Command bus is [120:48] kind of separate from the controller. [120:50] And as a request comes in the controller [120:52] handles the request creates a command [120:54] which is a value object sends to the [120:56] command bus. Uh sorry there's the [120:59] command. You guys did the blue squares. [121:01] Those are your commands. If you're doing [121:02] CQS those become your command objects. [121:05] Um if you don't do CQS those should [121:07] become your method names. um you know [121:09] add grain, add hops, things like that. [121:12] Um those again are value objects, [121:14] composite value objects. So the [121:15] controller passes that command down to a [121:16] command bus. Command bus figures out [121:19] which handler which is again just like a [121:20] listener. Um fires the command to that [121:24] figures out the response, passes it back [121:26] up. Um the idea here is that you can [121:29] have really really really thin [121:30] controllers because all you have to do [121:32] is take the user input, figure out a [121:34] command, the command is valid. I mean [121:36] it's like that um the example I just had [121:38] all those are value objects. It's [121:39] possible for it to be invalid. Command [121:41] bus you know fires back the response. Um [121:44] in the slides here I'll have a link to [121:45] go learn more about that but um the idea [121:48] is you know that these very complex [121:50] controllers you can eliminate down quite [121:53] a bit. Um I put a diagram in in the [121:56] packet as well as kind of like a you [121:58] know flowchart as far as how that falls [122:00] through your software. Again I don't [122:02] want to talk about it because it's it's [122:04] very complex. Um [122:08] again why would you want to do this? Um [122:10] well having those really thin [122:12] controllers makes it easier to keep your [122:14] domain logic uh separate from your [122:15] framework. You want to switch from [122:16] frameworks you want to make that you [122:17] know changes that it's it's very easy to [122:19] change um if you have many many ways of [122:22] doing the same thing. So if you have an [122:25] iPhone app and a web app and a console [122:28] application, various, you know, many [122:30] many versions of an API and you want to [122:32] do the same thing in multiple places, [122:34] commands and command buses make that a [122:36] lot easier because you build your [122:38] command, you fire it off the command [122:39] bus. All of your domain logic is in the [122:41] handling side. There's no logic in the [122:43] controllers and stuff like that. So it [122:44] becomes easier to do that. [122:47] All right, one more thing and that's [122:49] event sourcing and um that is a uh [122:53] basically a way of storing models and [122:55] data that's different um than most [122:57] people are used to. So it's not database [122:59] tables they're spread across. Um does [123:01] anybody play chess here? Yeah. All [123:04] right. So you guys are probably familiar [123:06] with this notation, but there's a [123:07] notation for chess that you can play [123:09] back any game in chess. Uh and you can [123:12] play it to any point and see what the [123:13] board looks like at that point by [123:15] following the notation. If you look at a [123:17] bank journal, uh, it has credits and [123:19] debits. So, at any point, you can figure [123:21] out the balance by following the credits [123:22] and debits. As software developers, [123:25] you're probably used to seeing like git [123:26] diff requests. Git git doesn't store [123:29] like every copy of every file that [123:31] you've ever had. It stores the [123:32] differences between the um over time. [123:36] That's basically what I'm talking about [123:38] with event sourcing is that you're no [123:39] longer going to persist your event [123:41] properties. Um, your object, your events [123:42] are persisted to an appendon event [123:44] storage. Um, so your object like your [123:48] grain object, you're not going to store [123:49] a name, uh, quantity, you know, those [123:52] kind of things. You're just going to [123:54] store the events like the name was [123:55] changed, the quantity was increased, the [123:57] quantity was decreased, and you're going [123:59] to by looping through those events and [124:01] replaying them, you're going to be able [124:02] to figure out what the current state is [124:04] or what the state was at any time. Um, [124:08] reasons to do events sourcing, uh, it [124:10] avoids a lot of data mapping because [124:11] you're just storing events. You don't [124:12] have to you have a recipe. You don't [124:15] need a grain table. You don't need a [124:16] hops table. You don't need a east table. [124:19] You don't need a you know all these [124:20] other tables that you would need to [124:21] store linked you know associated models [124:23] with all you have to do is store the [124:25] events. U that becomes one table [124:27] associated with your um recipe and you [124:30] potentially reduce model counts because [124:31] you don't need to store all these as [124:32] models. You can store them as value [124:34] objects as events. And um there's a [124:37] couple libraries that are PHP libraries [124:39] that are good for doing this. Um, but I [124:42] kind of wanted to do an example real [124:44] quick that um is in the GitHub [124:47] repository. You can go look at this. Um, [124:50] but uh it's in the like kind of the [124:52] second to last page I think or third to [124:54] last page of your packet there. And if [124:56] you look through that, you'll see that [124:57] um basically you just loop through those [125:00] history events and uh replay them and [125:03] you call a method that knows how to set [125:05] the internal variables uh of that [125:07] object. And all you have to worry about [125:10] storing if you're going to persist that [125:11] object then is the event string. So you [125:13] need, you know, a recipe table that [125:14] might store the ID. That's it. And then [125:17] you have a recipe events table that [125:18] you're storing everything in. You know, [125:20] if you're using NoSQL database, you you [125:22] just have one big blob that is your [125:24] recipe and it's going to have all the [125:25] events associated with it. So storage [125:28] really does not become a concern then of [125:30] at all. It becomes very very easy. Um [125:32] what becomes difficult is that if you [125:35] have um many many recipes many many [125:37] events and you're trying to read that [125:40] data like you want to display a list of [125:42] recipes and all the sol you know what's [125:43] happened you don't necessarily want to [125:45] have to load the recipes loop through [125:47] all the events play them back um you're [125:49] talking about you know complexity you [125:51] know if you remember big O notation [125:53] complexity getting worse and worse and [125:55] worse as you have the objects you know [125:56] if you have 10 recipes to display and [125:58] each one of those recipes has 10 events [126:01] in the fast. You have to load 100 [126:02] objects to load 10 recipes. Obviously, [126:05] that can get way worse. Um, so you can [126:08] cache it. You can do things like that, [126:09] but that's where the CQS and event [126:11] sourcing kind of come together is that [126:13] if you're going to do event sourcing, [126:15] you probably want to build read [126:16] projections that make your application [126:18] fast. So, you're going to want to store [126:19] a cacheed copy of all your recipe names [126:22] and maybe a few details about them. Um, [126:24] so to do event sourcing, you know, it [126:27] only do it in things that are very [126:28] complex or you're carried about care [126:30] about the entity over time. Uh, because [126:32] you get logging for free. Your event [126:34] stream is your log. Um, you know, but [126:37] again, if you start reading material on [126:39] DD, they're going to push you towards [126:41] secure events uh sourcing. You don't [126:45] need to do it um for most applications. [126:47] It's only for big, you know, enterprise [126:50] applications. [126:51] I know I'm a little bit over time here. [126:53] Um, learning more. Again, if you want to [126:55] learn more about brewing beer, homebrews [126:56] association.org, [126:58] home brew, the Reddit home brewing [127:00] thread is really good, go visit your [127:02] local homebrew shop. I have mine in my [127:04] phone as a favorite. Um, they're great. [127:06] You know, always a great resource if you [127:08] have one nearby. More importantly, if [127:10] you want to learn more about DDD, you [127:12] know, all these books are great. I [127:13] mentioned earlier in the beginning, um, [127:15] you can find them on Amazon, whatnot. [127:18] uh a couple of PHP developers that I [127:20] know did a podcast where they ran [127:22] through um they have a couple different [127:24] books that they've gone through, but [127:25] they went through the red DDD book every [127:27] chapter and had a discussion about it. [127:29] It's maybe about 12 hours, 14 hours [127:31] total. U but if you start looking [127:33] through the red book, watch this um dev [127:37] book club goes along with it. It's like [127:39] having a book club. I mean, if you've [127:40] ever done that before, you really get an [127:42] understanding of DDD from watching that [127:43] and understanding it. couple of podcasts [127:46] that you can go watch uh about DDD [127:48] they've t different episodes um there's [127:51] a conference called domain driven design [127:52] Europe that has a all their videos uh [127:54] their sessions are online [127:57] uh if you want a much more in-depth [127:58] workshop this is kind of a high level [128:00] you know we'll talk about it for two and [128:01] a half hours do a few things um I I [128:04] would have wished I could have done more [128:05] um examples but we we took longer than [128:07] to do a few things I talked way way too [128:09] much as everyone knows I do um but if [128:12] you want to go for a couple of days um [128:14] bon Vernon, the guy who wrote Redbook, [128:16] runs workshops and these are all [128:18] international right now. U but he does [128:20] plenty in the United States as well and [128:22] it's a great uh way to learn more about [128:24] it. Uh there's a couple of um GitHub [128:28] GitHub repositories that are great. The [128:31] friends of DDD state of the union is a [128:33] great one. Has a bunch of example [128:34] projects like full end to end um you [128:37] know projects that to get you going on [128:39] DDD. Um, awesome DDD. Again, another [128:42] list of things that you can learn more [128:44] about. Um, you know, that kind of thing. [128:46] If you have questions, there's a [128:48] fantastic Google group, uh, ddd phpb.org [128:52] that just takes you to the Google group. [128:54] Um, [128:56] fantastic answers questions on there. [128:58] You have a if you have a question, [128:59] search in there first. First, you'll [129:00] probably find your answer. Um, but, you [129:03] know, again, you can always reach out to [129:04] me on Twitter um or on my website. You [129:06] can get my email. Leave you with a [129:08] couple of final thoughts. Um, I can't [129:11] teach you everything about DDD in two [129:12] and a half hours, just like I can't cure [129:14] your slice in golf in 60 seconds. It's [129:16] actually not possible. Um, you're going [129:18] to get better by working together with [129:20] stakeholders, working with other [129:21] developers, modeling. Um, if you don't [129:24] have other developers you work with, [129:25] teach your dog about DDD, you learn more [129:27] by teaching. Uh, I have, it's probably [129:30] my fourth time, fifth time speaking [129:31] about DDD. I learn more every time. Uh, [129:34] you know, um, if you don't have a dog, [129:36] you can talk to your elephant. um they [129:38] don't you know they remember everything. [129:39] So, um, have one of these on your desk [129:41] and, you know, when you're thinking [129:42] about code, verbalize it. It just makes, [129:45] uh, for much better code, better [129:47] understanding. [129:49] Reasons why you should learn more about [129:50] DDD. Um, autonomous cars primarily first [129:54] reason. No. Um, CRUD applications are [129:57] dead. I mean, how much longer can it be [130:00] that to generate a full application that [130:02] just reads and updates and deletes data? [130:03] That's that AI is going to have that [130:05] crap figured out in a couple years. [130:07] Don't worry about it. Um, so having [130:09] better skills, having more advanced [130:11] skills, understanding and being able to [130:13] solve problems that are complex that a [130:15] machine may not be able to figure out, [130:16] that's going to be your value for the [130:17] next few years. [130:20] Value objects. Value objects. Value [130:21] objects. Avoid common pitfalls in your [130:23] program. I mean, how many times have you [130:25] had a bug that was tied to a value that [130:27] you didn't validate properly? Value [130:29] objects, big deal. Separate your code [130:31] into [130:33] bounded contexts. Keep things separate [130:35] as much possible. feel much easier. If [130:38] you're dealing with legacy, keep legacy [130:41] away from your bounded contexts. Um, the [130:45] easiest way I found is you're publishing [130:46] events from legacy that are new value [130:48] objects. So, you publish a domain event [130:50] from legacy to talk to the new bounded [130:52] contexts. Don't try to wrap legacy code [130:55] maybe, especially in my case, um, you [130:57] know, legacy code that's not dependency [130:59] injected properly. It's not written [131:01] properly, you know, it's using old OMS [131:03] and things like that. it's not possible [131:05] to move this over to a you know [131:07] dependency injected proper way of doing [131:09] things. Um so you pass messages uh tends [131:13] to be the easiest way to get stuff [131:15] between uh things you know whether it's [131:17] done through an API or call or whatever. [131:21] How many of you have seen the agile [131:23] manifesto? [131:25] Yeah. Okay. So everybody hears agile [131:28] with capital A registered trademark from [131:30] Jira. But the real way that you're gonna [131:32] have a better uh way of building [131:34] software is being agile. And if you look [131:37] at the actual manifesto and this is kind [131:39] of getting cut off because of the [131:40] projector, but you know valuing the um [131:43] individuals interactions over process [131:44] and tools. We've talked a lot about [131:46] ubiquitous language today. We tried to [131:48] you know go through how you can build [131:49] the ubiquitous language with your people [131:51] that you work with. Value that over the [131:54] frameworks and the implementation that [131:55] you build. working software over [131:57] comprehensive documentation, the [131:58] ubiquitous language and mapping those [132:00] directly to entities, mapping those [132:02] methods to those names. You don't need [132:04] to document the the brewer can read your [132:06] code. You don't need to write a bunch of [132:07] documentation that goes along with it. [132:09] And again, customer calibration and [132:11] responding to change, those are making [132:12] your software more modifiable, more m [132:14] more maintainable. [132:17] So, I covered a lot. I talked a lot and [132:19] I know you guys probably have more [132:20] questions and I'm happy to answer them [132:21] afterwards, but we're kind of out of [132:23] time. Um, [132:25] I wish I could have done more examples. [132:27] Um, kind of ran out of time, so I [132:29] skipped a few of them. I had them out, [132:31] you know, we could have done. Um, but [132:33] I'm happy to run through any of those [132:34] after, you know, you want guys want to [132:36] do some coding or anything like that, [132:37] I'm happy to stick around and go over [132:39] more. Does anybody have any questions? [132:43] No. Yeah. [132:58] Yeah. [133:06] >> Yeah. [133:12] >> Yeah. Start with a value. start building [133:14] value objects that you know are going to [133:17] you might be able to use those in legacy [133:19] code because those are going to come in [133:20] easy. There's no dependencies for them. [133:21] So you're going to be able to start [133:22] using those right away. Um yeah, if you [133:25] have a process fire an event and you [133:27] know new code that's reacting to that, [133:29] build a listener and then build your [133:30] model off of that. Um you know we're [133:33] doing we have that exact problem. you [133:35] know, we're we're sharing code between [133:37] we're sharing database tables between [133:39] legacy code and new domain code. And [133:42] that's our primary pain point is that [133:45] legacy code didn't validate something. [133:47] So like in the case of a brewery, you [133:49] know, example, um you know, maybe we [133:51] didn't validate the brewer's full name [133:54] in our domain. We had setters, you know, [133:55] so it just said set set and for some [133:58] reason somebody's name wasn't we didn't [133:59] know who it was. It wasn't set. Well, [134:01] the new domain model expects all that to [134:03] be there. So we end up having exceptions [134:04] because we're looking at data that's [134:06] invalid. Now it's proper that it's an in [134:09] an exception because we can't proceed. [134:11] We don't know who it was. So we stop [134:14] there and we halt you know the the code [134:15] halts. But that's our primary problem is [134:17] that you know trying to share model and [134:20] background stuff with the legacy code [134:21] and the new code becomes difficult. If [134:24] you like if you're going to share data [134:26] and you build a new model, one of the [134:28] things we'll do is like part of our m [134:30] migration process is we'll actually read [134:33] every entity out of the database and [134:35] make sure that it can be rehydrated and [134:37] operated on um making sure that we're [134:39] basically validating all our old data [134:41] going forward that way. So, you know, [134:43] example would be find all the brewers in [134:46] the brewery, loop through each one, call [134:48] get full name, get um, you know, because [134:50] that's going to force it to go through [134:52] the constructor process, the value [134:54] objects, and it's going to validate [134:55] everything. It's the only way to [134:56] guarantee that, you know, you've you [134:58] mapping old legacy code to new domain. [135:06] >> Yeah. [135:08] >> Yeah. um make you can make a value [135:11] object called middle name optional and [135:14] you know they could be set or not set it [135:16] could be empty string you know you can [135:17] deal with that way you can have um [135:20] multiple constructors so I mentioned [135:21] that set a constructor thing you could [135:23] have a full name that's first name and [135:25] last name constructor you could have [135:26] another constructor that's first name [135:28] middle name last name constructor it all [135:30] creates full name objects so now you're [135:32] dealing in full names you're not worried [135:33] about first middle last being there um [135:36] but your your optional parameter [135:38] constructor is handled at [135:40] It's common with like email addresses [135:42] and stuff like that where you may not [135:43] have data. Um, avoid nulls if you can in [135:46] your code. I mean, you'll have less [135:48] problems that way. [135:54] Okay. Thanks, guys. Uh, I appreciate [135:57] your feedback. Um, and I have a lot more [135:59] candy if anybody wants any of those nut [136:01] rolls. You guys suffered enough, so you [136:03] deserve one. But thank you.