Why DDD Makes You a Better Developer
40sTaps into the universal desire for self-improvement and career growth, with a clear promise of a better problem-solving approach.
▶ Play ClipDomain-Driven Design (DDD) is a software development approach that focuses on understanding and modeling the core business problem. It emphasizes creating a shared 'ubiquitous language' between developers and domain experts, which is then directly reflected in the code. This workshop provides a practical introduction to DDD, using the example of building software for a brewery.
DDD is about focusing on core business problems, developing collaboration with stakeholders, and modeling objects in an understandable and maintainable way.
A shared language between developers and domain experts, ensuring everyone uses the same terms for the same concepts.
A collaborative modeling technique using sticky notes to discover domain events and build a shared understanding of the problem space.
Small, immutable objects that represent a specific value in the domain and are always valid. They encapsulate validation and business rules.
Objects with a distinct identity and a lifecycle that can change over time. They are mutable and have state.
A cluster of entities and value objects treated as a single unit for data changes, ensuring consistency.
A boundary within which a particular ubiquitous language applies, separating different parts of the domain.
An architectural pattern that separates the core domain logic from external concerns like frameworks and databases.
A pattern that separates read operations from write operations, often using separate models for each.
A persistence pattern where the state of an entity is derived from a sequence of stored events.
"The title accurately describes the workshop's content, which is a deconstruction of Domain-Driven Design principles."
Domain-Driven Design (Blue Book) by Eric Evans
book
Implementing Domain-Driven Design (Red Book) by Vaughn Vernon
book
How to Brew by John Palmer
book
Matthias Noback
person
Bo Simonson
person
Alberto Brandolini
person
Brewer's Friend
tool
BeerSmith
tool
Brewer Wall
tool
FizzBuzz Enterprise Edition
link
Dev Book Club Podcast
link
Domain-Driven Design Europe Conference
link
Friends of DDD State of the Union
link
Awesome DDD
link
DDD PHP Google Group
link
What is ubiquitous language in DDD?
A shared language between developers and domain experts that is used in both conversation and code.
29:05
What is a value object?
Small, immutable objects that represent a specific value in the domain and are always valid.
66:28
What is an entity in DDD?
An object with a distinct identity and a lifecycle that can change over time.
66:50
What is an aggregate in DDD?
A cluster of entities and value objects treated as a single unit for data changes.
67:24
What is event storming?
A collaborative modeling technique using sticky notes to discover domain events and build a shared understanding.
52:21
What is a bounded context?
A boundary within which a particular ubiquitous language applies, separating different parts of the domain.
45:25
What is a domain event?
An event that has happened in the past, represented as a past-tense verb phrase (e.g., 'Beer was brewed').
55:41
What is a command in DDD?
An instruction to perform an action, often derived from event storming (e.g., 'Create Recipe').
58:26
What is hexagonal architecture?
An architectural pattern that separates the core domain logic from external concerns like frameworks and databases.
107:44
What is CQRS (Command Query Responsibility Segregation)?
A pattern that separates read operations from write operations, often using separate models for each.
119:44
What is event sourcing?
A persistence pattern where the state of an entity is derived from a sequence of stored events.
122:49
What is a specification in DDD?
A class that encapsulates a business rule and returns a boolean answer.
114:35
Ubiquitous Language is Key
This is the foundational principle of DDD, emphasizing a shared language between developers and domain experts.
29:05Event Storming for Discovery
A practical, collaborative technique to model the domain and build ubiquitous language with stakeholders.
52:21Value Objects for Safety
Value objects encapsulate validation and business rules, making the code more robust and reducing errors.
66:28Hexagonal Architecture for Flexibility
This architectural pattern protects the core domain logic from changes in frameworks and infrastructure.
107:44CQRS and Event Sourcing are Advanced
These patterns are powerful but complex, and are not necessary for most applications.
119:44[00:01] All right, I assume everybody can hear
[00:02] me. Do I need to talk a little louder?
[00:04] Are we good?
[00:06] Yeah. All right, great. Um, hi everyone.
[00:10] Um, I've met some of you before. Uh, but
[00:13] I'm Andrew Cassell. Uh, PHP developer.
[00:16] I've been developing for about 10 years.
[00:18] Um, I'm kind of local here. Uh, I live
[00:21] in H. turn, which is about 10 miles away
[00:26] or approximately 8 days travel uh during
[00:28] DC rush hour.
[00:30] Um
[00:32] we're for a uh a nonprofit that's called
[00:34] the Marine Spill Response Corporation
[00:36] and uh we clean up uh oil spills. We're
[00:39] a uh nonprofit um we're the largest in
[00:42] the United States uh that does what we
[00:44] do and we have all kinds of equipment
[00:46] and people who are trained uh if there's
[00:48] an environmental disaster to respond.
[00:52] Uh I work um like I said at doing PHP
[00:54] development there. I do mostly
[00:56] applications. We also build their
[00:58] website and I work as a uh part of a
[01:01] three-man team. So um three developers,
[01:03] small team. Uh, but I would put our
[01:05] three developers up against a team of 10
[01:08] uh, any day.
[01:11] Uh, I'm also the organizer of DCPHP. Uh,
[01:13] so if you're local, uh, we'd love to see
[01:15] you at our meetups.
[01:18] Um, today, uh, hopefully it's going to
[01:21] be a lot less formal than most
[01:22] presentations. Um, this is a workshop,
[01:25] so I intend it to be interactive. Um,
[01:27] the video is going to be recorded. If
[01:29] you guys need to refer to the slides
[01:30] later, uh, I'll put them up on the
[01:32] joined end. I'll also post them a link
[01:35] to Twitter. Uh joined in is the uh
[01:37] conference rating system that you guys
[01:39] should uh you know write this talk
[01:40] afterwards. Uh so the video is the
[01:44] slides are going to be recorded but
[01:45] nothing is going to be video recorded.
[01:47] Um you know so you guys don't have to
[01:48] worry about being up on camera or
[01:50] anything like that if we as we do uh
[01:52] stuff together here. Um I'm going to be
[01:56] you know kind of presenting here for a
[01:57] little while. Then we'll do some work
[01:59] and then we'll present a little bit and
[02:01] do a little work again. But while I'm
[02:03] presenting because I want to try to keep
[02:04] this informal, it's kind of a, you know,
[02:06] small enough group we can do this. Just
[02:07] raise your hand and if you have a
[02:08] question, I'll stop and try to answer
[02:09] your question and stuff like that. Um, I
[02:11] really don't want to go any further
[02:12] unless you're not, you know, you're
[02:14] understanding something.
[02:17] So, um, for also for today, you can
[02:19] assume that all the code you're going to
[02:20] see and do is around is PHP 7 or 7.1.
[02:24] Uh, but that doesn't mean you can't use
[02:26] PHP 5. have been doing this longer than
[02:28] you know PHP5 is what we did it uh you
[02:31] know for a long time before PHP7 came
[02:33] out. So all of the code that you know
[02:35] the examples and stuff you're going to
[02:36] see the only differences will be type
[02:38] hinting uh on the returns and stuff like
[02:40] that that uh you know you'll see from
[02:41] PHP7 but other than that nothing changes
[02:43] to go back to PHP 5. Uh we're also going
[02:47] to take a break in the middle um right
[02:49] around 11 when they um the other session
[02:51] gets out just you guys use the bathroom
[02:53] get another cup of coffee or whatever.
[02:56] Uh also you know as we're doing
[02:58] exercises if you need to leave you know
[03:00] whatever that's fine too. So
[03:03] to get into you know why why are we here
[03:06] today? Um why you know why are you here?
[03:08] Why am I here? Because you know I'm here
[03:09] for the same reasons. I want to become a
[03:12] better developer. I want to be uh a
[03:14] better resource for my organization. Um
[03:16] you know I believe in becoming becoming
[03:19] a craftsman meaning having better code
[03:22] craftsmanship raising the level of my
[03:24] code and becoming a more mature
[03:26] developer and becoming a more mature
[03:29] developer means um better understandings
[03:31] of the problems that you're trying to
[03:32] solve. Becoming uh you know more of a
[03:35] value uh for the company that you work
[03:37] for or for your customers.
[03:41] One of the best ways that I know to
[03:43] become a better developer is through
[03:44] domain driven design
[03:46] and domain domain driven design. It's
[03:50] often referred to as DDD uh in the the
[03:53] you know cool kids on the street call it
[03:54] that. Um but it's a very very large
[03:59] topic and there's no way I can teach you
[04:01] everything in about two and a half hours
[04:02] we have today. Uh but I'm going to try
[04:04] to show you what I think are the
[04:06] fundamentals and insights that everyone
[04:08] uh can benefit from hearing. So um you
[04:11] know anytime a presentation starts with
[04:13] a survey or a definition definition I
[04:15] immediately hate it. Uh but I am going
[04:16] to start with a survey and a definition
[04:19] because I want to kind of find gauge
[04:20] this because it's gonna be you know kind
[04:22] of a workshop. I want to know um couple
[04:23] of questions here. So does anybody know
[04:25] BDD or has experience with DDD at all?
[04:29] One person. Okay. Do okay.
[04:31] >> You've read it. Okay. So this will be
[04:33] this will be fun. Um
[04:36] yeah, it's going to be a very beginner
[04:39] um introduction. I think it'll be good
[04:40] for you and then I'm going to give you a
[04:42] ton of resources at the end so you guys
[04:44] can go and learn more and you know
[04:45] obviously answer questions. So let me
[04:48] tell you what DD is not. It is not drink
[04:50] drive and develop but we are going to be
[04:54] talking about beer today. So please
[04:56] drink responsibly and code responsibly.
[04:59] No. Uh so today's talk and today's
[05:01] workshop is on common sense software
[05:03] development and when I mean common sense
[05:06] software development I mean you know
[05:08] doing things that make sense as as it
[05:10] says um you know to as every
[05:13] presentation should steal a quote from
[05:15] Steve Jobs um design is not just what it
[05:18] looks like it's and feels like design is
[05:21] how it works. If you look at the
[05:23] circuitry of an Apple computer, you
[05:26] know, the old ones, they're they're
[05:27] beautiful compared to most, you know,
[05:29] computers of the time. Uh, and your code
[05:32] should be beautiful, too. There's not
[05:33] much more effort to be put in in order
[05:35] to make your code, you know, more repres
[05:37] more more presentational.
[05:40] So, um, because software to me is first
[05:42] and foremost about problem solving. Now,
[05:45] Freddy Krueger is an excellent problem
[05:47] solver. He is designed to kill and is
[05:49] very effective at it. But what I'm
[05:51] saying is people will enjoy your
[05:53] software much more if it's more like
[05:54] James Bond. Still designed to kill
[05:56] people, okay? But, you know, you're
[05:59] going to want to hang out with James
[06:00] Bond at a bar more, you know, and drink
[06:01] a martini and things like that. So, you
[06:03] want to get the job done, but do it in
[06:06] an aesthetically pleasing manner to both
[06:07] you and your clients.
[06:11] So, the bulk of the information I'm
[06:12] going to talk about today are from these
[06:14] two seminal books on domain driven
[06:16] design. Uh the first one domain driven
[06:18] design uh was a book by Eric Evans. Uh
[06:21] he wrote it in 2004. Um you can kind of
[06:23] think of this uh as the Old Testament of
[06:27] domain driven design. Uh the first time
[06:29] I read it, I did not understand it at
[06:31] all. Maybe I'm a little dense, but it's
[06:33] a very very theoretical book and it but
[06:37] once you understand more of the you know
[06:39] experimental side of things and you go
[06:40] back it makes a whole lot more sense. Uh
[06:43] the second book uh was by Von Vernon.
[06:45] People call it the uh the red book, you
[06:47] know, kind of the new testament of
[06:48] domain driven design. And this goes into
[06:51] much more practical application of how
[06:53] to uh build your code uh using domain
[06:55] driven design. There's been plenty of
[06:58] books afterwards once everybody got on
[06:59] the gravy train of domain driven design.
[07:01] Um you know, if you want to learn more
[07:03] about the techniques and things like
[07:04] that or um you know, if you just you
[07:06] were like me in high school and just
[07:07] read the cliff notes, the domain driven
[07:09] design books on the end in PHP and do
[07:12] domain driven design quickly. um those
[07:14] were, you know, good good uh source
[07:17] material to get going quicker.
[07:20] But, um first off, like when I'm talking
[07:23] about the code and patterns and stuff
[07:25] like this, none of this stuff is new.
[07:27] Nothing that the domain driven design
[07:28] people um created was new. It was all
[07:31] looking at patterns that had already
[07:32] existed in software development for a
[07:33] long time, whether that's repository
[07:35] patterns and object-oriented program um
[07:38] things like that. And you know, most of
[07:39] this comes from books that are even
[07:41] older than the books that I just talked
[07:42] about.
[07:43] Uh, a couple people that I want to thank
[07:46] real quick from the PHP community is
[07:47] Matteas Reyes and Bo Simonson. They've
[07:49] been um, you know, fantastic uh, pushers
[07:52] of DDD and PHP and couldn't do this
[07:56] presentation without them. Okay, so for
[08:00] those of you who haven't heard about do
[08:02] main driven design, this is your
[08:04] definition. So if you read the Wikipedia
[08:06] definition of it, um, you kind of get an
[08:08] idea. uh DDD is about focusing on the
[08:10] core business problems that you're
[08:12] trying to solve, developing a valuable
[08:15] collaboration with the other people who
[08:17] have a stake in the process or in the
[08:19] project that you're you know you're
[08:20] building and then trying to model uh the
[08:23] objects in your software in a way that
[08:25] is both understandable and maintainable.
[08:29] So DDD is really meant um to help you
[08:33] tackle really complicated problems much
[08:35] like putting together IKEA furniture but
[08:37] for software. Um so you know we're going
[08:40] to be trying to figure out the model,
[08:42] how to model what the business is trying
[08:43] to do it and then figure out how to
[08:45] apply that model to code.
[08:49] So, if you don't have a good grasp on
[08:50] object-oriented programming um so far, I
[08:53] apologize. Uh but this is going to be
[08:56] very object-oriented uh heavy. And when
[08:59] I mean object-oriented programming, I
[09:00] don't mean how they teach you
[09:02] object-oriented programming about how
[09:04] you know dogs drive and cars bark and
[09:06] those kind of things. Um this is
[09:08] object-oriented programming how it was
[09:09] meant to be. If you go back and read
[09:11] some of the older books on
[09:12] object-oriented programming from small
[09:13] talk and things like that, um you're
[09:17] gonna this is where the DDD people, you
[09:19] know, read this and applied it to new
[09:22] software practices.
[09:24] So to summarize DDD, we're going to be
[09:26] talking about encapsulation. So
[09:28] encapsulating business rules and things
[09:29] like that in logic, immutability,
[09:32] um something that's going to make your
[09:34] software much easier to maintain and
[09:36] write, modeling. So, we're going to talk
[09:38] about modeling objects and entities and
[09:41] uh stuff like that and behavior and
[09:43] encoding the behavior of the business or
[09:44] the process that you're trying to model
[09:46] in into your software.
[09:49] So, when I when I say the word domain,
[09:51] I'm talking about the problem we're
[09:52] trying to solve. So, or the problem
[09:54] space is it's kind of a universal word
[09:56] in the sense it's either the problem or
[09: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
[1:00:00] and its things like that. Don't worry
[1:00:02] about that kind of stuff.
[1:00:12] Okay, so I think you guys are you're far
[1:00:15] enough long on that one. Um the last
[1:00:17] thing and we're kind of actually done
[1:00:19] because the la the last one is the actor
[1:00:23] and that is you know who did the
[1:00:25] command, who did the action. Um, in this
[1:00:28] case, you know, we probably have like
[1:00:29] one person, the brew master or the
[1:00:30] brewer. So, it's probably going to have,
[1:00:32] you know, the same person on every task.
[1:00:35] So, I'm not going to make you um, you
[1:00:37] know, put green sticky on each one. Um,
[1:00:40] but, you know, I do have to congratulate
[1:00:41] you guys. Guys, diagrams are pretty
[1:00:44] pretty pretty good. Um, they're
[1:00:47] terrible. No, I'm just kidding. Um, so
[1:00:50] you covers kind of, you know, building
[1:00:52] the um ubiquitous language.
[1:00:55] Um, does anybody have any, you know,
[1:00:57] questions about the process? The only
[1:00:58] thing I I would say that I've noticed,
[1:00:59] you guys did a good job naming all your
[1:01:01] stuff. Um, some of the things you're
[1:01:03] going to have problems with in code. So,
[1:01:04] if you called something grain and then
[1:01:06] you had an object that's called mil
[1:01:07] grain. Now, that's fine when you're
[1:01:09] building this, but you're going to have
[1:01:10] a problem. You're going to have problems
[1:01:11] transitioning objects with PHP. It's
[1:01:13] difficult unless you separate them into
[1:01:15] different bounded contexts. When you you
[1:01:17] have an object called grain and you have
[1:01:19] a function called mill, you can't change
[1:01:22] that type of object. So it can't
[1:01:24] translate into a new kind of object. You
[1:01:26] have to create another object called mil
[1:01:28] grain gets a little complex. So
[1:01:30] sometimes you may want to store the
[1:01:31] state of the grain as a you know a
[1:01:33] property of that object not having a new
[1:01:34] object called mil grain. But you know it
[1:01:37] might be important enough that maybe
[1:01:38] they're dealing in one section with just
[1:01:40] milk grain. So you may have an object
[1:01:41] called milk grain. It's possible. Does
[1:01:43] anybody have any questions about this?
[1:01:48] Yeah. Uh sure. It so it's basically the
[1:01:51] who did it. So, um, later when we look
[1:01:55] at the command, it's going to be the
[1:01:56] person who, you know, punched the button
[1:01:58] on the software that said add grain. You
[1:02:00] know, the grain was added. It's going to
[1:02:02] be tied to the event. You know, they're
[1:02:04] going to they're going to be a model in
[1:02:06] your in your somewhere in your software.
[1:02:08] You're going to have an object called
[1:02:09] brewer. You know, that's going to be the
[1:02:11] person logging into your software and
[1:02:12] using it. So, you know, they're they're
[1:02:15] not exactly a bounded context. They're
[1:02:16] not really part of any of uh one
[1:02:19] specific particular bounded context.
[1:02:22] what's called a supporting valid
[1:02:23] context. So they're going to show up
[1:02:24] everywhere in your software. There's not
[1:02:26] really a way to avoid that. Um other
[1:02:28] than you can if you know it's complex
[1:02:30] enough, you may want to create a
[1:02:32] inventory user interface or something
[1:02:34] like that. So that way you have a
[1:02:35] limited set of functions on the user in
[1:02:37] that um area of the software. That may
[1:02:39] help keep things a little bit better
[1:02:41] organized. Or if you have very distinct
[1:02:43] teams that are working on different
[1:02:44] parts of the software, you're more
[1:02:46] likely to do that where you have your
[1:02:47] user which is like a symphony user
[1:02:49] Laravel user and that might end up
[1:02:51] implementing like 15 different
[1:02:53] interfaces from different namespaces.
[1:02:56] That answer your question.
[1:03:02] Yeah.
[1:03:06] >> Yeah.
[1:03:09] Event storming. Event storming. Yeah. Um
[1:03:15] there's other ways you can do it and and
[1:03:17] I'll kind of touch at those real quick.
[1:03:18] Um you know, you guys started building
[1:03:20] diagrams. You can see they're already
[1:03:21] getting kind of large. Um you're going
[1:03:23] to want to break those down into bounded
[1:03:25] context like I mentioned as the thing
[1:03:26] gets larger. Um you know, you start
[1:03:28] circling them off. If you're doing it,
[1:03:29] do this on a whiteboard or a big giant
[1:03:31] long sheet of paper so you can you start
[1:03:33] doing it over and separate the stuff
[1:03:35] out. Um, you know, these, like I
[1:03:37] mentioned, these events are going to be
[1:03:38] pushed around to the different contexts.
[1:03:39] So, like the inventory context needs to
[1:03:42] know when a brew session is planned to
[1:03:43] make sure the ingredients are there or
[1:03:44] something like that. You know, we're
[1:03:45] going to order the grain form
[1:03:47] automatically or something like that.
[1:03:48] And it might be, you know, multiple
[1:03:50] events from the same bound context that
[1:03:51] are coming to it. Um, if you're really
[1:03:54] having problems understanding the
[1:03:55] process, the business process and stuff
[1:03:57] like that, um, there's a couple other
[1:03:58] techniques you can use from user
[1:04:00] experience side of things. Uh, one's
[1:04:02] called business origami and um, learned
[1:04:04] about this at 2011 uh, in 2011 at UX
[1:04:06] week. Um, there's a handsome guy in the
[1:04:08] background there,
[1:04:11] but basically you make these fancy
[1:04:12] little cards uh, and you actually
[1:04:14] physically um, let me jump ahead a
[1:04:16] little bit here. You'll see. But like if
[1:04:17] you're building like an e-commerce
[1:04:19] thing, you actually physically move the
[1:04:20] people around the um, you know, origami
[1:04:24] uh, store so to speak buying things. So
[1:04:26] that way you can identify which cards to
[1:04:28] to write on the process. So it might be
[1:04:31] um useful to actually build a physical
[1:04:33] model of the real world in paper or
[1:04:35] something like that in order to figure
[1:04:36] out oh what cards you know do we to have
[1:04:38] in our um event storming session.
[1:04:42] There's other ways to do this too like
[1:04:44] they call it user story mapping and it's
[1:04:46] kind of the same thing. You build like a
[1:04:47] big long list of um events and then you
[1:04:50] try to find you know the different
[1:04:52] things that you're going to do and break
[1:04:54] it up into you know planned releases and
[1:04:55] stuff like that. But I you know I think
[1:04:56] it's the idea here is that we're going
[1:04:59] to identify the behavior first. You know
[1:05:01] people think about software they don't
[1:05:03] think about database models like I was
[1:05:04] mentioning. They think about what does
[1:05:05] the software need to do for me. So
[1:05:07] they're thinking that you know I need to
[1:05:08] be able to add grain to this. I need to
[1:05:09] be able to you know do things. Those are
[1:05:11] the events. So starting with the events
[1:05:13] and starting with the things that have
[1:05:14] to happen in the software is a much
[1:05:16] better way to to build software other
[1:05:18] than starting with the databases and the
[1:05:20] data. Um so I would give this you know a
[1:05:23] correctness and usability much higher as
[1:05:26] compared to you know CRUD code.
[1:05:29] All right. So, we're going to start
[1:05:31] talking about actual code.
[1:05:34] How do you implement this ubiquitous
[1:05:36] language and how do you, you know, make
[1:05:38] software that is maybe completely
[1:05:39] different from how you guys are writing
[1:05:40] it today. And um you what I mentioned
[1:05:43] earlier is going to be heavy on the
[1:05:44] object-oriented uh side of things. Um
[1:05:47] but it's hopefully not too difficult to
[1:05:49] understand. In domain driven design, we
[1:05:52] have pretty much four basic uh kinds of
[1:05:55] entities and objects in our system. We
[1:05:57] have value objects which are going to
[1:05:59] represent um small things in our system,
[1:06:02] pieces of information. Domain events,
[1:06:04] those are the orange cards that you put
[1:06:06] in your event storming uh session there.
[1:06:08] Those going to translate exactly to
[1:06:10] objects in your system. Entities, those
[1:06:12] are your yellow ones, those are the
[1:06:14] models. Um you know that you had a you
[1:06:17] know you have a grain model that's going
[1:06:19] to become an entity. Aggregates um those
[1:06:22] are your fancy um models and I'll get
[1:06:24] into that. They basically contain child
[1:06:26] entities. So
[1:06:28] um you know a value object like I
[1:06:29] mentioned is the smallest pieces of your
[1:06:31] software. Um biggest thing about them is
[1:06:33] they're going to be immutable. Um they
[1:06:35] have no identity. I'll get into that.
[1:06:37] But examples of value objects in the
[1:06:39] brewing thing is like a hop name, an
[1:06:41] amount paid, a temperature, things like
[1:06:42] that. They're they're values. They're
[1:06:44] not um things that have uh things that
[1:06:47] are stangeable about them. Entities are
[1:06:50] things that are identifiable and they're
[1:06:51] mutable and they have a life cycle and
[1:06:53] they're going to operate on those
[1:06:55] smaller value objects and I'll get into
[1:06:57] that later. But an example of models
[1:06:59] might be a line item in a in invoice.
[1:07:02] You know, you could change the quantity
[1:07:04] or change the price. You know, that that
[1:07:06] that could change over time or you could
[1:07:07] delete the line item. So that has a you
[1:07:09] know life cycle. Brewers, the names
[1:07:11] change. They come and they go, they're
[1:07:12] fired. They're hired. Water chemistry,
[1:07:15] you know, you might have a model for
[1:07:16] your your water chemistry. Well, your
[1:07:18] city water changes, you know, daily. So,
[1:07:20] if you're measuring it, you're going to
[1:07:21] be constantly updating your your water
[1:07:23] supply.
[1:07:24] An aggregate. So, an aggregate is
[1:07:26] basically a fancy entity, a bigger
[1:07:28] entity, and it is responsible for
[1:07:30] managing smaller entities, and it's
[1:07:33] primary job. It's going to have business
[1:07:34] logic for sure. Um, but it's going to be
[1:07:37] the um larger, more identifiable objects
[1:07:40] in your thing. So if you had um things
[1:07:42] on your uh eventtorming session like
[1:07:44] brew session um you know that's going to
[1:07:46] be controlling some things as far as
[1:07:48] what state we are in the process and
[1:07:49] stuff like that. the recipe recipe is
[1:07:51] gonna if you flip to the the recipe that
[1:07:53] I gave you in the packet there it has
[1:07:55] hops it has grains it has yeast you know
[1:07:58] it's got to contain all these other
[1:07:59] models so it's got to manage and it's
[1:08:01] got to hold them all together to build
[1:08:02] one giant thing called a recipe that's
[1:08:05] an aggregate
[1:08:08] but if of all those things value objects
[1:08:11] are by far the most important
[1:08:14] so um the value objects again we were
[1:08:18] talking about out of kind of this the
[1:08:19] brewing You might have an email address
[1:08:21] for a brewer. I don't know. That's kind
[1:08:22] of an easy example. A recipe name. Um
[1:08:24] the date we brewed the beer on. That's
[1:08:26] an example of a value in the system that
[1:08:28] is immutable. You can't change when we
[1:08:30] brewed it on. The weight of grain you
[1:08:32] might have, you know, that's a 13 pounds
[1:08:34] is 13 pounds. You can't you can change,
[1:08:37] you know, how much grain you've weighed
[1:08:38] from 13 to 15 pounds, but the value of
[1:08:41] 13 pounds does not change. It's that is
[1:08:43] 13 pounds. You know, 70 degrees uh
[1:08:46] Fahrenheit is 70 degrees Fahrenheit.
[1:08:48] There's no changing that. If you change
[1:08:49] to 71 degrees, that's as a new
[1:08:51] temperature.
[1:08:53] And all these value objects in the
[1:08:54] system are going to come directly from
[1:08:55] the ubiquitous language that you know
[1:08:57] when somebody if they call it, you know,
[1:09:00] uh the date we brewed on, yeah, you
[1:09:02] might want to shorten that to brood on
[1:09:03] in your code or something like that. But
[1:09:04] if they call it a recipe name, it's a
[1:09:06] recipe name in your code.
[1:09:09] And we're going to have classes that map
[1:09:11] directly to um the classes or we're
[1:09:14] going to have classes that map that you
[1:09:16] look at this language directly to the
[1:09:18] objects in our software. So if you're
[1:09:20] talking about temperature in the brewery
[1:09:22] that you're building software for it
[1:09:24] does everything in Fahrenheit, well
[1:09:25] you're going to have a class called
[1:09:26] degrees Fahrenheit that's going to
[1:09:27] represent that. Um there's no reason to,
[1:09:29] you know, build it out in Kelvin. There
[1:09:31] just brewers don't talk in Kelvin. They
[1:09:33] don't, you know, think about in, you
[1:09:34] know, Kelvin or even maybe degrees
[1:09:35] Celsius depending where they're from. So
[1:09:37] have a degrees Fahrenheit class because
[1:09:39] that's how they're going to class in
[1:09:40] your software because that's how they're
[1:09:41] going to have to put information in.
[1:09:42] They're they're going to want to use
[1:09:43] degrees Fahrenheit and everything.
[1:09:44] They're not going to have to convert.
[1:09:47] And you know these objects are not just
[1:09:49] about creating uh classes that do static
[1:09:52] typing, meaning type hitting in your
[1:09:53] functions. That's not the point of them.
[1:09:55] Um there's studies that have shown that
[1:09:56] you know just the variable names is
[1:09:58] enough to keep you from swapping
[1:09:59] parameters. That's not the whole point.
[1:10:01] Um the point of value objects is to
[1:10:03] reduce complexity and reduce um checking
[1:10:06] in your software. So value objects I
[1:10:09] mentioned are immutable meaning they do
[1:10:11] not change. Um there's no in there's no
[1:10:14] factor of time involved in a in a value
[1:10:16] object. You know the temperature doesn't
[1:10:18] change over time. 70 degrees Fahrenheit
[1:10:20] is 7 degrees Fahrenheit regardless of
[1:10:22] when it is. The other reason um you want
[1:10:25] to have as many objects in your system
[1:10:27] uh immutable in your software is because
[1:10:30] PHP passes objects by reference and if
[1:10:33] you pass an object to a function that is
[1:10:36] mutable. So um that function could
[1:10:38] change something on that object and you
[1:10:40] don't know that. So when that object
[1:10:41] that you pass in could be changed. Now
[1:10:43] if it's an immutable object like a value
[1:10:45] object and you pass that to that
[1:10:46] function you don't have to worry about
[1:10:47] that object being changed. So if I pass
[1:10:49] 70 degrees Fahrenheit to a function, I
[1:10:51] don't have to worry about it coming back
[1:10:52] as 68 degrees. It's not possible. That
[1:10:54] object is locked and it's immutable.
[1:10:56] There's no possible way to do it.
[1:10:59] The other way um the other thing that
[1:11:01] helps you in your software here is your
[1:11:02] your value objects will always be in a
[1:11:04] valid state. Now they don't have state,
[1:11:05] but what I mean by that is they're
[1:11:08] always valid. So 70 degrees Fahrenheit
[1:11:10] is a valid temperature. Now if anybody
[1:11:14] remembers from high school physics,
[1:11:15] there's something called absolute zero.
[1:11:17] you know, you can't be below what 273
[1:11:19] degrees Celsius. You know, 300 degrees
[1:11:22] negative Celsius is not a valid
[1:11:24] temperature. So, we're going to prevent
[1:11:26] that uh in this uh value object class.
[1:11:28] So, anywhere you deal in temperatures,
[1:11:30] you know, it's always a valid
[1:11:31] temperature.
[1:11:33] Value objects become like the thin candy
[1:11:35] shell uh in your application where
[1:11:37] everything stops and keeps everything
[1:11:39] from hitting the nice um creamy center
[1:11:40] in the middle of your application. the
[1:11:42] earlier you can solve problems in value
[1:11:44] objects um the easier you're going to
[1:11:46] have time uh building software
[1:11:49] if you're not doing software uh you're
[1:11:51] not doing test-driven development now
[1:11:53] value objects are a gateway drug to test
[1:11:55] driven development they um are by far
[1:11:57] the easiest to develop doing test driven
[1:11:59] methods
[1:12:01] #my tests don't pass
[1:12:05] so what are value objects they're like I
[1:12:07] mentioned they're just small little
[1:12:08] classes that have one purpose they're
[1:12:10] plain PHP objects
[1:12:12] Um they don't necessarily have to
[1:12:14] inherit from anything or be part of
[1:12:15] something else. They're called call them
[1:12:17] popos. I mean a plain old PHP object. Um
[1:12:21] they're all their properties are
[1:12:24] private. There's no public way to change
[1:12:26] anything about them. Um there's no
[1:12:29] setters on them. Like I said, you can't
[1:12:30] change anything about them. They're
[1:12:32] mutable. U they don't hold references to
[1:12:34] mutable objects. Um, so you know like uh
[1:12:39] a grain for example, you can't have that
[1:12:41] as a value object because the grain
[1:12:44] could actually change like different
[1:12:45] acids and stuff like that or enzymes
[1:12:47] could be different in the grain. So you
[1:12:48] can't hold a value object and have an
[1:12:50] entity inside of it that can change.
[1:12:52] It's not possible. That value object if
[1:12:54] it's 70 degrees Fahrenheit, like I said,
[1:12:56] should be 70 degrees Fahrenheit forever.
[1:12:57] There's no change to it. The biggest
[1:12:59] difference um in domain driven design
[1:13:02] code versus most code is um we're going
[1:13:04] to throw as many exceptions as possible
[1:13:06] in the construction of these objects.
[1:13:08] And exceptions are going to be your
[1:13:09] friend. You're going to catch these
[1:13:10] exceptions when you need to to react to
[1:13:12] it. But for the most part um you know a
[1:13:14] lot of your validation is going to come
[1:13:16] from throwing exceptions in the
[1:13:17] constructor.
[1:13:20] And like I said, value objects only
[1:13:22] depend on scalers and other value
[1:13:24] objects. Um so like I said, you can't
[1:13:25] pass an ID to a value object and hold
[1:13:27] it. um 70 degrees Fahrenheit. To hold
[1:13:30] that, you need maybe a float that's 70
[1:13:33] and a unit that's Fahrenheit. So there
[1:13:35] might be two values you need to hold.
[1:13:36] Those don't change. Um that's all the
[1:13:38] dependencies that this this value object
[1:13:40] is going to have. Um and they're not
[1:13:42] dependencies that you have to inject
[1:13:44] either. Um so you know, sure, if you're
[1:13:46] following Solid Principles, you know,
[1:13:48] dependency injection, things like that,
[1:13:49] if you have repositories and services
[1:13:52] and stuff like that, you don't want to
[1:13:53] just be littering those willy-nilly in
[1:13:55] your code. That's that's a bad practice.
[1:13:57] Value objects are a little bit
[1:13:58] different. Um they're pretty much like
[1:14:00] scalar types. Like do you worry about
[1:14:01] having integers in your code anywhere or
[1:14:04] strings? No, you don't. You don't worry
[1:14:05] about that. These are pretty much just
[1:14:06] an extension of the scalar types. So
[1:14:09] don't worry about saying new temperature
[1:14:11] in anywhere in your code. It's it
[1:14:13] doesn't have any dependencies. It's
[1:14:14] designed that way. Uh it's going to be
[1:14:16] perfectly fine to have those new uh
[1:14:18] things happening in your code. You may
[1:14:20] um you know value object gets very
[1:14:22] complex. You may need a factory which
[1:14:24] you know if you guys are familiar with
[1:14:25] patterns you may need a factory to build
[1:14:28] that uh value object sure you might want
[1:14:30] to inject that in that case but for the
[1:14:32] most part value objects you just put
[1:14:34] them wherever you need to put them and
[1:14:35] use them. All right enough talking about
[1:14:39] value objects let's look at an example
[1:14:40] and I put this example in the packet
[1:14:42] that I put out just so you guys can see
[1:14:44] it a little bit closer. Um but let's
[1:14:46] talk about you know the business rules.
[1:14:48] Uh we're going to apply those directly
[1:14:50] to our code. So the brewers have told us
[1:14:52] that yeah we name all our recipes and
[1:14:54] they have to be nice creative witty
[1:14:55] names um that we put up on the board and
[1:14:58] everybody smirks at and they they sniff
[1:15:00] it first and drink it. No, I mean so
[1:15:02] important thing is to have you know some
[1:15:04] business rules associated with this
[1:15:06] recipe name. And basically the business
[1:15:07] rule is that a recipe name cannot be
[1:15:10] empty. So if I if I create a new recipe
[1:15:13] name object and I pass an empty value in
[1:15:16] it should blow up. So it's going to
[1:15:17] throw an exception. you know, if I add
[1:15:20] if I pass in a valid name, it should
[1:15:22] give it back to me in the getter. So,
[1:15:24] it's get value. It's kind of a simple
[1:15:25] way of saying, you know, give me back
[1:15:27] the value out of this object.
[1:15:29] A lot of times I like to do on these
[1:15:31] simple value objects, if you can cast
[1:15:33] into strings, we'll put a two-string
[1:15:35] method in that'll just cast it. So, you
[1:15:37] don't have to have get value everywhere
[1:15:38] in your code. Uh, can get a little
[1:15:40] verbose. Hopefully, those are nice witty
[1:15:42] names like iphpa and recursive viton.
[1:15:46] So, uh, like I mentioned the recipe
[1:15:48] test, I think you guys can see that I
[1:15:50] printed it out.
[1:15:52] So, um, like I said, we're doing
[1:15:54] test-driven development. We've added our
[1:15:56] test. Let's run it. And everything fails
[1:15:58] because the class doesn't exist. The
[1:15:59] method's not found, all of that. So,
[1:16:02] let's start, uh, by building that class.
[1:16:04] And like I mentioned, the thing that
[1:16:05] we're going to do most of the time in
[1:16:07] these value objects is throw an
[1:16:08] exception in the constructor when things
[1:16:10] fail. So, when you're building your
[1:16:12] value objects, you're going to try to
[1:16:13] identify the failure points for these
[1:16:15] value objects. So, if the value that's
[1:16:17] passed in is a string, we don't have to
[1:16:19] test if it's string because we're using
[1:16:20] PHP 7.1. Um, if we're using PHP 5, you
[1:16:24] couldn't type hint that string there. If
[1:16:26] it was value, so you'd have an
[1:16:27] additional check like if uh not is
[1:16:31] string in PHP, you would then throw an
[1:16:32] exception saying this is not a valid
[1:16:34] string. Um, but yeah, I mean, if it's
[1:16:37] empty, we throw an invalid recipe name
[1:16:39] exception. In this case, I've created an
[1:16:40] exception class because maybe you need
[1:16:42] to deal with that exception specially.
[1:16:43] If you don't need to deal with the
[1:16:44] exceptions especially in this case throw
[1:16:46] an invalid argument exception which is
[1:16:48] in the root you know base name space of
[1:16:50] PHP that that's perfectly fine I I do
[1:16:52] that in some of the examples and then we
[1:16:54] hold the value and
[1:16:57] that you know that is enough to pass our
[1:16:58] first test in that uh recipe test thing
[1:17:01] where it's testing to make sure we pass
[1:17:03] an empty string
[1:17:05] it fails.
[1:17:08] Next thing we have to do is we just add
[1:17:09] a get value function and that returns
[1:17:11] the value back out of the value object
[1:17:14] again. Run the next test pass test
[1:17:16] passes and then the uh tworing that's
[1:17:19] really easy to implement. You just get
[1:17:21] the value back. You could also just wrap
[1:17:22] the the get value function. Um you know
[1:17:25] internally you could just call that
[1:17:27] public function internally. Not a big
[1:17:28] deal. Um, I mean, again, I don't I
[1:17:31] wouldn't stress too bad or too much
[1:17:34] about the value objects and how you
[1:17:35] implement them. As long as you're
[1:17:36] testing them and you're um, you know,
[1:17:38] you're wrapping things in test and
[1:17:39] you're identifying the fault points. The
[1:17:41] internal code, if you want to, you know,
[1:17:43] get fancy with your implementation
[1:17:44] there, that's fine. Do whatever you
[1:17:45] want. Important thing is you test,
[1:17:47] lights are green, tests are clean. It's
[1:17:50] in the trap. You know, thing is it's
[1:17:52] locked down. So now you know as we look
[1:17:54] at this recipe name class anywhere I use
[1:17:57] this in the system I'm guaranteed that
[1:17:59] the recipe name is valid. So it's kind
[1:18:01] of a different way of looking at code is
[1:18:03] you no longer ever have to check on this
[1:18:05] recipe name throughout everywhere in
[1:18:07] your code. Recipe name is now valid.
[1:18:09] It's now a valid object. It's not
[1:18:11] possible for somebody to create an
[1:18:12] invalid recipe name.
[1:18:14] Look at another example. Get get a
[1:18:16] little bit more advanced. Um so a brewed
[1:18:19] on like when was the recipe brewed on?
[1:18:21] you know, we write a test for that.
[1:18:22] We're just going to create a new
[1:18:23] datetime, and it should give us back,
[1:18:25] you know, a datetime uh immutable uh
[1:18:28] value. So, you know, you just hold it.
[1:18:30] Datetime already does the validation for
[1:18:32] you. You know, it's going to throw an
[1:18:34] exception if it's an invalid date. So,
[1:18:35] for the most part, you're done. Um but,
[1:18:38] you know, if you want to add some
[1:18:39] business rules in there, maybe to catch
[1:18:41] edge cases and things like that, you
[1:18:42] can. You know, like, oh, you know, it's
[1:18:44] not possible because we're writing the
[1:18:45] software today for there to be a date
[1:18:47] that's less than, you know, 2017
[1:18:49] November 15th. It's not possible. the
[1:18:50] software didn't exist. So throw an
[1:18:52] exception if the date's too far in the
[1:18:54] past or you know oh maybe this we know
[1:18:55] this software is only going to last a
[1:18:57] year so we put it in the future you know
[1:18:59] things like that you know it you want to
[1:19:00] try to stop anything you identify that
[1:19:03] are problems with that uh object in the
[1:19:06] constructor
[1:19:08] another example of pounds you know um we
[1:19:11] can test that value uh like I mentioned
[1:19:13] make sure it's a float um you know it's
[1:19:16] not really possible to have a negative
[1:19:17] weight you know unless we discover
[1:19:19] antimatter weight is always positive So
[1:19:22] you can treat pounds as you know
[1:19:23] positive in your system and throw like
[1:19:26] at the bottom one here test negative
[1:19:27] throws exception you know it's easy to
[1:19:29] check that um you know value is less
[1:19:31] than zero uh may not be negative now
[1:19:35] because PHP can be screwy sometimes you
[1:19:38] want to identify like I said pounds
[1:19:39] always must be positive you want to
[1:19:41] identify a way that that makes sense to
[1:19:43] both you and the business of what this
[1:19:45] object is going to represent. PHP has
[1:19:47] this nasty thing of a negative zero.
[1:19:51] What is negative zero? It doesn't make
[1:19:52] any sense. Let's eliminate that from our
[1:19:54] domain. Um, you know, so we can just
[1:19:56] cast it to a regular zero if we have
[1:19:58] negative. That way, if they print it out
[1:20:00] and it's zero pounds, it doesn't
[1:20:01] accidentally show up as negative 0
[1:20:03] pounds and confuse the hell out of them.
[1:20:05] You know, your two string in this case,
[1:20:07] you know, maybe the breweries decide
[1:20:09] that, you know, they don't have to worry
[1:20:10] about anything less than, you know,
[1:20:11] 0.0001 ounce, you know, pounds. Do your
[1:20:14] formatting and your value objects. do
[1:20:15] your rounding. You know, you might want
[1:20:17] to hold the entire value. If it's like a
[1:20:19] long float, you may want to hold that.
[1:20:20] But when you get the value out or we
[1:20:22] display it to them, you handle your
[1:20:23] formatting here. Now, that's only for
[1:20:25] simple things, uh, like, you know,
[1:20:27] pounds and stuff like that. If you have
[1:20:28] dates and more complex objects and you
[1:20:31] need to format it, again, looking at
[1:20:32] solid principles, it's a good idea to
[1:20:34] separate your formatterers into another
[1:20:35] class or into a template, things like
[1:20:37] that. Again, those policies apply.
[1:20:41] The the thing I mentioned about
[1:20:43] immutable in the value objects doesn't
[1:20:45] mean that you can't have behavioral
[1:20:46] functions on a in a value object. That
[1:20:49] is definitely possible. The trick is
[1:20:51] though is we're going to return a new
[1:20:53] object um if you change something. So if
[1:20:56] we had 11 pound or 10 sorry 10 pounds
[1:20:59] and we want to reduce that amount by 6.1
[1:21:02] pounds, we expect a value of 3.9. Now
[1:21:04] what that is actually going to return is
[1:21:06] a new pounds object with 3.9 pounds in
[1:21:10] it. As I mentioned that that original
[1:21:12] one we 10 10 we passed it's not mutable.
[1:21:14] So it cannot change. It will return a
[1:21:16] new object.
[1:21:20] So like I mentioned biggest thing about
[1:21:22] value objects is it eliminates checking.
[1:21:25] So the pounds object decrease by
[1:21:28] function. A little bit hard to see maybe
[1:21:30] there at the bottom. Um but yeah like I
[1:21:32] said the first thing you're going to do
[1:21:33] there is new self
[1:21:37] in your object. So you're going to
[1:21:38] return a pounds object because like I
[1:21:40] said the value objects are not are
[1:21:41] immutable. You cannot change them. And
[1:21:43] you're just going to say this value
[1:21:45] minus decrease by pounds get value. You
[1:21:47] don't have to check and see if the
[1:21:48] pounds are negative or like in case the
[1:21:50] recipe name. You don't have to check if
[1:21:51] it's a string or anything like that.
[1:21:52] It's all done. I don't even have to
[1:21:54] check that when I'm subtracting, you
[1:21:57] know, say have six pounds and I try to
[1:21:58] subtract 10. I don't have to check that
[1:22:00] here because it's not possible. the
[1:22:02] constructor will catch that because this
[1:22:04] will come in as a negative value and
[1:22:06] it'll be neg3 and the exception will be
[1:22:07] thrown weight cannot be negative. So a
[1:22:10] lot of your checking and if logics and
[1:22:12] stuff like that can be handled by the
[1:22:13] the the um value objects you know like
[1:22:15] mentioned the 70 degrees if you try to
[1:22:18] subtract 400 degrees from that it's not
[1:22:20] possible the absolute zero is going to
[1:22:21] catch that you have a question
[1:22:42] >> Yeah, that that's perfectly fine. Like
[1:22:44] um yeah, if you had a weight object in
[1:22:46] and say it's you just want to deal
[1:22:47] because you're dealing in many
[1:22:48] measurements like let's say that not
[1:22:49] like a brewery where it's all pounds
[1:22:50] because it's in the US. Um yeah, you
[1:22:52] have a weight object and you're going to
[1:22:54] have to store I'm going to get into this
[1:22:55] in a second, but it's they call it a
[1:22:57] composite value object. So weight is
[1:22:59] going to contain two diff distinct value
[1:23:01] objects probably maybe in the case
[1:23:03] probably just a float just a regular you
[1:23:05] know PHP object float for the and then a
[1:23:08] string or a unit of measure object that
[1:23:11] represents the unit. So then anytime
[1:23:14] like this if you're like decrease like
[1:23:16] let's say it's kilograms you try to
[1:23:17] decrease it by pounds in your you know
[1:23:20] you can throw exceptions there and say
[1:23:22] like hey you know what the units don't
[1:23:24] match or you can do the conversion if
[1:23:25] that's business is like yeah we get
[1:23:27] stuff randomly all the time we want to
[1:23:28] do the conversion automatically be nice
[1:23:30] and do it for them don't throw an
[1:23:31] exception say oh you must put this in
[1:23:33] pounds you know build these rules into
[1:23:35] your business build intelligence into
[1:23:36] your software you know like I mentioned
[1:23:38] before the factories if it's difficult
[1:23:40] to create an object from a string or
[1:23:42] something like Feel free to build a
[1:23:44] factory if that's the way you want to do
[1:23:45] it. I mean, it's fine. However you
[1:23:47] operate, you know, building your code
[1:23:48] now is probably for the most part fine.
[1:23:50] It's mostly just naming and
[1:23:51] understanding that these value objects
[1:23:53] are going to be immutable and always in
[1:23:55] always valid.
[1:23:57] Um, one of the things I like to do on
[1:23:59] stuff is like static constructors on
[1:24:01] these value objects. Go ahead real
[1:24:02] quick.
[1:24:07] >> Yeah.
[1:24:13] Now, now PHP especially five, you know,
[1:24:18] five or 54 up objects are incredibly
[1:24:22] easy to generate. The only time you'll
[1:24:24] run into a problem is if you build um
[1:24:28] recursive
[1:24:30] like issues where okay um you know I
[1:24:33] want to make sure that the Fahrenheit
[1:24:35] object can't be below absolute zero.
[1:24:38] Well, I can't build a absolute zero
[1:24:41] Fahrenheit object that extends
[1:24:43] Fahrenheit because it's not possible for
[1:24:45] it to be absolute zero. It's just not,
[1:24:47] you know, so you end up having to make
[1:24:49] sure you kind of separate things a
[1:24:50] little bit. But objects are cheap. PHP
[1:24:53] objects are very very cheap. So don't
[1:24:55] don't be afraid of creating all these
[1:24:56] objects and stuff.
[1:24:58] Good question. Okay. Um, so static
[1:25:01] constructors and I like to call these
[1:25:02] natural language constructors. They're,
[1:25:04] you know, they're coming from the
[1:25:05] ubiquitous language. coming from what
[1:25:07] you know um somebody talks about you
[1:25:09] know maybe in the example here we have
[1:25:11] pounds but we want to sometimes we get
[1:25:12] stuff in that's metric in kilograms um
[1:25:15] you know you have a function that's
[1:25:16] static function from kilograms and this
[1:25:18] will return a a new pounds object and do
[1:25:21] the math for you now your software is
[1:25:23] just dealing in pounds not worrying
[1:25:24] about kilograms and stuff like that but
[1:25:26] we know that that weight is always valid
[1:25:30] so
[1:25:31] um
[1:25:33] yeah I mean you might have to do you may
[1:25:35] even want something like from string. So
[1:25:37] if somebody writes like 2.0 lbs, um you
[1:25:40] may have you may want to write some
[1:25:41] parsing logic there that does some reax
[1:25:43] or something fancy and does that.
[1:25:49] I think I've um you know done the
[1:25:51] temperature example here a few times. Um
[1:25:54] you get the you know the formulas and
[1:25:56] stuff like that. I was going to do an
[1:25:57] example but I think I'm going to move
[1:25:58] past that. Does everybody kind of get
[1:25:59] the idea that we're, you know, you're
[1:26:01] creating these objects, they're
[1:26:02] immutable, and um, you know, you do all
[1:26:04] the validation in the constructor? Just
[1:26:05] think everybody got that?
[1:26:13] >> No.
[1:26:15] >> Yeah. Do whatever you need to do. Um,
[1:26:16] like I was saying, like it's two float,
[1:26:18] pounds a string, something like that
[1:26:19] unit of measure. And I'm just about to
[1:26:20] go into like composits of these. So, um,
[1:26:24] but you know, like I was saying, the the
[1:26:26] units are important getting those right.
[1:26:28] You know, if you've heard stories about
[1:26:29] the Mars Climate Orbiter that crashed
[1:26:31] into Mars because they were working in
[1:26:33] miles and kilograms, you know, things
[1:26:35] like that. Um there was a the plane
[1:26:37] called the Gimly Glider that um you
[1:26:39] know, they they weighed the the fuel in
[1:26:42] kilograms instead of pounds. It didn't
[1:26:44] have enough like, you know, had half you
[1:26:46] know, whatever was less than half the
[1:26:48] fuel it was supposed to had to, you
[1:26:49] know, crash land. Luckily, nobody was
[1:26:50] hurt. Um you know, these are the kind of
[1:26:54] things you can eliminate by using these
[1:26:55] value objects. um and making sure that
[1:26:57] you know it's not possible to have
[1:26:58] invalid state in your app. All right, so
[1:27:02] composite value objects um easy example
[1:27:06] would be a brewer's name. So a brewer
[1:27:09] full name, you know, might consist of a
[1:27:11] first name and a last name. If we look
[1:27:14] at the the full name object,
[1:27:17] uh there's really nothing to validate
[1:27:19] here other than the fact that there is a
[1:27:21] first name and a last name because first
[1:27:23] name is a value object. It's just going
[1:27:24] to make sure it's not empty just like
[1:27:25] the recipe name. Last name value object,
[1:27:28] it's going to make sure it's not empty.
[1:27:29] So the full name, we know now passing
[1:27:32] that around anywhere in our system, we
[1:27:34] know exactly what a full name is always
[1:27:36] valid. It's not possible to have empty
[1:27:37] strings. And right here, we can
[1:27:39] implement the two string method of how
[1:27:41] to represent that in the system. So if
[1:27:43] later you decide to add middle names and
[1:27:45] suffixes, prefix and stuff like that, um
[1:27:47] you don't have to worry about where
[1:27:48] you've, you know, said, you know, two
[1:27:50] string or get value on a full name or
[1:27:52] formatted that. It's, you know, you just
[1:27:54] have to update the constructor and where
[1:27:55] you've used it and stuff like that. Um,
[1:27:57] but yeah, I mean, we've eliminated a lot
[1:27:59] of checking here. There's no checking to
[1:28:01] make sure first name is not empty and
[1:28:02] last name is not empty. We're relying on
[1:28:04] these value objects to compose
[1:28:05] themselves.
[1:28:07] We're going to, you know, the goal here
[1:28:09] is to encapsulate as much of our
[1:28:10] business logic in the value objects as
[1:28:12] possible. Like I mentioned, the
[1:28:13] temperature thing. Um, you can get very
[1:28:15] complex with these value objects. So,
[1:28:18] one of the things that a brewery is very
[1:28:20] concerned with is the amount of alcohol
[1:28:21] that is in a beer. Um, you know, they
[1:28:24] have to put it up on their board. They
[1:28:25] have to tell you by law how much alcohol
[1:28:27] is in a beer. And, uh, they call it ABV.
[1:28:30] If you see that up on the board, that'll
[1:28:32] tell you, you know, alcohol by volume,
[1:28:33] it's 7% alcohol. Um, you know, that's
[1:28:36] kind of a stronger beer. So, don't
[1:28:38] drink, you know, 10 of them. But the way
[1:28:41] you find out how much alcohol is in a
[1:28:43] beer, you can obviously send it out to a
[1:28:45] lab and spend a ton of money, have it
[1:28:47] analyzed, um, or you can just calculate
[1:28:49] it using some measurements. And if you
[1:28:52] know about the brewing process there,
[1:28:54] like I was telling you, if sugar and
[1:28:55] yeast turn alcohol and uh CO2 out the
[1:28:59] other side, um there's actually a
[1:29:01] chemical equation for this, but I'm not
[1:29:02] going to bore you to death with that.
[1:29:04] But if we're trying to calculate the
[1:29:05] amount of alcohol that comes out, we
[1:29:06] know we don't care about CO2 and we
[1:29:08] don't care about the yeast. That doesn't
[1:29:09] affect the amount of alcohol that comes
[1:29:10] out at all. Well, we care about the
[1:29:12] sugar and the sugar, the amount of sugar
[1:29:14] we start with and the amount of sugar
[1:29:15] that we end with. Now, like I said,
[1:29:17] yeast consumed sugar. So if we know how
[1:29:19] much sugar the yeast consumed, we know
[1:29:21] roughly how much alcohol a yeast
[1:29:23] produces when it eats that sugar. We can
[1:29:25] calculate how much alcohol is in the
[1:29:27] solution. So we get alcohol by volume.
[1:29:30] By dividing those two things um you know
[1:29:33] subtracted from each other. Now you
[1:29:35] measure that um amount of sugar in a
[1:29:38] thing called specific gravity, but it's
[1:29:39] basically the density of the sample
[1:29:41] versus the density of water. And you can
[1:29:42] do that very expensively. If you're a
[1:29:43] professional brewer, you probably buy,
[1:29:45] you know, a machine that to do that. Um,
[1:29:48] but many craft breweries and every home
[1:29:50] brewer does, and I have one of these up
[1:29:52] there here if you want to look at it
[1:29:53] later. It's a hydrometer and basically
[1:29:55] it you put it in the water or you put it
[1:29:57] in the the W that came out of the boil
[1:29:59] kettle and you measure how far it
[1:30:01] floats. And um, you know, so it floats
[1:30:04] in the solution. It has a little scale
[1:30:05] on it so you can measure, you know, how
[1:30:07] much it goes up and down. And if you
[1:30:09] know anything about chemistry, the
[1:30:11] density of something lowers as it heats
[1:30:13] up. Things expand. Like water actually
[1:30:16] grows. I think it's like 5% from cold to
[1:30:19] boiling like the volume of water grows
[1:30:21] um in a solution. So, um when you're
[1:30:25] measuring that specific gravity, you
[1:30:26] have to know exactly what temperature
[1:30:27] you're measuring that specific gravity
[1:30:29] at because um like I showed you earlier,
[1:30:32] that hydrometer has been scaled and
[1:30:34] measured exactly a certain temperature.
[1:30:36] So, in my case here, I have a 60°ree
[1:30:39] hydrometer. So, that scale is meant for
[1:30:41] 60° uh Fahrenheit.
[1:30:44] And you can look it up on a table and
[1:30:46] figure out how much to move, you know,
[1:30:48] the the temperature uh with specific
[1:30:50] gravity. Um or you can try to you can
[1:30:52] calculate it very easily. So I look at
[1:30:54] um I put a thermometer in when I do the
[1:30:56] measurement. So I know like in this case
[1:30:58] it was it's kind of hard to see there,
[1:30:59] but 66 uh degrees and I measured the
[1:31:03] specific gravity and my you know my
[1:31:05] hydrometer's set at 60. Do a little bit
[1:31:08] of math and it's actually kind of
[1:31:10] complex math but you can calculate you
[1:31:13] know what it was supposed to be reading.
[1:31:14] So if it read 1.040, we know it's
[1:31:16] actually 1.041 because the temperature
[1:31:19] adjusted it slightly. And it's not a
[1:31:21] very hard calculation to do. So kind of
[1:31:23] use this as an example with the
[1:31:24] composite value objects to do this. So
[1:31:27] the hydrometer test, you know, we're
[1:31:29] going to look at the um building a test
[1:31:30] for this first because I said like I
[1:31:32] mentioned u testing value objects is
[1:31:34] pretty easy. I just pulled values from
[1:31:36] that table and you know when the
[1:31:38] temperature is exactly the temperature
[1:31:40] of the hydrometer, everything should
[1:31:41] match up. That's an easy test, right? Uh
[1:31:44] then we do maybe a test a bit higher,
[1:31:46] put some values in there, you know, do a
[1:31:49] test a bit lower, do the same thing. And
[1:31:52] we're going to end up building a
[1:31:54] composite value object that's called a
[1:31:57] gravity or original gravity. In this
[1:31:58] case, if you're measuring it before the
[1:32:00] the yeast has eaten the sugar out of the
[1:32:03] the wart, it's called the original
[1:32:04] gravity. So, we're going to call we're
[1:32:05] going to create a value object that's
[1:32:06] called original gravity. And to read the
[1:32:09] gravity reading, like I mentioned, you
[1:32:10] read the gravity reading off the
[1:32:11] hydrometer. So that's a float value
[1:32:13] object that we've made sure is within a
[1:32:15] reasonable range. And a temperature that
[1:32:16] we know is within a reasonable range as
[1:32:18] well. So um
[1:32:21] you know, we we know that we can verify
[1:32:23] that the hydrometer, you know, class
[1:32:25] here can value object can tell you, you
[1:32:27] know, you can't read a value above or
[1:32:28] below the the scale. And you know, we
[1:32:30] can do the logic right here to correct
[1:32:32] the gravity for the temperature. So it's
[1:32:34] like I said, a big long equation. um but
[1:32:37] it's all centralized in this value
[1:32:39] object. So the business rules and the
[1:32:40] business, you know, uh the way they're
[1:32:43] they do things, we're putting as much as
[1:32:45] we can in the value objects.
[1:32:50] So like I said, we want to um find the
[1:32:52] uh gravity here, you know, the alcohol
[1:32:54] by volume. This is the formula right
[1:32:56] here. There's our readings. Original
[1:32:58] gravity is OG and final gravity would be
[1:33:01] after the yeast eats it. And that's the
[1:33:02] formula for creating it. Now we can also
[1:33:05] create a composite value object out of
[1:33:06] that. We can have a gravity range. So
[1:33:09] gravity range value object becomes a
[1:33:11] original gravity and a final gravity.
[1:33:13] Now we can make sure right in this value
[1:33:15] object that the original gravity is
[1:33:17] lower than the or sorry is lower than
[1:33:19] the final gravity because as the yeast
[1:33:21] eats sugar the amount of sugar in there
[1:33:23] becomes less. The gravity actually
[1:33:25] becomes lower. Um so we can verify that
[1:33:27] you know somebody is putting in stuff
[1:33:29] properly and that's all this object
[1:33:31] needs to be. It just needs to be a
[1:33:32] holder of you know those values perhaps
[1:33:35] and then you know the class when we
[1:33:37] write the alcohol by weight and the
[1:33:38] alcohol by volume can work from that
[1:33:41] gravity range. So this is again another
[1:33:42] value object that has a static
[1:33:44] constructor that creates itself from
[1:33:46] another value object and the formula is
[1:33:48] right in here. So I don't have to
[1:33:49] validate anything you know as far as the
[1:33:51] gravity ranges go. All that's been
[1:33:53] validated for me temperatures the
[1:33:54] readings all that stuff's validated. I
[1:33:56] just have to worry about building the
[1:33:57] formula here and doing the math and to
[1:34:00] actually calculate ABV then you know we
[1:34:02] do that final function equation there
[1:34:05] and we end up with another value object
[1:34:07] that is the alcohol by volume. So you
[1:34:08] can guarantee everywhere in the software
[1:34:10] that the alcohol by volume has been
[1:34:12] validated nothing to do no checking. I
[1:34:15] want to contrast that you know real
[1:34:16] quick with u I mentioned that brewer
[1:34:18] wall and that that's a PHP software
[1:34:20] application but if you look and this is
[1:34:22] just one class of calculations they have
[1:34:25] um you know they have ABV OG and final
[1:34:27] gravity um you know they're checking is
[1:34:30] the original gravity more than the final
[1:34:32] gravity is it a numeric value is it a
[1:34:34] numeric value you know they're doing
[1:34:35] that and if you look through that one
[1:34:37] class um you know as they do it they do
[1:34:39] it over and over over again they
[1:34:40] actually you can't see because it's
[1:34:41] getting cut off the top of the projector
[1:34:43] here but they check og greater than
[1:34:45] final gravity five times in one class.
[1:34:48] So right there um you know you're
[1:34:50] repeating code. That's one of the first
[1:34:51] things we learn is don't repeat
[1:34:52] yourself. Don't repeat yourself. Don't
[1:34:54] repeat yourself. Don't repeat yourself.
[1:34:55] Don't repeat yourself. Um it's a big
[1:34:57] thing in code. You know the is numeric
[1:34:59] checks. Not having those value objects
[1:35:00] that represent a float knowing that a
[1:35:02] final gravity is accurate. They did that
[1:35:04] 39 times in one class.
[1:35:07] Passing these value objects around you
[1:35:09] know eliminates a huge amount of
[1:35:10] checking in your software. Um, you know,
[1:35:13] you've put all of that checking into
[1:35:14] small little classes that are very,
[1:35:16] very, very easy to test. Now, like we
[1:35:19] mentioned earlier, not doing things in
[1:35:20] DDD. Some things are CRUD. Even things
[1:35:22] that are CRUD, I still use value objects
[1:35:23] a lot because it makes that stuff a lot
[1:35:25] lot easier.
[1:35:27] So, like I mentioned, you know, DDD, we
[1:35:29] have these objects. Recipe name,
[1:35:30] temperature, date brood, those are all
[1:35:32] valid. We know they're valid. CRUD, you
[1:35:34] know, like I said, strings, floats, you
[1:35:35] don't know what they are. Functions,
[1:35:36] validations testability usability I
[1:35:39] think is, you know, a lot higher. You
[1:35:40] don't have to worry. the users don't
[1:35:41] have to worry about accidentally
[1:35:42] screwing formulas up, things like that.
[1:35:45] Um, another check there. And of course,
[1:35:47] you know, we all test our code. So, all
[1:35:49] the time.
[1:35:52] No. Uh, but if it's obvious that you're
[1:35:55] not going to have time to test
[1:35:56] everything. Um, but value objects, I
[1:35:58] would say absolutely test them and
[1:36:00] because those are the like I said, the
[1:36:01] very first thing that your your
[1:36:03] application you put as much logic as you
[1:36:05] can into them and focus on them. um
[1:36:08] because
[1:36:09] when you're building entities and these
[1:36:11] are the models I was talking about,
[1:36:12] you're going to rely heavily on those
[1:36:14] those value objects. So um those
[1:36:17] entities like I said they're
[1:36:18] identifiable, they have state, they're
[1:36:19] mutable. Um but they operate on the
[1:36:21] value objects. They use those value
[1:36:22] objects in order to store values and um
[1:36:25] you know change over time. Um ideally
[1:36:28] they're storage agnostic. Now that's not
[1:36:29] always possible uh depending on what you
[1:36:31] know frameworks you're using, stuff like
[1:36:33] that. Laravel. Um, sorry. You may not be
[1:36:37] able to do that quite as easily, but if
[1:36:38] you're using Doctrine and stuff like
[1:36:40] that, um, you know, it makes a little
[1:36:41] bit easier to just keep your stuff
[1:36:42] storage agnostic and then do mapping
[1:36:44] later. But, um, do as much as you can in
[1:36:47] the value objects. Put as little as
[1:36:48] possible in the entities. Your entity
[1:36:50] should just be storing values and
[1:36:51] holding state. Um, you know, use those
[1:36:54] doctrine mappings, doc annotations. Lar,
[1:36:56] if you're Laravel developers, I'm sure
[1:36:57] there's a few of you in the crowd.
[1:36:58] Nothing wrong with that. Um, you'll do
[1:37:00] this a little bit differently. I'm going
[1:37:01] to show examples in doctrine. Um, but
[1:37:04] Laravel, you probably will use your ORM
[1:37:06] objects to hold state. So, you're going
[1:37:08] to pass those to your entities and hold
[1:37:09] state. That way, your entities can kind
[1:37:12] of worry about business logic that's
[1:37:13] associated with it. So, you're still
[1:37:14] going to you're going to map in and out
[1:37:15] of value objects in order to do your
[1:37:17] mapping um through the OM
[1:37:20] behavior first, storage second. So, like
[1:37:23] I made you guys do the event storming,
[1:37:25] thought about modeling, we weren't
[1:37:26] worried about data and stuff like that.
[1:37:28] entities again I mentioned earlier
[1:37:30] single entity aggregates contain other
[1:37:32] entities just to kind of um you know
[1:37:35] keep those two in your head the code
[1:37:37] behind them is almost identical it's
[1:37:39] just that the aggregates store you know
[1:37:41] multiple entities and if you're doing
[1:37:43] transactional stuff um your transaction
[1:37:46] boundaries are going to be around the
[1:37:48] greater aggregates so when you save a
[1:37:50] recipe you want to save all the hops and
[1:37:53] grains associated with it all at the
[1:37:54] same time um if you have a recipe and a
[1:37:57] brew session together and you're
[1:37:59] operating those in the same controller
[1:38:00] because you've done too much in one
[1:38:01] place. That happens, you know, has to
[1:38:03] happen sometimes. Persist the recipe,
[1:38:05] then persist the brew session. You could
[1:38:07] do that as all one big transaction, but
[1:38:08] put each one in its own transaction as
[1:38:10] well. Uh if possible, it'll just make
[1:38:13] your life easier because you're already
[1:38:14] dealing with enough. Um like I
[1:38:16] mentioned, uh you just how you make an
[1:38:18] entity. It has an ID. Again, recommend
[1:38:21] using EU ids. has functions like change
[1:38:24] name, change email.
[1:38:27] Um, it's going to be mutations on that.
[1:38:29] So, we're going to try to avoid setters.
[1:38:31] Now, these are kind of like setters. Uh,
[1:38:33] but I'll kind of get into some more
[1:38:34] behavior that we're going to have. Um,
[1:38:37] if you look at the constructor of a
[1:38:39] brewer, you know, what is required for a
[1:38:41] brewer? You need a username, a full
[1:38:42] name, an email address, and a password
[1:38:44] maybe to store it login or something
[1:38:46] like that. You we don't have to validate
[1:38:48] any of this. This is basically our um,
[1:38:50] you know, our entity. We've we've
[1:38:51] validated it. There's nothing to do
[1:38:52] here. We know the full name is valid. We
[1:38:54] know the username is valid. Um, your
[1:38:56] entities become quite simple. They're
[1:38:58] just storage contain, you know, storage
[1:38:59] of stuff.
[1:39:01] And like I mentioned, centers are bad in
[1:39:03] entities. Um, we want to avoid uh what
[1:39:06] they call anemic modeling. Um, if you
[1:39:08] look at an ORM, like I've written one in
[1:39:10] the past, it's terrible, but um, Cropel
[1:39:13] is a good example because, um, more
[1:39:15] people know it. So you know you say new
[1:39:17] book and then you set title set price
[1:39:20] you know new author set set
[1:39:24] at no point you know do you know exactly
[1:39:26] when the book is in a valid state you
[1:39:28] know if you if you don't have you know
[1:39:30] is price required like you don't know
[1:39:32] like until you go to persist to the
[1:39:34] database you know is this book in a
[1:39:36] valid state your entities should always
[1:39:37] be in a valid state if possible now
[1:39:39] there's going to be some times where you
[1:39:40] can't do that necessarily and you need
[1:39:41] to try to contain that as much as
[1:39:43] possible but you know in the case of a
[1:39:45] book If it requires a title and a pi
[1:39:47] price, put those in the constructor of
[1:39:49] that object and have them be valid
[1:39:51] object value objects so you know that
[1:39:53] it's a valid title, a valid price. Um
[1:39:55] there's no reason to like have this be
[1:39:56] in limbo anywhere throughout your app.
⚡ Saved you 2h 16m reading this? Transcribe any YouTube video for free — no signup needed.