Welcome to my talk models and service layers hemoglobin and hobgoblins, and I promise by the end of it The title will make sense. My name is Ross Tuck and my job is to keep you awake after lunch So a little bit about myself by way of introduction. I'm an independent engineer Coach Consultant you can find me on Twitter and free node as creatively Ross Tuck Also have a website and blah you get the idea. Okay? So I'm here today to talk to you about a topic that's important for web developers no matter who you are What you do specifically hemoglobin Now if you're not familiar with hemoglobin, it's a substance in your blood And I mean you specifically in the 8th row you have it in your blood If you don't have enough of it or it doesn't work properly You probably have a medical condition known as anemia because hemoglobin's job is to carry iron throughout the body If you don't have enough iron you're kind of pale and sickly looking. It's not a good look But this disease isn't limited to just people and parcel tongues Objects could be anemic to except instead of iron. They're missing behavior or logic. This is what makes strong objects Let me give you an example This is a model like you'd see in any PHP application. You know that right away for two reasons one I labeled it in the top left corner to It's made up entirely of getters and setters You know exactly what the internal structure of this object looks like it's got a name.  All right. It is basically a big data container. There is no behavior here I mean sure in a modern PHP framework Maybe you've got an adder and not just a getter and a setter But for all intents and purposes you could replace this with this and you'd be the same minus a little bit of type checking This is generally regarded to be a bad thing to him But no one will believe you if you say something about objects unless you bring a martin Fowler quote So I picked this one Says in essence the problem with anemic domain models is that they incur all of the cost of a domain model Without yielding any of the benefits in other words You sat down and thought up what all the models in your application were you thought up what their properties were how they're connected to each Other and so on and so forth, but you didn't put actually anything in there to enforce that or actually even use it really in any way Which is kind of a waste this leads to the unfortunate conclusion that our industry standard is an anti pattern Now an important note before you any further.  I am not here with some sort of divine revelation about how to build your code because guess what I'm still figuring it out, too What I want to offer you today instead of advice is A buffet I want to show you a line you can walk down and sample several different ways of building your application And maybe you like some of them. Maybe you don't like any good buffet this is essentially judgment-free you can decide if you like it or you don't and We're also not going to talk about if it's good or bad and we're not going to go really in depth with any one thing You're just going to try a little bit of each one so that at the end of the day You'll know enough to go further on your own and hopefully make it at your own house, okay? I'm also not going to talk too much about the models themselves a lot of what I'm going to discuss is often associated with the main driven design Which is really really awesome, but today I'm going to talk about the stuff around the models instead I'm going to focus on integration over implementation of strong domain models, okay? Now because I'm going to show you several different ways of building something it helps if I have a common setup so that you Can follow its evolution so I'm going to stick with this to-do list thing because it's bonkers simple It has a name it has a status and it has zero or more tasks, okay? And the tasks themselves are even simpler. They have a description and a priority Everybody with me, okay Now I'm going to show you how to build this stuff using an ORM That's totally not doctrine to a promise and a framework. That's absolutely not symphony to Hmm, okay There's some flavor that in here, but you can build anything and everything I show you from scratch in some of it's something else triple Whatever you like, okay? So I'm going to start off with kind of a crud application. That's how we build most php stuff today, right? And we're going to begin in the controller because that's where most of the action is when you do crud So we're going to have this add task action It takes an HTTP request as its first parameter And what we're going to do is create a new task and attach it to an existing to-do list And this is the example we'll use throughout the rest of the presentation Okay, so I'm going to take my time with this code. The first thing we're going to do is we need to create a new task All right, and here I'm just going to get the task. I'm going to set some stuff on it And this is really simple. I know in real life you'd have some Validation or something like that here. You'd probably be using a form library or serializer, but it basically boils down to the same thing It's on the same layer of code Next I'm going to take a to-do repository and I'm going to look for the existing to-do list inside of it So we're going to do a find by ID there if the to-do list doesn't exist We throw an exception a four or four and then we set the to-do list on the task This should be your first hint by the way that something is bass-acquards because Right if the task belongs to the to-do list then why are we putting the to-do list on task? I mean it makes sense when you think about it from a database perspective because this is a parent-child kind of relationship And you know that you need the parent ID on the child row But that's a database concern. It doesn't really belong all the way up here in what's basically UI logic But we'll talk about that later After we set the whole thing up we need to save it. We'll use a repository for that That just flushes it to the database and then we'll have some application specific concerns like updating an audit log Maybe we send a new email and then finally re redirect the user back to the edit page Okay, so I'll let you look at that real quick because we're going to slice a nice a lot Everybody good cool ish Now your first impression is probably correct All right, and this is not just the aesthetics although those are important too I mean I can't even fit the closing bracket on the bottom of the slide for God's sake All right, but there's some real technical concerns here the model is thoroughly anemic which we've already talked about as being kind of You know bad it is hard to maintain this code will only grow in complexity It's only going to get worse as we add more concerns. It is clearly not testable There are way too many collaborators. There's no clear point to the object It's going to be a real pain to write anything but an integration test for and then finally The person who's written it is clearly never heard of the single responsibility principle in their life Okay Now in defensive crud for all the bashing on it. There are some good things here All right crud is a very very low barrier to entry if you can normalize a database you can build a crud application It's that simple It's also easy to follow provided that you can keep the entire domain and all its rules in your head Because there's nothing in the code outside of maybe your form validation that's going to help you get any of this right It's not encoded anywhere in the design and Sometimes all you really want is data entry. I mean it's not as often as we think it is in the industry But sometimes it really really is so I might have some kind of really fancy insurance calculator That's well-designed well-tested But it maybe needs some actuary tables that are updated in a database once a year and for that updating of the tables Why not build a crud application? It's simple. It's easy. It's not important to my business And then finally crud isn't always a developer's fault if you have a bad project manager or a subpar ux person Who just hands you designs that are nothing but overview pages and edit forms you have very little choice But to build a crud application in my experience All right, but I think we can do better And I think one of the ways that we can do better is by adding something called a service layer to its application Now service is like the most overused term in all of it right now I mean we got a service layer service container a web service a service or a new architecture a domain service stateless Service software service platform service whatever service I mean deliver service lunches of We have a lot of services is what I'm saying. So I want to be really clear about what I'm talking about here I'm talking about something called an application service like God another service All right, but this is basically just a service layer and I'm going to use the two interchangeably the reason I like The term application service I picked it up from this book implementing domain-driven design is that it emphasizes the role of this service layer as Being tying different concerns together to create what's essentially the application and we'll talk about that again a bit later The way it works in practice though with an MVC app Is that you just have a model on a controller normally and the service layer kind of butts in there like an unwelcome house guest All right, and you might be thinking okay Ross. Why would we do that? I mean if three layers didn't cut it wise for going to magically be better well If we turn to the good book you'll find a chapter here written by a guy named Randy Stafford who Fowler asked to write about Service layers and in there he highlights two main reasons to build a service layer The first one is that you have multiple user interfaces that consume the same domain logic All right, and that might not have been too common when the book was written I don't know. I wasn't there But I would argue that for us today This is practically the norm like how many of you here have a website and a rest API that let you do some of the same things Or you have a website and a cron job or a command line admin interface That's consuming the same logic or a queue worker from gear man or beanstalk These are all different interfaces consuming the same domain logic He also hints at the idea that it's good for in between logic or stuff That doesn't really fit in the controller or in the model like Database transactions you don't want to duplicate those in every single controller They don't belong there, but they don't really fit in the model either. That's the persistence concern So an application service can be a good place to put that stuff And then finally there's another reason you might hear bandied about on Twitter or conference hallways these days Which is that application services help you decouple your domain model from the underlying framework Because clearly frameworks are the source of all evil in PHP All right, but for all intents and purposes This is kind of true like me personally when I'm building an application I tend to base the controller and the view entirely on Whatever framework I'm using because it's easy. It's the most productive. It's also the least important part of my code The service layer itself has sometimes has components or libraries from this framework or from another lighting Romantic anyways So we have that stuff in here and it uses a couple components Event dispatchers or validation libraries something like that And then finally the model itself is decoupled from the rest of this mess Usually maybe except for a couple value object libraries or a couple validators something like that All right, so it's kind of a standalone piece Now it's a whole lot of jibber-jabber. Let's talk about actually building a simple service layer. All right So an easy way to go about doing this is as a quick rule of thumb Just think about what code would I want to reuse if I had multiple user interfaces? I would say in the case of our giant controller here It's probably the stuff about you know setting it up and then the associated objects with it So what I'm going to do is basically an extract class refactoring and I'm going to pull this out I'm going to put it in a new class called to do service and it's going to have a method called add task And I'm going to require all the different pieces here as formal parameters All right, by the way incidentally to do service is a really crappy name for service Please name these actually after something that's maybe related to your domain like reminders or journal or something like that But I'm lazy. Anyways, so we're going to have this in here So there's no way that you can invoke this method incorrectly because it requires everything explicitly All right, and then we'll just dump that code in here. Ta-da simple little service layer Now you'll notice that we also took a fair number of the collaborators along with us like the repository the autologues stuff like that I would usually inject these here through the constructor with whatever DI layer you're using You know if you've got a factory class that builds your application same thing All right So we've got that in there now one of the things I would normally do as well here is if you've got different Collaborators that you're using in the service layer. I would begin encapsulating all access to any of those Okay, and this might seem like a little bit overdone or a bit over engineered But it has some serious benefits because you know what's accessing what now All right, so if we cut back to our controller having done this refactoring You'll find that it's already a lot more high level and it reads better now I'm finding to do this by ID. I throw a four four if it's not there I add a task to it and I redirect the user. This is a lot simpler This is easy to follow right and if we add an extra concern like some extra piece of logging or whatever Then it's not going to mess the controller up So this also begins to enable other things like if we wanted to build a super hipster command line task management Application then that's pretty much peanuts now, right? We just dump it in there because the important code is all inside this service class All right Now this is also in very very simple applications a decent point to begin going ahead and drying up the rest of the code In terms of don't repeat yourself So stuff like this not found exception if we want that thrown everywhere You could conceivably go ahead and begin putting that inside the service layer So you could do something like a fine by ID dump the exception in there, and you didn't have to modify the entire application Now keep in mind once you start doing this that no trace of your user interface layer should exist inside the service layer All right, so we're not using an HTTP exception here anymore. We're using a specific named exception Okay Now if we turn back to the same UI code again here, it's once again a little bit simpler We try and find something by ID we add a task to it and we redirect user. That's a step forward Okay, now you might be asking what a why don't we go ahead and move this fine by ID stuff into the add task method as well Well, that's true. You could but you begin to sort of close off some doors at this point For example if on the command line interface. I wanted to refer to it by name rather than ID You know, I still have to pass it in there instead So you want your user interface your service layer to be close to your use cases, but not too close Now that joke makes sense. Oops Okay So we have that stuff here. All right now. That's not the only way to go about doing it though. For example We could Instead of passing around the object itself that we want to modify We could also pass around the ID instead and this is just as good We could say find ID by name and then we pass that into the service layer as well Usually you would do this as some sort of value object So you get really strict type checking and this is a great maneuver as well if you want some extra isolation So it depends a little bit on what you want to do, but whether you use objects or whether you use IDs just be consistent in what your service layer accepts pick one pick the other but not both. Okay Now this is going to feel really really crazy because you're like why am I just taking this stuff and then wrapping it With one line functions again. What's what's the benefit of this? And the easiest benefit that I can show you without getting into anything deeper, which we're going to Is that it makes it really simple to add extra behavior without having to modify several collars So I could add a cache to this method without having to go hunt and peck or everywhere in the application Now that's a lot of technical advantages. Let's talk about some indirect ones as well I think that this has had a great effect on the readability of the code every class feels more high level They're easier to isolate. They're easier to test There's also a certain level of junior protection here You've got this great big interface running down to the middle of the application And that means that you could divide your team a little bit easier a little bit better You could also for example, you know change something on one side without having it break something on the other side Hopefully, at least you're having the beginnings of that here It's also got a great element of discoverability if I'm looking at a Cred application for the first time, and I'm just looking at your database tables. Basically. I don't really know what your application does I don't know what it allows you to do whereas if I look at the method signatures on your service. I have a pretty good idea So at this point you might be thinking hey mission accomplished. We're basically done. We've built a simple service layer There's just one little detail. We need to wrap up. But our model is still what's the technical term? Dumb as a box of rocks We've done absolutely nothing to help our model, which is what we started with this kind of a premise here So I hate to go return of the king on you, but that's a fake ending We're not even a third of the way through yet okay, so This leads the question Where is my logic every application has some level of business logic, and if it's not in the model then where is it? Well, what happens usually in PHP is you start using service classes, and that begins to leech the logic out of the model All right, so I would argue that this stuff right here is an important chunk of business logic It doesn't look like it because it's composed of just setters But it's really an implicit way of saying some really important things like what is the relationship between a task and a to-do list? What are the required things that I have to give in order to create a task? You know it has to be a description and priority that's important stuff here, but you can't see it because it's in the form of setters All right, so if we turn once again back to the good book you'll find a description of what it is We've written it says Organizes business logic by procedures where each procedure handles a single request from the presentation That's close to what we've done except it's not talking about a domain model It's talking about something called transaction scripts, which are kind of a halfway point like on one end of a scale You've got crud on the other end you've got domain model and transaction scripts are this nice little place in the middle All right, and that's not a bad place to be actually. I mean transaction scripts are very simple I mean you've seen how we can implement one in just a couple minutes And they're definitely more flexible than a crud application at least The problem with the transaction script is that they don't scale quite as well And I don't mean performance scaling, which I'm actually not that interested in I'm talking about Complexity scaling like as our application gets harder and more complicated and adds more features It will get messier and it will have more concerns to deal with So if that's the kind of stuff that we're worried about being in a model what belongs in the service layer then Well, if it's not this stuff, then I would argue it's this stuff This is the kind of thing that you might want to put in a service layer, okay? Ultimately a service layer is meant to be about orchestration. This is the key word here It is not meant to do anything on its own It is meant to tie together a bunch of different concerns that are stand alone But tie them together into an application and that's why I like the term application service personally All right, so things like database transactions security maybe Notifications or logging perhaps even bulk operations if you want to get fancy These are things you could conceivably put inside of a inside of a service layer the key pattern here is facade We are not adding behavior to any of these models. We're just tying them together All right, so you've often heard the term fat model skinny controller think fat model skinny service layer as well All right, so with that stuff in line Let's do some rethinking about what it is we've built if we look at our service here You can kind of break the stuff down into two categories We have write methods which change something like add tasks and we have read methods like fine by ID fine by latest list And the reads outnumber the rights, so let's give them attention first So we're going to remodel our reading by refactoring our repository again Okay So if we look back at our service layer here, this is this is pretty simple code It's easy to follow, but this stuff right here is basically adding behavior All right, we want to try and make our service layers thin as possible and this doesn't really belong here So we need to get it out. I mean the question is where should it go? We're clearly using some sort of like repository or database layer here Which doesn't throw exceptions when something is not found so how are we going to shoehorn that behavior in I mean It's not like we can just go in and you know create objects that work how we think they should oh wait we can So let's try that for a change. All right, so let's create an interface to do repository These are the methods that are important on it. These are the ones we're going to use All right, so we'll start off with that and we're just going to go ahead and create a to-do database repository that implements that interface Okay, and then we're going to have a fine by D and we'll basically plot the exact same code in there It's again a simple extract extract class refactoring. All right, and this feels better. It's much more consistent here It's only in one place. It's only in one way Now you might be thinking that's cool Ross, but I'm not made a time or money I don't have time to run around with a raw database connection and do all this object mapping myself That does not interest me. I'm busy doing it with doctrine or propel or whatever it is You know that you want and that doesn't throw exception. So how can I make that happen? Well, you want to know how to fix that? fixed All right, all we did was instead of using their repository directly We wrapped it in our repository and I know you're thinking like repository section. That's crazy But honestly, it's a matter of not which object it is. It's a matter of interfaces you know, that's what we really care about and This is the interface that we care about the to-do repository is the important interface in the circumstance All right, this is doctrines repository interface and it is a very very good interface for doctrine I like doctrine a lot that is not a knock on it But between this interface and this interface. This is the one I want to support This is the one I deal with and this is the one I care about. So that's what you should be using All right, so if we cut back to the to-do service having made these changes but it being but a boom much simpler Now finally this list is a little bit more complicated because you could make an argument that this stuff right here is orchestration we are orchestrating how a cache and a repository behave in unison But at the same time it kind of doesn't make sense though because the service classes meant to tie things together And this is still kind of adding behavior, which is not what we want Just think about it from a unit test point of view again here. We would be testing two different things All right, so boom let's extract that code. Let's bring it to the repository much cleaner much simpler You could also go a step further here though because we're using a single interface for this stuff And that's separate from a concrete implementation. I could do something like this I could create a caching to-do repository, which is basically a decorator object It takes an actual an actual inner repository, which could be the database one a mock one Whatever you want and just encapsulate that okay, and That seems like a lot of objects. So how would we tie this together? Well do it in your data on your di layer So you might start off with like a doctor and repository you put your own wrapper around that to get the interface You want and then you have a caching thing on top of that Which you can turn on or off if you so choose and then you encapsulate the whole thing with a service All right, and I know that sounds crazy. All right It looks totally over engineered But if you go out and for me and you go home and try it I guarantee you'll notice a couple things one Unit testing gets a lot lot easier to you have a lot more Composability in turning like features on and off and three you'll never want to go back to the old way promise If you ever have doubts about this just remember the inverse biggie wall Which is commonly stated as mo classes mo decoupling and reduced overall design issues Admittedly not as catchy, but Okay, now in particular finder methods do proliferate at a crazy rate Especially if your database objects are too big so you may have a design issue you want to go in and shrink those back down again But a different way of doing it would be to consider something like a criteria pattern So instead of like individual search methods you have one that takes multiple parameters to kind of describe the search You want to do that's the common advice anyways, but it turns out that building your criteria Pattern thing here from scratch is surprisingly difficult So you might want to use something like doctor and criteria in order to give you a head start, but it's not that bad Now we still need to do something about improving their writing in our application But let's take a brief interlude here and talk about what probably seems like an extreme proliferation of classes in our application at This point because it's it's really going all over the place, right? Especially we're only focusing on one object right now the to-do list, but that's already got a service It's got a repository and as we continue to add stuff like a task with that'll probably need a service It will need a repository as well You'll need tags and then you just melt some cheese on top of this sucker and you've got a big steam and pile lasagna code Okay, which if you've never worked with a lasagna code. It is the worst type of code All right, it is the opposite of spaghetti code Where you basically have so many layers that are stacked up on top of each other that if you want to modify anything You have to cut through all of them at the same time true story I once worked on a on an Application where if you wanted to add a new field from the database level all the way up to the user interface Then you had to modify the code in seven different places It was the worst Okay So don't ever build this please instead try and reason about what you're doing Don't just follow some template because some guy at a conference told you what to do One way you could approach this differently is to be more intelligent about how you design your models Something that DDD guys do a lot is create aggregates, which is basically where you have an aggregate route that's the to-do list in this case and It basically manages the life cycle of models that only makes sense when used by it So you might have a single to-do service here with lots of collaborators like a repository and auto log whatever But you're talking about a group of models rather than an individual one and this can cut down on what seems like a crazy number classes Now over time you might be tempted to keep making these bigger and bigger like you say well All to-do lists are actually done by a user. So this all belongs under the user service technically But that's probably too big. All right. You want to keep it a bit smaller So keep take the user service one way the to-do service another there and if they have to communicate with each other That's okay. You can have references between them or something like that But don't just like tie them together because they're that way in the database I mean the user could be split off in the future to a An external rest API or something and then you're kind of what's the technical term screwed Okay, so if you're gonna do this and you're gonna let them communicate between each other You know it goes really really well here Interfaces interfaces go great with everything. Don't just pass the raw user pass in a value object pass in an ID pass in some kind of Alternate implementation of a user something more specific to the to-do list whatever you want. All right, but interfaces are your friend Remember the services aren't only for entities They're basically facades and facades are meant to simplify any interface So the scale can differ anywhere from like it's one class to ten classes to twenty classes to whatever all right Just remember the quality of implementation matters if you have a really crappy service layer that nobody likes working with I guarantee you your colleagues will find you in a back alley one night and stab you with a shiv made from the plastic of your own keyboard Don't be that guy So with that in mind, let's talk about remodeling the writing in our application Well, we last left that stuff We were here on the add task method and we were talking about how this stuff right here is the business logic in our application Okay, so we're gonna bring that stuff to the model where it rightfully belongs All right, and that can be pretty straightforward again We're just gonna have a method add task We pass these things into it and it's set up now and the important thing is that we both set up the task And we do the binding to the to-do list here. Okay Now it is still possible to build this thing incorrectly inside the model So the task should still enforce its own integrity So we could require it with the instructor that way you can't instantiate it unless you have the required stuff Now that's great in theory, but there is a catch here Many of your ORMs still need a reference on the child object the task that refers to the parent because they can't Magically figure out that one is you know the child of the other they need the ID the reference etc etc So if you have to do this then you can pass it into the constructor you can hide it in some way That's okay. It's a lesser sin But if you do do this do not compound your mistake by putting a getter in a setter for the to-do list on the task All right because that way lies madness. All right, so we're just pretending. It's not there Now once we turn back to the service having done this again, it reads a little bit shorter It's a little bit more compact and it feels more like this is about orchestration, right? We're now tying together a bunch of different concerns the domain model is one of them But we're also tying together these other things and again that emphasizes the idea that this class is what brings stuff together to make an application Okay So this also paves the way once we have these things in place to begin adding real business logic to your models and by real business logic I mean the type of BS examples You only see in talks like this like if I have more than 10 tasks will change the status to unrealistic who has these problems in real life I don't know but we'll pretend that this is a valid one a Good hint that you're on the right track though is when you can write Meaningful tests for your models if you can write your unit test that actually covers something inside your models It means there's logic in there. So you're on the right track, okay? But you won't be doing this long before you notice that you have some problems making everything work together I mean the model is the boss the model should be in charge, but the model also has a very limited scope So right now we're fixing that by for example mentioning every single concern here inside the to-do list service class So we just have another list if we wanted to add some extra piece of logging or whatever It would have to be injected here and put at the bottom of the class as well So that's only going to grow over time. It's going to add more collaborators more complexity someone and so forth Also, what happens when we have conditional logic inside of our models? Like how are we going to send an email every time we get over 10 tasks for example? Are we going to like duplicate that check here inside this thing? That's silly That's the opposite of everything we've been trying to do and then finally what happens if you have to communicate like over a Network like send these things automatically to a printer or whatever That's that's like a sink that could be really really hard to do and the service shouldn't be necessarily caring about that So we need something new Something better something event here Yes, domain events that would work now if you're not familiar with the main events They're really really common pattern that you've probably seen in jQuery. You know that thing that runs in browsers it's an observer and We're just going to use it in a fashion you might not have seen before All right So I'm going to throw a couple new lines of code here on the screen at once don't flip out or anything. All right. Here we go We're gonna have a this raise method and then we're going to toss in a new task added event And that's going to take whatever the important things were that just changed Okay, so let's talk about the event first because that's the easiest thing here. It's really just a message Okay, we're going to pass these things in here through the constructor and then we're going to probably put some getters on here So you can read it, but it is basically a simple immutable little message object It is no real logic of its own and that might seem kind of hip-hop hip-hop Hippocritical is the word I'm looking for it might seem kind of hypocritical because I've been Ranting about an EME the whole time, but think about this more like a data structure than an actual object. Okay So we're going to set up this task added event Now that's pretty straightforward. But what about this raise method? What is that thing in my barber? Well, we take the to-do list here. We're going to add a few more lines of code bear with me We're going to have a pending events array All right starts off empty and the raise method just the pins an event to that array and Then finally we have an extra method here release events sometimes called DQ or collect All right, and it just returns a copy of whatever events are in there and then resets it So it kind of like unloads all the pending events and it returns this stuff All right. Now the only thing. Oh good point here This is an excellent use case for a trait. It's not enough code for a base class certainly doesn't justify it But it's just enough. You don't want to duplicate it everywhere. So trait would be a good move here Now the only thing we're missing at this point is a dispatcher because we're not going to bind every single listener to every single model That'd be hugely inefficient and total waste All right, so we're going to take a dispatcher here now We would probably do that inside the service layer So we would kick out all these individual concerns like the auto log the mail or and stuff like that And we would just replace that stuff with dispatching these events and then things like sending the email For example could be relegated out of the service and into an email listener object where it just waits for whatever the proper event Is and then triggers the same stuff All right, and this is really really loosely coupled at this point It might seem like a lot of boilerplate But at the same time you can reuse these listener classes for all sorts of things They often have a common set of dependencies and the listener classes themselves are meant to be thin They're kind of like controllers in their own rights. So they're just referring the work off to something else that's actually doing it Okay, so this works out really really well then And now we can also begin to dispatch multiple events if we want for example You can send zero events with the method you can send lots of events with the method and it's easy to tie this stuff together Just add events when you need them So there are a couple nice things about domain events as a whole we get to keep the logic here in the model where it belongs which has been a central theme It prevents a big ball of mud from appearing within our service So as we get more collaborators and more little bits of logic that accumulate there over time we've now reduced that to kind of a fixed amount of functionality and Individually the pieces are all thin and easy to test if I'm writing unit tests for the model I check that it raises the events if I'm Testing the service layer then I'm checking that the events get the flow from one thing to another And then if I'm testing the listeners here I'm testing that they pass them off to the appropriate collaborators every piece here is really really small and It's also a great way to communicate over a network because you can simply serialize these little immutable data structures Pump them off over a network for whatever piece of communication and then have things happen out of process That's one of the reasons why we only pass scalars or simple value objects here instead because you can't change those You don't let events change in the past unless you have a time machine There's some less nice things about domain events though and they basically all boil down to exactly the same thing Humans hate debugging events, especially if it's an event on an event on an event on an event in practice That doesn't happen nearly as often as you fear, but if you are going to use domain events It's worth spending a few hours to build into development logging Maybe some debug commands you can see whatever listeners are just kind of hanging there waiting for stuff to happen That gives you a much better overview the system as a whole Okay, so we've been talking an awful lot about how to get the model in the service layer communication Right, but that's only half of the integration story here We also need to talk about how to consume the stuff from our controller and view all right So let's talk about that Now the big danger that we have at this point here is that we are allowing full-fledged access to the model in all the Controllers we are just returning the entire model and letting you do whatever you want with it And in most cases that's going to go correctly We're going to pass it back into the task into the task service and you know add the task But if you have a new developer who's just coming to the project for example, and they only follow their autocomplete They're like oh well This is like a database map where I get the thing back and oh wait There's an add task method here, and I just invoke that directly and oh I want to rename something to and oh wait I need to pass it in to say it and there's like more ways to get this wrong than there are to get it Right, and that's a sign of a bad API So let's try and think about this in a different fashion All right, because right now what we have is essentially some implicit Communication or maybe even coupling between the model and the controller if you change one It's possible to maybe break the other the service layer is not being a good layer here It is basically letting the model run around and poke its nose into different places in the application where it doesn't belong All right, it's like a bad puppy. So You should instead do as a wise man once said and keep them separated So One of the ways we can do that is beginning to isolate these things from each other So we can bring something into play called a view model if you're into in VVM stuff That's different than what I'm talking about here. Don't worry about it All right, so it's a really really simple pattern All we do is instead of passing back the to-do list in the find by ID method We're going to wrap that in some other little simple object, and I'm calling it a to-do DTO here Which is short for data transfer object, right? It's just transferring data It's again more like a message or a little thing like that Okay, and it's only going to give you a subset of the functionality here, and it could be a decorator It could be copying state. It could be built by crown job doesn't matter Okay, it's a totally different thing and it's usually pretty much a logic list It might have a few helper methods, but that's kind of where it stops Okay Now another way of thinking about view models is also to bring structure to things that you often have implicitly like who here has ever Had to build a crazy report out of some 14 line SQL query with a thousand joins in there, right? It happens all the stinking time and you usually pass that back as some sort of data array That's totally untyped and you format it in one particular template that nobody can read or understand anymore So a better way of doing that might be to actually put some form put some structure in that thing You know so create an annual goal report object that expects something in a particular format put your helper methods in there Right unit tests for it right if you can do that kind of thing right here for a Shapeless blob of data you can do the same thing for your models. It's a really really powerful concept But at the end of the day it ain't rocket science, okay? So what I think is more interesting is if we reverse it and we use DTO is not for output But for input instead Which leads to us going commando by which I'm clearly referring to the 1980s Arnold Schwarzenegger classic All right case anybody's wondering Now this is almost the same thing, but in the opposite direction We're going to create a simple little message object, which is called a command and I'm super lazy in this scenario I'm just using public properties. You might want a static factory or some getters and setters and real life But as I said, I'm really lazy Okay, so I have this little command object and I'm going to fill it in in the controller All right, so I'm just binding all that data from the request directly to it And at first glance this might seem like more lines of code than you we had in previous examples But it's simpler code and if you were using a serializer or using a form library. This would be peanuts, right? So we're going to fill that command object in and then we're going to dump it into the to-do service But not into an add task method. We're going to dump it into an execute method instead, okay? Now the way this whole thing works as a flow is that the controller fills this message in It dumps it in the service and the service acts kind of like a router All right, there's one handler object out there for every command just one handler Okay, but there's a whole list of them and the service's job is to act like a matchmaker and find this command soulmate You know the one handler it was meant to be with right, so it pipes it on through to there All right now. How does it do that? Well, we replace the add task method with the execute as I said But it needs an actual strategy for doing that to be honest with you. I don't care I mean you could do it get class on the command and map it in an array You could have command get name and then have that be the name of the handler You could have the command execute itself foul relax this as long as there's no dependencies You know that you actually need extra which there always are but anyways, this is this is you know Whatever strategy works best for you in your framework. I don't care All right, so what goes in a handler then well? It's basically everything that's left over which in this case turns out to be not much We just look it up in the repository We add the task and maybe we dispatch the domain events But that's pretty much it and this might seem like again like a lot of oral plate But the entire service now is completely reusable completely composable and this stuff can again have some more dependencies So you could use the same handler for multiple operations multiple actions easy peasy All right So the once you start doing this for a while you realize that well this works for the to-do list service But we could actually extend this further I could have instead of like a different command dispatching thing for every single service I could have one generic command bus for all right operations in my class in my entire application I mean you still probably want services or something like that for doing the reads But the command bus can handle all the rights and you just need one really because it's all routing under the hood now There's a really really smart guy named Benjamin Everly who wrote a couple years ago that if you have a service layer He likes having this kind of command dispatcher interface and the reason for that is that it's really really simple Because the interface is just one method So you can easily extract that into an interface and then write your own implementations of it You could have a whatever works for your application here, but you could also create something that lazy loads from your di layer directly You could add validation behavior here as a decorator again So like if the command is not valid in some way then you throw an exception Otherwise you pass it on down the chain and so if I want you know like specifically symphony Validation on my command I can just drop some annotations on here and I'm done The possibilities are practically endless you can do anything and everything you want with it All right because it's a very very simple interface some other possibilities I've seen in your life logging log every single command that comes through Database transactions are a good fit If you've got a unit of work so you can inspect the identity map on something You can do the domain dispatching of the domain event dispatching like capture all the changed entities and send their domain of it Send their events out All right, so lots and lots and lots of possibilities here. So commands in general Fewer dependencies per class More layers, but simple layers and very very easy to test. We're really cutting this stuff down to its core No, and this isn't this is not an either or scenario though. I can use view models and commands at the same time In fact, that will give us complete isolation here So every time I want to make a right I would shoot a command into the service layer and every time I want to make a read then I would get a view model back And this is really cool and one of the things I like the most about this approach for PHPers especially is that it gives us crud for the framework but domain model for the chewy Center and That's because frankly there's a dirty secret that a lot of people won't tell you about when you start doing ddd stuff like this Which is that your average PHP framework really really likes you to have gettersetter based models I mean things like forms templates validators They all love gettersetter based models because they can do met a very easy metaprogramming and figure out how to operate with that On the other hand, we've got the service layer in place. I can use the domain model for things like tough logic capturing semantics testing That's a better fit so I can get more of the best of both worlds approach okay So if you're using commands and view models here at the same time Over time you begin to might maybe possibly notice that they'll start to diverge You'll see that maybe your commands are sending in fewer properties than your view models are reading or that they don't really begin to resemble each other Very much that can be a natural flow of your application or it could be a sign that perhaps the modeling is actually different for Commands and for view models which leads us to the last section of our talk a really hot buzzword right now CQRS Now CQRS is kind of hard to show you because on the surface it looks the same This is the exact same controller. I showed you in the last example What's different here is the concept of CQS or command query separation This was a discovered invented whatever you prefer by a guy called Bertrand Meyer Very famous. Oh appear and he theorized that all operations any method you call can be classified as one of two things It is either a command which changes data, but returns nothing new or query Which reads data, but changes nothing in the process of doing so and don't confuse the terms command inquiry with like the command pattern We saw in the last section or query like a database query. He means any method call whatsoever All right, he says that these are two different things if you like rest then think about it like the difference between a get in the post okay Now a few years later and by that I mean a lot of years later back in 2009 or 2010 a guy named Greg young came up with this idea of CQRS or command query Responsibility separation and his insight was that if you look at your average model Then you can see that many of the methods here already break down along the same line So we have a rename and add task and those are commands and the stuff on the bottom are naturally queries But what if these are actually two different responsibilities as in terms of single responsibility principle? Well, then you would have two models one that covers the reads and one that covers the rights All right, so you might actually split it into two different objects like this Where the top one is making the changes and throwing domain events for that stuff and the bottom one There could be multiple read models is receiving those domain events and updating itself in order to generate like new visualizations on the fly Okay, so if you're having a hard time picturing this think about My to-do list application where the marketing guys come in and they say hey We would really like to have this feature where for every to-do list I can easily see all of the users who were ever involved with this to-do list in any way shape or form You'd be like holy crap That's that's actually kind of hard to figure out and it's kind of performance intensive And you know we sort of did a lot of work and separating the two things out So just slapping a get participating users method on here. It's kind of screw-in-the-pooch So CQS gives us an alternative to that what we could do is create a to-do list model on top where we just you know Make the changes themselves. We add the tasks, but the stuff on the bottom that could be generated from a cron job We could be doing it over an API. We could be you know building these things asynchronous. It doesn't matter Right we can build that view in any way we prefer it could be a combination of data-based stuff and remote API stuff doesn't matter All right in practice This often means that you have like an ORM and C for the stuff on top because the right model is the one with all the Logic and this one on the bottom is maybe an SQL query or some combination of data Okay The important concept here is that read and write are two different systems Like a user in a shopping cart they have a relationship with each other one uses the other probably But you want to bring that same kind of split into play here What does this do to the surrounding classes? Well a lot of it looks the same actually Command pattern is often used here already with CQS like many people think that they're part of the same thing So you would often have a handler like this You would often have a service for doing reads like this and they would be side-by-side identical To the previous examples the difference here is that the repository on the top and the repository on the bottom Are two different repositories the one on top does the right models and it usually has only very simple finder functions Usually just a find by ID and the one on the bottom is you know got more complex query stuff Okay, and they return two different models one returns a right model one returns a read model and This has some surprising effects throughout your application Consider this code we do this all the time we create a new to-do list We save it and then we get the database ID back from it so we can redirect the user to a URL with that ID in it Right pretty standard This will not work if you take CQRS seriously Why because the actual writing of a new to-do list is a command and commands can't return state All right, even an auto-generated ID that you're setting on a model you passed in here is extra stated Is maybe side-loading return value, but it is basically doing that Okay, so you cannot do this instead what you most often see is people using UU IDs because these are unique They're generated by the client the rest of the stuff can pass it in and it still knows what the ID is at the end of the day I would redirect the user back to you know a URL with the UU ID in it instead So there are a lot of different possibilities or ways to work around this But the the work of generating that ID is now in a different place This is really a low level so maybe you can get a better picture of it here if I zoom out This is a diagram I straight up stole from Martin Fowler's website because if I was trying to do it again I would just be duplicating it so straight up stole it All right, what he says here is that in general you have a command model What I call a right model here on the bottom and a user comes along and makes a change in the UI All right, and that goes in right here, which is basically our command bus that gets piped into a handler That makes some changes on the model and then that stuff gets saved to the database Sometime later the same user or different user comes along and makes a read and that goes through the query model or the read model All right, and that comes back out and gets displayed in the UI Now Fowler says that in this case the query model and the command model are Communicating with each other through the database like they have an agreement or a contract about what those tables in the database look like But they are still two different systems one of the cool things about CQRS and one of the things that might make this split a little bit easier to visualize is The fact that we could actually use two different databases here We could use like my school here for the integrity for financial transactions And we could use redis here in order to do it and deliver that in the most high-speed way possible Or we could do it the other way around or we could have like one right database There's always one consistent right database, but we could have in any number of read databases All right, however you want to do that Now how does that stuff replicate between there because there is no magical redis to my school adapter that I found yet Well, the most common way is domain events, you know the right model fires them to read model listens to them and updates its own projection But that's not the only way I mean you could use DB views like we had in the first example You could use a big honking queue. I don't care But domain events are the number one way that people use If you'd like to try and put this into action the Benjamin Everly guy mentioned earlier total man crush He wrote a CQRS library or rather reported it from C sharp and you can take a look at that That was kind of the original one in PHP The guys over at candidate labs here in the Netherlands wrote a new one recently more for event sourcing maybe called Broadway It is really good, and I'm still reading it, but I like to look at this a lot And then finally Greg Young the guy who coined the term CQRS in the first place has a Couple hundred lines example that he feels illustrates the principles of the whole thing It's written in C sharp, but we're all big grown-ups here. We can we can handle that. Okay? Now what are the pros and cons of CQRS because there are serious ones Let's let's talk about the crop of cons here first. It is a big mental leap It is a very different style of modeling than what we're used to and if your team is not ready for that That that could cause some problems. It may not be the best thing to roll out It is usually like pretty much always going to be more lines of code Arguably simpler code, but more lines more pieces and in my opinion. It is not necessarily for every domain Udi Dahan who is a really well-respected O up here You know that because the sidebar on his website has like 40 recommendations about how awesome he is He says that unless your domain has an inherent race condition. You probably don't need CQRS That's his take on it at least But often what you see in applications that do use it is that it's mixed like one high-speed section of the application Is using CQRS and another one is using crud to just fill in database stuff, right? So it's not an all-or-nothing approach Now what are the pros of using CQRS? Well, it is easy to scale and this time I do mean it in the performance sense like because you would now have eventually eventual consistency in your application you can control the speed at which changes replicate users It's very powerful. It's a great way if you're under a lot of pressure a lot of speed, right? It also bears complexity well And I mean that if you have a very complicated domain model This can be a useful way to model it or to picture it It allows you to separate these things into smaller chunks and it makes certain allowances that were traditionally very hard It has great support for doing async which is more and more important all the time And it is probably the single best pattern we have for implementing event sourcing right now Event sourcing you might not have heard of it's still kind of making the rounds It It's kind outside the scope of this talk But I'll talk about it briefly because it goes really really well with CQRS like many people think they're often the same thing The fundamental idea here is that instead of storing the current state in the database like name is equal to Ross ages equal to 29 Had is equal to Fedora Instead I would store the domain events that were triggered leading up to the current state So I would have like Ross was born Ross Went to school Ross got his first hat Ross, you know And then if I wanted to know what the current state of things are I would take all those events out of the database and I would replay them on top of the model one after the other And you might think that's really really slow But in practice it's not and by doing this you actually enable a whole lot of really powerful amazing stuff Like if your performance obsessed you can kind of offset all the differences here by using it to generate snapshots like every 10 events You know do something, you know record a quick load version. It's not often necessary and kind of controversial But you can do it it is amazing for debugging. All right, how did the client screw it up this time? Let me look in the database and see everything you did that led up to it Audit logs if you've ever built an application with a real audit log, you know how hard that is and here It's basically something you get for free It is a goldmine for business intelligence All right, you can see and follow user flows whenever any time in the past or or maybe project them in the future I don't know I have a theory personally You might be able to use this cap style to overcome network partitions because you can bundle the domain events up on one side And then send them over at a later date I've seen some people talk about using this to build self healing patches where you Change like a calculation object and you replay the events that occurred previously and you get a new outcome Which is the correct one? All right, that's kind of bonkers, but think about it afterwards. It'll make sense Or you could Google it or he can ask me in the hallway, and I'll point you to some really smart people who know a lot about it Okay, so that's all the time. I have for you today I just want to leave you with this quote from Emerson. He says a foolish consistency is the hobgoblin of little minds That might sound like Emerson's trying to insult your eye I mean, I assure you that's absolutely not the case what Emerson was trying to say is that you should believe Whatever the best thing to believe is today and tomorrow if new facts come to light or new discovery is made You should switch over and believe whatever that points to instead and you shouldn't feel bad about changing your mind Because you are believing whatever the best thing is day-to-day. I mean in IT. We often call this strong opinions weekly held But maybe a better way to put it is strong techniques weekly held When we're using PHP 3 it was a lot of a procedural and imperative code and it wasn't pretty but it got the job done in PHP 4 to 5 we were began doing simple. Oh, I mean lots of inheritance and again not all of it good, but better and PHP 5.3 and up we're living in the air of composer man. I mean it's it's all about tying stuff together and making it work and Pretty soon we'll be in PHP 7 and I don't know what that means yet But I think it's going to be pretty cool Some of what I'm talking about today might seem crazy But try it in a little dose is not the whole thing at once if you want the most bang for your buck and you're building credit applications Try building a little transaction script thing. I think you'll like what it does if you want to go a step further Roll out your first domain events. I really think you'll like what that what that does to your code All I can do is assure you that the end of the day people are doing this it is working for them And it can work for you too. Thank you very much I have no idea what time it is, but the middle link here Sean McCool's blog is a great place to get more info Thank you very much to these people. Thanks to these people and I'd appreciate your feedback. Thank you very much


Iranian Supreme Leader Ayatollah Ali Khamenei has received his false dose of a home-grown COVID-19 vaccine. Amid an effort by the country to speed up its vaccination rollout, TV showed Khamenei receiving what it said was the Khorvi-Ran-Barakat vaccine developed by a state-affiliated conglomerate and approved for public use earlier this month. Iraq, with a population of 83 million, has recorded 83,588 deaths from coronavirus, the highest toll in the middle list. The government of outgoing President Hassan Rouhani has blamed a so-far-slow vaccination drive on U.S. sanctions, hampering efforts to buy foreign vaccines and on delays in deliveries.


The Ministry of Health, Wellness and Elderly Affairs alerts the public on the new variant of concern, Omicron. The public health team is working closely with the regional public health agencies in obtaining updated, timely information to continue guiding on the necessary measures in country. At this point, countries are advised to continue strengthening their national protocols that are already in place. Senushah has diagnosed a total of 12,975 cases in country, with 109 active cases. The daily infection rate for the last seven days is 500,000 population per day, with a transmission rate of 0.8. We have noted a total of 280 COVID-19 deaths, and we have 20 positive cases admitted at the respiratory hospital, with seven severely ill persons. On November 26, 2021, the World Health Organization designated B11529, a variant of concern named Omicron, based on the mutations that may impact its behavior. This variant was first reported to WHO from South Africa on November 24, 2021, and to date has been confirmed in the United Kingdom, Canada, Australia, Italy, Germany, Great Britain, Israel, Hong Kong, Belgium and the Netherlands. Based on the wide distribution of this new variant at this early stage, travel restrictions from countries with confirmed cases would be less effective. To date, there is still limited information on Omicron. It is not clear whether it is more transmissible as compared to other variants. The severity of disease has not been confirmed compared to infections from other variants. There is no information to suggest that the symptoms are different or more severe. Preliminary evidence suggests that there may be increased reinfection risk with Omicron. Based on the information on variants, we know that they can cause severe disease, or in particular to the most vulnerable. Our first line of defense must be prevention, followed by control and reduced transmission measures. The effectiveness of the available vaccines has been reviewed, but it is noted that the current vaccines remain effective against severe disease and death. Omicron is accurately detected using the PCR method, but it is still not known whether it can be detected by rapid antigen tests. The effectiveness of the current treatment regimen is also still being assessed. On a national level, we have recently managed our fourth wave, and we are going into the month of December, which is the month of highest risk for transmission of COVID-19. Due to the increased tourist arrivals, our returning nationals and the increased social activities related to December. In an effort to reduce the impact of this new variant and COVID-19 in general, we must take urgent actions. These include increased surveillance for early detection, ensuring optimal testing capacity, and strengthening of the public health measures. Prevention remains our most important measure at this point in reducing the health implications of this new variant. We remind you of the other important measures. Avoid large crowds and crowded areas. Ensure the protocols are maintained at workplaces, on minibuses, the commercial and tourism sector, the proper use of the face mask when in public places. Before you remain in quarantine or isolation if you are a direct contact of a case. If you develop respiratory symptoms, seek medical care and avoid contact with others. The Pfizer and AstraZeneca vaccines are available at the various wellness centers and advertised sites. These vaccines have been proven to be safe and effective in protecting persons from developing COVID-19 in severe forms, complications, hospitalizations and death. The booster Pfizer vaccine is also available for persons who have had both doses of the AstraZeneca for over six months. Everyone who has not been vaccinated is urged to get vaccinated urgently. The Ministry of Health and Wellness will continue providing updates as new information becomes available.


In order for Eevee to be such a powerful and fast renderer, there are a lot of different methods Eevee uses to calculate lighting compared to engines like cycles. To start off, let's look at the render tab in our properties editor. In here, with Eevee selected as our render engine, you can see several settings that pertain to how Eevee calculates lighting and visuals. This includes several effects such as ambient occlusion, bloom, screen space reflections, and motion blur. In this video, we'll learn how to view each one of these effects and how to adjust their settings. To enable any of these, simply click the checkbox on the left. You can also expand each category by clicking the arrow on the left. However, you may notice that checking these makes no visible difference in the viewport. This is because we are in solid view. In order to view in real time, the differences each of these settings might make simply change your viewport mode to render view. You can do that by clicking the rightmost sphere in the top right hand corner of the viewport or pressing the Z key and using the pie menu there. Once in rendered mode, you can test each of these settings to see how they might affect your render. Enabling ambient occlusion will be most apparent at the corners or crevices of your scene. To show this better, let's go ahead and add a mesh plane object and scale it up to act as our floor. This is a real life effect that can help make geometric detail really pop and often helps renders feel more 3D. Let's take a look at the ambient occlusion settings. Distance affects how far the ambient occlusion shadow extends from the corners. Factor affects the darkness of the shadow and you can actually manually set it past the maximum of 1.0. For the rest of these ambient occlusion settings, feel free to hover over them for more information and experiment to get what you like. Bloom is basically another word for glow, but you'll notice when we enable it, it doesn't really change much in the viewport. That's because nothing in our scene is bright enough yet to trigger the bloom effect. But it's a very pretty effect so let's see if we can get it to show up. Let's select our cube and go to the material tab, indicated by the red material sphere icon at the bottom of our properties editor. Here under surface, we can see that we have the principle BSDF selected by default. This is great, but we want to make it bright. Well, luckily if we scroll down here, there is an emission value. This is a color that we can set. Let's drag the value slider all the way up so that it's the brightest white it can be. Now, this isn't bad, but it's not obvious enough for testing purposes. We can confirm that the bloom is working however, if we go into our render settings tab again and check on and off the bloom checkbox. Yes, the cube is glowing slightly, but how do we make it really glow? Like a lot. To make the emission even brighter, I'm going to use an emission shader. To do this, let's go into our cubes materials tab in the properties editor. We can then switch out our principle BSDF surface shader node for an emission node from the drop down menu. Now we have a strength value we can increase to our heart's desire. I'm going to set the brightness of our emission to 10. Now that's a lot of bloom. Let's play around with our settings now. Feel free to adjust the threshold slider to determine how bright an object needs to be to start glowing. For example, our emission shader is at a strength of 10 and setting the threshold to 10 in the bloom settings actually stops the glow of the cube perfectly. You can also change the color of the glow, the radius of the glow, and the intensity of the glow. Setting a non-zero clamp value will also set the maximum intensity the glow can be in your scene. The knee value simply makes it so that those objects that are bordering the threshold of the bloom are given some slightly way to fade the bloom so that the cutoff threshold doesn't look too visually jarring. Next, is depth of field. This isn't actually a lighting effect, but I want to go over it anyway. This simulates a real life camera effect that depends on the focus of the camera. This is when only certain parts of the image are clear, while the rest is blurry based on distance from the focal point. Before we test this out, I'm going to add a few monkeys at various distances throughout our scene so the effect is a bit more obvious. However unlike the other two settings before it, this does not have a check box. This is because the depth of field setting is enabled for each camera object individually, while this setting is simply a way to set max blur size for the effect. To turn on the depth of field effect, we have to select our active camera, then go to the green camera icon tab in the properties editor, and check depth of field from there. However, we still don't see any huge blurriness or depth of field effects. That's because we still have to set the focal length for the camera itself. Let's simply left click drag the focus distance down to around one. But still nothing? Ah, that's because the depth of field effect is only visible through the eyes of the active camera. So let's simply click this camera icon to change our view. There we go, as you can see everything in the image is blurry due to them being far away from the focus point. If we drag our focus distance back up slowly by holding shift while sliding the slider, we can see the focus point moving through the scene, as certain objects get clearer and blurrier. But where is this focus point in 3D space? Well, we can actually scroll down here and go to viewport display. Then check limits. If we go back into our perspective view and drag the focus distance again, you can see that we can very easily adjust the distance how we need to. One more setting that affects depth of field greatly is the f-stop value. The lower this number, the blurrier the image can potentially be.  For a deep depth of field where many things are clear, you want a larger f-stop. Also, going back to our render settings tab, we can adjust the depth of field max size value to clamp the blur amount for render efficiency. But default values typically work fine. The subsurface scattering setting affects how subsurface scattering is calculated. With a similar samples option to the global samples, these settings overall increase or decrease the quality of the subsurface scattering calculations. We can add a quick subsurface scattering shader to our monkey here by simply selecting it, go into the materials tab and dragging the subsurface slider on our principled BSDF shader all the way up to max. Now as you can see, the monkey has a soft skin-like texture. But we're not really seeing the redness of the ears like we should. That's because there's one more setting in the material that we need to check. Let's select our monkey and go to the material tab. If you scroll down, you'll notice the option for subsurface translucency. This will allow light to pass through the ears and other thin parts of the mesh to give a more realistic skin shader effect. By moving our light object closer to the surface, we can really see more clearly both the translucency of the ear and the banding artifacts of subsurface scattering approximation. Now to get rid of the banding artifacts, we can increase the samples to increase the resolution of the effect, while Jitter helps hide some of the banding by randomizing it a bit. Separate Albedo preserves the colors a bit better, but uses more video memory. Screenspace Reflections is used specifically to approximate reflective and refractive surfaces in our scene. If we go back into our materials tab, we can select our plain object and add a new material. Then decrease Roughness to 0.2. As you can see, we now have a very shiny floor, but there are no reflections of our objects, only our lights. Although technically it's also reflecting our background. I'm going to add some more reflections to the background I'm going to add a checker texture to my world shader to make that a bit more obvious. Anyway, by enabling Screenspace Reflections, objects will actually start to appear in the reflection on the floor plane. The settings here will affect various aspects of the reflection. Roughness, for those who don't know, is how you set how clear the reflection looks. The rougher it is, the more diffuse the reflection. Whereas mirrors are typically a roughness of 0. Max Roughness here is similar to Threshold in that anything above the Roughness value will not display reflections. This saves Screenspace Reflections for only the shiniest of reflective shaders. Trace Precision will affect the quality of the reflections to a certain extent, but in reality, the global sampling settings is what will affect the noise in the reflection the most. Increase the samples to decrease the noise. Half-res trace also allows you to lower the quality of the reflections without affecting your global samples. This makes it more noisy but faster, so feel free to play around with what works for your scene. The Refraction setting under Screenspace Reflections is specifically for glass-like shaders that refract light as it passes through. Let's go ahead and go to the Materials tab and select a monkey to give it a glass shader. I'm simply going to add a material and switch out our surface option from Principled BSDF to Glass BSDF. Now you'll immediately notice that it looks like glass, but you can't see through it at all. Let's check on the Refraction option under Screenspace Reflections in the Render Settings tab. But it's still not see-through. Ah, that's because just like Normal Transparency and Subsurface Scattering Translucency, glass refraction is also handled as a transparency effect that needs to be enabled in the Materials tab. Let's go back into the Materials tab and scroll down until we see Settings. Then check to enable Screenspace Refraction. Now, as you can see, the object is refracting the light. However, we can also edit the object-specific refraction depth to approximate the thickness of our object if we want to be a bit more accurate. For your reference, each grid square in our viewport is typically 1 meter, but default settings are fine too. Next we have Motion Blur, which is also only visible from the camera's perspective. So let's turn on the Motion Blur checkbox and go into our camera perspective by pressing the camera icon here or pressing 0 on the number pad. However, we still don't see any motion blur, but that's because there's no motion in our scene. So the fastest way to see it in action is to animate our camera real quick. Let's select our camera by clicking on the border of its frame and turn on Auto Keyframe Mode by clicking this white circle record button. Then we can rotate our camera by pressing R twice to look a little to the left of our monkeys. As you can see, the timeline now has a yellow diamond keyframe set at our current frame. Then, click and drag the top of the timeline to move our current keyframe to frame 10. Here we'll want to rotate our camera again to look a little to the right of our monkeys. Dragging our timeline back to the beginning, we can play our animation with the spacebar and see a very prominent motion blur effect when the camera is in motion between our two new keyframes. To see this more clearly, you can also pause and simply scrub through the frames as the motion blur will still be visible to help tweak. Looking at frame 5, for example, we can very clearly see how the motion blur settings affect our visuals. So now it's time to play with the settings. The shutter value affects the amount of blur while the number of samples affect the quality of the blur. Volume Metrics is a setting that affects how volumetric shaders look in our scene. If we expand this section, you'll see a few things that we can tweak. However, we don't currently have any volumetric shaders in our scene to test. So, let's go ahead and add another cube from the Add menu. We can go into the Materials tab and switch out our principled BSDF for Remove. This will remove entirely our surface shader. Then, we can expand the Volume section and select Volume Scatter from the drop-down. This will add a volumetric shader to our cube. To better illustrate what this does, let's scale our cube up to engulf our light object and maybe half our scene. You'll notice it really fogs up the place. To make things a bit more clear, let's turn the density value of our volumetric scatter setting down to 0.5. Nice. Now we can test out the volumetric settings in our Render Settings tab. To start off, the Start and End values determine the clipping range relative to the distance from the camera for when volumetrics should be visible. As you can see, if we zoom out far enough, our volumetric cube will disappear. Likewise, if we drag up the Start value to something like 10 meters, we can zoom in and the volumetrics will disappear before we can get too close. Default settings are typically fine here, but feel free to experiment for your scene. Tile size and samples are both ways you can control quality of the volumetrics. You may have noticed by now that when moving around in the viewport, the volumetrics show a kind of banding pattern as it refreshes. The number of bands is based on the number of samples. The more bands there are, and the less obvious the bands are, thus the higher quality the volumetric becomes. Meanwhile, the tile size actually affects how sharp the edges of these bands are. Setting a high tile size number will result in blurry banding edges, but won't be as accurate, while the smaller tile size will slow down your viewport a bit but increase the sharpness of the samples. Distribution is a very important setting for when you or your camera moves inside or close to a volumetric shading. If we zoom in here, you can see that currently our volume resolution still holds up pretty good, but if we turn our distribution all the way down, you'll notice that it starts banding heavily as the volume gets closer to the camera. If you think of volumetrics like essentially a bunch of semi-transparent planes in an array stacked close together, this makes sense. As the closer you get, the more obvious the distance between the planes would become. However, with distribution, the space between the planes gets smaller as the camera gets closer to the volume, thus hiding the gaps between the planes and giving a higher quality volumetric look from all distances. The higher the distribution, the more it compensates for camera distance. This next section is for volumetric lighting specifically. If we check this checkbox off, you'll notice that our light object no longer affects the volumetrics. That's pretty much it, but light clamping will let you prevent any lights within the volume from being brighter than that value. A light clamping value of 0 simply means the clamping is turned off, allowing all light to persist in the volume. Volumetric shadows are basically shadows that are cast by the volumetric shader itself onto itself. These can get expensive, so use with caution, but feel free to experiment with it for your own scenes. The hair settings are specifically for hair particles and how they're rendered. The basic option is simply choosing between strand and strip. Strand is better for previewing, but stripped looks a lot prettier. Additional subdivisions can also help increase the smoothness of the hair's curves. Shadow settings can be adjusted here as well. The shadows of your scene can be calculated based on different methods in Eevee. ESM, or Exponential Shadow Mapping, is the default, whereas VSM, or Variance Shadow Mapping, can also be selected. You can read about the difference between these two in the official documentation in the description down below. Furthermore, cube size can visibly increase the quality of your shadows. This is basically resolution for your shadows. The higher the cube size, the higher resolution the shadows will look. Cascade size increases or decreases the detail of shadows specifically from sunlight. High bit depth can help increase quality as well by reducing some artifacts that might persist in lower bit depths. Soft shadows randomizes the shadow maps to soften the edges of your shadows. And light threshold is an interesting setting, as it allows you to change the threshold at which shadows are calculated. Typically, a shadow is simply an area with little to no light. However, you can increase the threshold to define what little to no light really means. For example, if I increase this to 1, then any area with less light will also be displayed as a shadow. Indirect lighting is a group of settings that refers specifically to the objects known as light probes. You may have seen these in the add menu, but not understood what they do. In the add menu, we can see there are currently three kinds of light probes. Reflection cube map, reflection plane, and irradiance volume. Light probes are objects used to precalculate certain lighting effects, such as bounce lighting, reflections, and refraction. This is a technically more accurate way to calculate real-time reflections in EV compared to screen space reflections, with some limitations. Let me show you what I mean. Let's subdivide this cube and give it a roughness of 0 in the materials tab. Since we have screen space reflections turned off, this reflective sphere doesn't reflect the monkey next to it, only the light and the background. However, let's add a reflection cube map to our scene. Reflection cube maps are used to calculate reflections for objects within a certain volume. When we add a reflection cube map, you'll see the sphere appear, which can be placed around objects with reflective shaders. Once we have placed the light probe properly around the sphere, simply press Bake in Direct Lighting. As you can see, the monkey is now properly reflected in the sphere. However, you might notice that there are diamonds in the reflection. That's because of the clipping settings of our cube map. Simply go into the Light Probe data tab in the Properties Editor, marked by this diagonal volume icon, and go to Viewport Display. Here we can turn on Clipping, which if we go into Wireframe mode, will notice the clipping starts inside of our sphere. This is what's causing the black squares, so let's drag the clipping start value up a little bit to bring that to the sphere. If we go back into Render Mode, go to our Render Settings, and hit Bake in Direct Lighting again, we can see these black squares have disappeared. But in case you don't want to press Bake every time you make a change, you can also check this Auto Bake checkbox. This will update the bake every time you make a change to the Light Probe objects. It's important to note that reflection cube maps do not update reflections to show the animation of objects, the reflection calculated is static. However, irradiance volumes and reflection planes do show object animation in real time. Reflection planes work much the same way as reflection cube maps, only they are flat. Irradiance volumes are a way to simulate bounce light. You can add them to your scene to sample surrounding colors and brightness, and cast that bounce light onto other objects. Remember when I said you can't use emission shaders as light sources in Eevee? Technically with irradiance volumes, you can. However, they don't cast shadows and require the light sources to be static. But irradiance volumes along with other Light Probe options can be incredibly helpful in Eevee to make the lighting feel more realistic. Light probes are an Eevee specific feature and you can read more about them in the official documentation in the description down below. As you can see, Eevee's real time lighting settings can make big differences in how your scene looks in Final Render. I hope this video helps you get started enough to allow you to experiment further for your own projects.