0:02 Um Mary Perry is a dear friend of mine
0:03 and I'm very excited for her to be on
0:06 the Laracon stage for the first time. Um
0:09 a little bit of lure about Mary is um I
0:11 I host a podcast a podcast called Mostly
0:14 Technical with my friend Ian and Mary
0:16 Perry. All right, we got eight fans out
0:19 there. I love that. Um Mary Perry had
0:21 the first sticker on her laptop uh
0:23 thanks to producer Dave. So Mary and I
0:26 have been friends for a long time. um
0:27 she doesn't work with Laravel
0:30 professionally daytoday but she came to
0:34 Laracon for the first time 2 years ago
0:36 and was just totally floored by the
0:39 community and just continues um to
0:40 invest and be a part of this community
0:42 and that's one of the things I think is
0:45 so special about this and um Mary is is
0:48 brilliant she's self-taught she's
0:50 enthusiastic um generally she's a
0:52 database person which a woman after my
0:55 own heart but today uh she is coming
0:56 from scrant
0:58 Pennsylvania to talk to us about design
1:00 patterns. Please put your hands together
1:03 for Mary Perry. [Applause]
1:30 Oh,
1:38 uh, hello. I had this, uh, [Music]
1:44 I had this whole, um, entrance planned.
1:45 It was like really elaborate. There's
1:47 going to be choreography. I asked some
1:48 people to help me with dancing. There's
1:50 like a different song, but I think I
1:53 baro something yesterday when I was um
1:57 playing golf. Um and uh I needed to have
1:58 a more measured entrance. Just get a
2:00 little bit of rest. Um I'm just trying
2:02 to compose myself because I'm new to
2:05 speaking. Um some of these puns are
2:08 terri treble. Um I'm actually string you
2:11 all along. I can't dance. Um on that new
2:14 note, uh what's the good word?
2:17 I'm Mary Perry. I'm from Scranton,
2:18 Pennsylvania. I don't have too many
2:21 interesting hobbies, but um I like
2:23 liking things. You may have seen me on
2:25 social media saying nice things about a
2:27 project that I think is cool. Um my
2:30 handle is cifus. Uh the first part is
2:33 from the Arabic root cifher, which means
2:35 zero or nothing or null. It's also the
2:38 root of cipher. Um so I basically think
2:40 of it as like false and then I tried to
2:42 turn into an adjective. So it's like
2:45 kind of falsy. um which I think is an
2:47 interesting concept and here's an
2:51 example of why. Um you could write a
2:55 function that returns a boolean um
2:56 checking that an object has an
2:58 attribute. But sometimes in real life we
3:00 find that true and false don't really
3:02 satisfy every relevant case. So we can
3:04 define a class that helps us to combine
3:08 multiple checks for booleans and make a
3:10 more complicated assessment of whether
3:12 the evaluation should be true or false.
3:13 And this works really well like in
3:16 authentication for example. And this is
3:18 really all design patterns are named
3:20 solutions that you can reuse that you've
3:22 reworked to solve cases that h you
3:25 haven't encountered yet. Um but instead
3:27 of all of this if we were working
3:30 together I could just say
3:32 let's manage the access with assertions
3:34 and then you could say skipping all of
3:37 this. Um I think a guard close pattern
3:40 would be a better choice. uh because in
3:42 some cases true and false and falsy are
3:44 all important and so is the way you
3:46 handle them and I think the names of
3:47 these patterns are really interesting
3:49 but maybe you don't and I don't really
3:50 think that that matters because if
3:53 you've worked with layer you've probably
3:54 used a guard class in one of your
3:57 applications and if you didn't have to
3:59 invent it I'm guessing no matter what
4:00 your background is the first time you
4:02 used a guard class it worked pretty well
4:05 and it didn't take that long
4:08 um just really quick uh to see a key for
4:10 the uh diagrams that I'm using in this
4:13 talk, you can go to ado.larvel.cloud.
4:16 It's going to be um more detailed in the
4:19 future. It's very very basic right now.
4:22 Um and if you want to follow me for
4:23 updates, you can check out my pink
4:26 carry. I'm at cphrius and all my other
4:28 socials are linked there. So without
4:31 further ado, this is my talk. Much to do
4:33 about naming.
4:34 You already know that perhaps the best
4:35 reason to use Laravel is its
4:37 productivity. And what I mean here when
4:39 I say productivity is that many of the
4:40 problems that need to be solved when
4:42 you're designing a web application um
4:45 already solved and given to you for
4:47 free. It takes about 10 minutes to set
4:49 up a default layer of application with
4:51 authorization and even multi-tenency and
4:54 also have a coffee. Um and because
4:55 you're using Laravel, you probably
4:57 already know not to try to solve every
4:59 problem with first principles. Laravel
5:02 is an entire ecosystem of solutions to
5:03 common problems. And when you build with
5:05 Laravel in his packages, you're
5:07 benefiting from other people's mistakes
5:10 and from their experience as experts. So
5:11 this means you're probably going to ship
5:14 faster while avoiding foot guns. All
5:15 that considered, do you need to learn
5:17 design patterns?
5:20 Probably not. So uh you're already
5:22 capturing design experience in a form so
5:23 effective you don't really have to think
5:25 about it. And just mentioning the names
5:26 of these packages that make up the
5:30 ecosystem communicates the complexity of
5:32 these solutions as well. Layer core is
5:34 full of design patterns and your
5:36 development experience with Laravel is
5:38 full of their benefits. In the source
5:40 code, you can look at it. It's concrete,
5:42 testable, readable. These patterns are
5:44 combined in Laravel's fundamental
5:46 solution to the question of web
5:48 applications. How to best return a
5:52 response to a request? Um, the answer is
5:54 from Laravel's perspective the uh
5:56 request life cycle. And over the next 20
5:58 minutes or so, I would like to take you
6:00 on a tour of it and point out some
6:01 places in Laravel core where those
6:05 patterns are used. Um the index php file
6:08 loads the composer generated autoloader
6:09 uh definition and then retrieves an
6:12 instance of the Laravel application in
6:14 bootstrap. So the whole project of this
6:16 first step section um is creating an
6:18 application and we'll start with a
6:20 singleton. The Laravel application is a
6:22 singleton because it has a method which
6:24 returns a unique instance. Um
6:26 application extends container among
6:28 other classes and the get instance
6:30 function ensures that only one instance
6:33 is ever um returned when you ask for it
6:34 and when it needs to be created for the
6:37 first time set instance takes container
6:40 contract and overrides it. A container
6:42 contract is the inter interface that
6:43 defines the required parts of the
6:46 instantiation and your instance of the
6:48 container implements it. application
6:50 also has other methods that are
6:51 inherited and overwritten from these
6:53 interfaces and they actually work when
6:55 you get your application running. Um, in
6:58 the context uh contracts directory in
7:00 the container.php file, we're going to
7:02 see the container contract which has
7:05 bind which doesn't do anything until the
7:07 container class overwrites the
7:09 definition of a functional method and
7:11 the class knows or knows how to find and
7:13 return the data it needs which can be
7:14 stored and modified without modifying
7:17 the singleton itself. And the unique
7:18 application object can be returned using
7:20 applications get instance method which
7:23 we just saw. Um so there can only be one
7:25 in a singleton. It uses an interface by
7:27 inheriting and overriding it and it
7:29 knows it's the only instance. Many of
7:32 these surfaces are factories which is a
7:34 really good pattern for if you want uh
7:35 one of a group of products but you don't
7:37 know which one at a given time. So in
7:40 this factory um the product uh
7:42 ultimately determines through the
7:43 creator and the concrete creator how
7:45 we're going to get a concrete product
7:46 which in this case is going to be
7:50 sessions. Um so this is uh where the
7:53 session manager is registered and then
7:55 the result is going to be um stored in
7:58 the service container as a singleton. Um
8:00 this is an example in the session
8:03 manager where we're taking um a
8:05 instantiation of one of those concrete
8:08 factories um and creating it with build
8:10 session. This kind of cookie cares about
8:12 uh this kind of session cares about
8:15 cookies and expiration. And there's a
8:16 very similar one where we're going to
8:18 take a database session handler and it
8:20 cares about you know the table and the
8:24 connection etc. Um so in general a class
8:25 a factory is a class that provides
8:28 instances from a group of subasses. They
8:30 have a method that's determined at
8:32 runtime. Um it has products which are
8:34 similar objects produced by a factory
8:36 and used by your application. And it
8:38 uses an interface or contract to give
8:40 instructions of those similarities and
8:43 ensure that the similarities are there.
8:45 Uh speaking of services, if you need
8:47 immediate wormhole like access to the
8:48 service in the service container, you
8:50 can use a facade. Uh the diagram for a
8:52 facade looks different from other
8:53 patterns. Generally, facads hide
8:56 complexity while providing a few simple
8:57 access points like an API or an
9:00 interface. Here's a classic example. Um
9:02 if you're using a pi compiler, you
9:04 pretty much only need the compiler
9:07 method. Um unless you're writing one,
9:09 but then you'd probably be like using Go
9:11 or Rust by the way, and your editor
9:13 would probably be neim by the way, and
9:15 you'd be running like Arch by the way.
9:17 So I'm really just speculating wildly
9:20 here. Um, a facade in a word is
9:22 encapsulation. Hiding complexity in a
9:24 system makes the code which interacts
9:27 with that simp system simpler. But
9:28 Laravel gives you more than a design
9:31 pattern of a facade. They're more
9:33 specific and they give you access to a
9:35 service provider class from anywhere.
9:37 Realtime facads, you could get static
9:40 access. You could do custom facads. They
9:42 are an awesome vanity plate. They look
9:44 fantastic on a hat. And if you learn
9:46 them really deeply, then you can stay up
9:48 late into the internet on the internet
9:50 arguing with strangers about whether
9:52 anyone should ever be allowed to use them.
9:54 them.
9:55 That's not nearly as productive as
9:56 actually trying to write code with them
9:58 and seeing what the service container is
10:00 capable of, but you could.
10:03 Um, after first steps, the uh request is
10:04 going to be sent through the handle
10:07 function of the kernel, either the HTTP
10:09 or console. Web requests we're going to
10:12 kind of focus on now with the HTTP.
10:14 Um, and if you don't use a facade,
10:16 Laravel will find the appropriate
10:18 classes via inversion of control. This
10:20 family of patterns provides instances
10:21 without requiring the controller to know
10:23 about them or be direct freely
10:25 responsible for them.
10:28 So um it inverts the control flow,
10:32 increases decoupling and frameworks are
10:36 really good uh use case for
10:39 uh the dependency injection and
10:41 inversion of control and so are event
10:43 handling systems and event uh Laravevel
10:45 has a lot of events. Uh there's four
10:47 varieties of inversion of control and
10:49 Laravel arguably uses all of them but
10:51 we're just going to talk about um
10:53 dependency resolution really quick. The
10:55 service container uses bind and binding
10:56 like strategies to resolve and
10:59 autoresolve dependencies for you. So you
11:01 never have to experience dependency hell
11:03 when you're using Laravel. Um you've
11:05 probably seen code like this in a
11:08 controller and whenever you call
11:09 construct either implicitly or
11:11 explicitly in Laravel, it's a hint that
11:14 some dependency injection is happening.
11:17 Um so anytime a service is resolved um
11:20 we can see make or build happening. Um
11:23 with make we're going to see the um
11:26 dependencies resolved. Laravel will go
11:30 through the resolve function and return um
11:32 um
11:34 and iterate through the dependencies
11:35 making sure that they're all created or
11:37 throwing an error outside of your
11:39 controller. So um you can avoid
11:41 catastrophe or ensure in as in most
11:43 cases that the object you're trying to
11:47 create can be created. um the
11:50 method is resolved when the constructure
11:52 the controller is actually called and
11:53 there's a lot going on behind the
11:55 scenes. It's a for a very short amount
11:58 of code. I really love to be able to see
12:00 the complexities of good the controller
12:02 and know what's going on there. It makes
12:06 me very happy. Um then there's a builder
12:08 pattern I'm going to talk about in terms
12:10 of mil uh middleware. Um in the
12:12 bootstrapping phase we saw this index
12:14 entry point and the project of this
12:16 phase is to instantiate an application.
12:19 Um so now we're going to talk about how
12:21 the middleware gets created. The builder
12:22 pattern is a solution when we want to
12:24 build a complex object using the same
12:26 construction project but get a different
12:28 representation every time. The director
12:29 in the builder pattern is a method which
12:31 works um to build the product. And the
12:33 director of this is going to be the
12:34 kernel um which is responsible for
12:36 passing the request through the
12:38 application's middleware stack. And the
12:40 plan is to send a request through this
12:42 pipe object which is configured with
12:43 whatever middleware is going on in the
12:46 application. Um the order the middleware
12:48 occur is important and when you modify
12:50 the kernel you can choose different
12:52 orderings um based on the type of
12:55 request that you're uh getting. Um the
12:56 pipeline needs to send the request
12:58 through these middlewares which modifies
13:00 the request as it passes through and the
13:02 concrete builders or individual
13:04 middleware inherit from the middleware
13:06 interface and eventually a product is
13:08 specifically configured. In this case
13:10 it's the request object. If none of the
13:12 middleware stop the request from
13:14 continuing during this pipeline then the
13:15 request can be routed to the appropriate
13:17 routing controller with the rate HTTP
13:20 verb. So in general um the builder
13:22 pattern reuses functions in the same
13:24 project for different object
13:26 representations, produces complex
13:28 objects and the build steps are managed
13:32 by a director. Um next the service
13:34 providers are loaded.
13:36 I assure you this is very important but
13:38 I don't have time to elaborate on it
13:40 because we're down to eight minutes. So
13:42 uh next is routing. During routing
13:44 service providers are registered and the
13:46 request is going to be handed off to the
13:48 router for dispatching. My favorite use
13:51 of Laravel is eloquent and a close
13:52 second is collections which is also kind
13:54 of eloquent. Collections are a type of
13:56 iterator and database enjoyers may like
13:58 to know that another name for this
14:00 pattern is cursor. Uh route collection
14:02 provides a lot of functionality on top
14:03 of listing the routes in our
14:06 application. So here's another diagram.
14:08 The client in this case is going to be
14:11 um the Laravel routing mechanism and um
14:14 our iterator is actually the iterator
14:15 aggregate interface that's inherit
14:17 that's from PHP in general. This gives
14:19 us all kinds of things that we might
14:22 want to do with a list. Um the abstract
14:23 route collection is going to collect all
14:24 of the routes that we have listed in
14:27 various route files like web PHP or off
14:29 PHP or API PHP if you have one or a
14:32 custom one. Um and then we have this
14:35 object that um can be returned and get
14:38 routes with more specific behaviors that
14:40 we have decoupled but can use with that
14:43 object. Um that gives us a lot of
14:45 additional functionality specifically in
14:47 the routes collection. We can use this
14:50 to compile routes, support subdomains,
14:51 name routes, group routes and
14:53 middleware, use fallback routes, all
14:55 kinds of things. Um and it's because of
14:57 this decoupling. So in general,
14:59 iterators uh let you access the elements
15:02 of an aggravated object, avoid exposing
15:03 the internal structure or bloating the
15:05 list too much and traverse the list in
15:08 different ways um by defining different
15:09 ways of traversal for different purposes.
15:11 purposes.
15:13 Um it's a combination of the routing and
15:15 the verb which determines the request
15:16 needs from the container. And that
15:18 brings me to the strategy pattern.
15:20 Generally a strategy is an interface to
15:22 be inherited and it happens in some
15:24 context from which it's decoupled. um
15:26 the strategy has an interface which
15:28 defines some behaviors or attributes and
15:30 the the strategies are all supposed to
15:32 have and then the concrete strategies
15:33 overwrite them and do slightly different
15:35 things for different cases. I already
15:37 showed you at least three strategies and
15:39 you can find this all over layer. It's
15:42 generally just a good life choice. Um
15:44 in the context of the controller methods
15:46 return views and those views are
15:47 decoupled from the controller the
15:50 request the route and the verb. In the
15:52 context of the application, all the
15:53 middleware have a handle function and
15:54 the behavior is decoupled from the
15:56 middleware pipe and the service
15:59 container. And in the concept of a
16:01 service container, service managers can
16:02 build unique sessions by parameterizing
16:05 a construction of the concrete factories
16:07 with the service manager.
16:09 So strategies maintain a reference to a
16:11 strategy object in a context. concrete
16:13 strategies inherit from the interfaces
16:15 in a strategy and then it implements
16:18 that behavior as it sits on the strategy
16:21 and using interfaces is good.
16:23 So we've reached the point of finishing
16:25 up where the response travels back
16:26 outward through the rout's middleware
16:28 and the application has a chance to
16:30 modify or examine the outgoing response.
16:32 The command also known as the action
16:34 pattern takes a behavior um we may have
16:35 implemented in a method and stores all
16:37 the information we need to execute in
16:39 that object which can be parameterized
16:41 by the object that executes it. So this
16:43 is an example of raification the process
16:46 of turning some process into a first
16:50 class object. Here's an example. Um the
16:51 application receives the action as a
16:53 parameter to its destroy method in some
16:55 controller and the action instance in
16:56 that controller is invoked when the
16:58 controller gets hits by a request and
17:01 that destroy method includes calling the
17:03 handle method on the action which
17:05 contains a reference to the part of the
17:06 application that knows how to handle the
17:08 action. Um in this case it's going to be
17:10 a database.
17:12 It's typical for a strategy to look like
17:14 this. Um the creation of receiver and
17:16 then passing the receiver as a reference
17:18 um on instantiation of the action. But
17:20 in Larbo because of dependency injection
17:24 it might actually look like this.
17:27 Um so let's look again in the context of
17:29 controller it's decoupled from the
17:31 service container which functions as a
17:34 client in this example. Um the destroy
17:41 which shares qualities of the other
17:44 actions including a handle function and
17:45 that references the receiver of the
17:47 action. and the receiver knows how to
17:50 actually get the job done. So in this
17:52 combination of actions on top of all the
17:53 strategies and controllers is very
17:55 powerful and flexible if you think about
17:57 it. But if you're also seeing this and
17:58 you're thinking, well, I've structured
18:00 my code like that before and I didn't
18:01 mean to use a pattern or know the name
18:05 of it. Then welcome in. It is awesome to
18:07 feel like you invented a pattern for
18:08 yourself. It means you're on to
18:10 something and you can use that name to
18:11 talk about it with other people who
18:12 already understand why you're so excited
18:14 about your solution.
18:16 Um, the command pattern is useful when
18:18 you don't know what the action is going
18:19 to be or what the receiver is going to
18:22 be. It encapsulates a request as an
18:23 object which contains an execute
18:25 operation, parameterizes clients with
18:27 requests, and supports undoable
18:29 operations. It's also super good for logging.
18:30 logging.
18:32 And then after a request has occurred,
18:33 most of the time changes will have
18:34 happened in the state of your application.
18:36 application.
18:38 And the observer pattern lets an object
18:40 called the subject update other objects
18:42 when changes happen. Subjects need to
18:43 have a way to know about and notify
18:45 their observers the classes that are
18:47 going to be updated. And eloquent models
18:50 can attach to observers using um a
18:51 static observe method in Laravel and
18:53 observers can be a class property. Uh
18:56 dispatchers help a specific model like
18:58 um team manage their observers when
19:00 state changes and they're identified
19:03 through uh reflection. They need to have
19:05 specifically named functions. Um but
19:07 they can access state temporarily for
19:09 these per this purpose and define their
19:11 own behavior. Um like for example
19:13 logging when a team gets created or
19:16 deleted. Um so as your request behavior
19:18 is ending you have a lot of objects that
19:20 weren't directly affected um which are
19:23 updated to um when it's a state in a
19:24 different object changes. And this
19:26 pattern allows you to store those
19:28 changes in objects called events which
19:31 benefits subsequent storage logging and
19:33 other cool stuff.
19:35 This is really cohesive. What I find so
19:37 beautiful about Laravel is the choice of
19:39 patterns it uses. The expertise
19:40 demonstrated in the way that it solves
19:42 the web's classic problem. How do we
19:45 handle a request? The framework is
19:46 extensible not just because these
19:48 solutions adhere to the terminology of
19:49 patterns, but because the code is
19:50 implemented in ways that have been
19:52 proven to work. And code that is
19:54 reusable and has been proven to work
19:56 tends to acquire names. These
19:58 implementations are not always canonical
20:00 or classical, but they are thoughtfully
20:02 designed in ways that invite us as a
20:04 community to participate, to learn, to
20:06 read, and to contribute.
20:08 Designing object-oriented pro software
20:10 is hard, and designing reusable
20:12 object-oriented software is even harder.
20:15 Projects and processes are we manipulate
20:17 are unique. But experienced developers
20:19 who have solved similar problems have
20:22 found working solutions in the recurring
20:25 patterns of classes and many
20:27 object-oriented systems. These
20:28 commonalities and the solutions to these
20:30 problems allow us to put forth design
20:33 patterns and to name them and it gives
20:35 us the language to discuss solutions
20:36 with other people who know about them
20:38 and express and recognize those
20:42 solutions more quickly. Um, for example,
20:44 there's usually two S's and classes, but
20:46 the variances in each system we design
20:48 means that the details of our
20:50 implementations and their grammar and
20:52 the combinations of our business logic
20:53 should not and often cannot be classical.
20:55 classical.
20:57 They help a designer to get a design
20:59 right faster. They speed up
21:01 communication, reduce complexity,
21:03 encourage documentation and readability.
21:06 Their definitions describe real systems,
21:08 but they're almost never exactly what
21:10 they claim to be.
21:12 My opinion is this. Learn the names or
21:14 don't. The right tool, architecture, and
21:15 implementation is always specific to
21:17 what you're building. Design patterns
21:19 are just one way to talk about design
21:21 that we can agree solves some problems.
21:23 But whatever you're building, I hope
21:24 that you're talking about it because
21:26 ever since I started talking about it
21:28 and liking liking things online and
21:30 posting about it, my life got a lot
21:32 better. So, I'll leave you all with a
21:35 final blessing. Laravel forever. Thank
21:38 you very much. Wow.
21:41 Wow.
21:44 Are you kidding me? That was incredible.
21:46 That was your first big Laracon talk.
21:48 That was incredible. And here is your
21:49 artisan jacket.
21:49 >> Thank you very much.
21:51 >> That was unbelievable. Give another
21:55 round of applause for Mary Perry.
21:57 So, um, couple of questions. The first
21:59 is not a question, it's a statement. We
22:01 had many people that tweeted about your
22:03 puns. So, the puns worked. Everyone
22:04 Everyone loved the puns. So, good job
22:05 there. I guess
22:06 >> to my ears.
22:10 >> Yes. My question for you is um what
22:12 appeals to you about design patterns
22:14 because you've obviously gone super
22:16 deep, right? Deeper than probably most
22:18 of us have gone. Um what is it about
22:20 those that appeal to you and where did
22:22 you look to like study and learn those
22:24 things such that you could identify them
22:25 in Laravel?
22:29 >> I like the idea of naming things and of
22:32 the ways that we use grammar to name
22:35 things. So, I heard Jake Bennett's state
22:37 machine talk when it was uh in Nashville
22:39 in 2023, and I thought it was so
22:42 interesting that we could give a
22:44 30-minute talk that I had to spend a
22:45 couple hours going back and learning
22:48 more about to understand and describe
22:49 everything that was going on to people
22:52 who already understand it in two words,
22:54 just state pattern, you know. So, um I
22:56 started really diving deep into it. I
22:59 read the Gang of Four book. I read, um a
23:02 small talk book, a couple of
23:04 a couple of uh articles online,
23:08 especially um the uh the inversion
23:10 control articles are are better there.
23:12 And I just uh kept going with it obsessively.
23:13 obsessively.
23:15 >> Yeah. Well, it it it worked. That was
23:17 the best deep dive into the Laravel life
23:19 cycle that I've ever seen. So, well
23:20 done. Very proud of you. Y'all give it
23:21 up for Mary Perry.