Handling complicated view logic w/ Skyler Katz & Bogdan Kharchenko

00:07.20
Chris Morrell
All right? Welcome back to overengineered the podcast where we ask the question. What's the absolute best way to do things we already have a perfectly acceptable solution for ah today we are trying. Video so you may you may be seeing this on video or we may have abandoned it and just post the audio. We'll see um but I am back with ah Skyler Katz and Bogdin karchenko you guys want to say hi.

00:34.70
Skyler Katz
Hello Hello Nice to see everybody out there in podcast land.

00:40.31
Bogdan Kharchenko
Hello everybody great to be back. It's been a while I feel like Chris has been going off on his own and doing his own podcast show with everybody all the cool people. So it's exciting to be back here.

00:47.51
Chris Morrell
So.

00:54.58
Chris Morrell
You guys are the ogs though you know, um so the the 3 of us worked together and this question came up recently ah that it was it was kind of a specific problem that maybe we'll get into later. But. Um, the general question of how much should a blade component do like what's the scope of a blade component because we we kind of got into a situation where there was a component that was doing a lot in its should render method. And um, it just there. It. It sparked quite a heated discussion and so um, we thought it might be just kind of interesting to to think about like. What are the boundaries of a blade component. It's not exactly the classic overengineering problem but it's more just ah I mean I think we can. We can find a way to overengineer it. So um I don't know Skyler. Do you want to? do you want to kind of like talk about the initial thing the initial problem that you were solving and and. What felt good about that approach.

02:02.43
Skyler Katz
Yeah, so we have this this email that we need to send to our our members our users and our app and some some of the parts of the message it depended on which state that you reside in. As to whether or not you receive something um in some states you receive it all the time in other states you only receive it during certain days of the year and in my first pass I had all these if statements just in the email blade view like if user state is California and they. Are in this ah state of of app like they they scored a certain way on on an exam then display. Um this additional inlude and I finished and the blade view was very large and it looked gross to me. Ah. But then I discovered a should render method is available in the blade component and so I moved a bunch of logic I split out all of these California North Carolina like all these various localities and. Did sql queries in there should render methodist to whether or not the user is in a in you know the right the right state and submit the pr and I was like oh this is perfect like it looks so much better I could test these blade components. Um.

03:32.51
Skyler Katz
Then Chris reviewed the pr and was like I don't know about this. Ah maybe we should do if statements and so it it entailed just this long conversation. Ah, and you know boss man Chris is the boss. So pr got closed but it was it was good I feel like we came to a good solution in the end. But.

03:38.85
Chris Morrell
Ah.

03:51.67
Skyler Katz
Ah, yeah I still am on team should render.

03:53.83
Chris Morrell
Yeah I mean spoiler alert if you go back to the episode with Caleb ah, the whole hooks implementation ended up being the the solution here or we're hopeful. Um, when Caleb and I were talking about it. We were we were mostly talking about like hooking into. Moments that a class or function is is executing but the same sort of principle sort of translates really nicely to view rendering as well. And so um, there's ah, there's a early ah pre-release of of the the hooks package that you can check out that that does both. Sort of the um breakpoint hooks that we were talking about in the last episode as well as like providing a way to hook into ah moments in a view render if you need to do a lot of like really complicated logic. Um, but the question sort of sort of still remains because like.

04:50.18
Chris Morrell
When I was reviewing the pr like the end result is you've got this email view that just has a couple of blade components at the top of it that from my perspective I'm just like well it's just always showing this like California notice and this Nevada or. I can't remember what the other one was but it's always showing these notices that's kind of weird. Um and nothing was getting passed into them. So it's like how is it like what is going on here and so I think like my first. My first reaction was just like what. What is going on and this feels really bad and maybe we should just have if statements because that would be more clear but I have been in the exact same place of like the moment you start having a bunch of if statements in a blade component. It just gets it. It gets really rough if you need to do really conditional rendering but it's something that has a lot of shared language or shared ui you know it's like you're in that in-between place. It's just it's just a hard thing to solve and so I I totally get. Like using that should render ah logic and letting blade components be sort of more self-aware like I think it is a cool idea and it definitely potentially solves a problem. But I think you know it.

06:21.40
Chris Morrell
It feels a little bit like is it too off the beaten path or something like that I don't know.

06:28.14
Bogdan Kharchenko
And so is your kind of like concern with um, you know, just that data being like loaded from a database. Let's say from that component and there's like nothing getting passed in or the fact that the component itself is like dictating. Whether or not it should render. Um, you know under the hood should render is being called all the time when the components boil down into like php code when the view was cached so you know if you just return false in there. It gets evaluated anyway or not. And anything on top. Obviously the downside is you know the entire component gets you know, ah parsed into. Um you know, ah php Code. So is that kind of like the question like you don't want that code being computed or. The fact that there's no data being passed into that component and that component is loading its own data which could potentially you know introduce and plus one issues and so on and so forth.

07:34.14
Chris Morrell
Um, yeah I mean I think it's more the latter I think I think that I think that there are kind of 2 things happening here. 1 is like anytime you introduce sort of like a non um, idiomatic approach to things like. It just introduces like friction or it it introduces just like a little bump when you're looking at the code when you're reading the code right? So like I think there's that question is it. You know. Is it common enough to have blade components that are just like. May not do anything and you just have to know that like and and I think that's the type of thing just like I always talk about this with with um, you know event-driven applications versus like ah, any other approach like there's nothing wrong with firing a ton of events and then reacting to those events. But. That needs to be sort of the primary interface that your application uses to communicate or else. You're not, you're just not going to think to look in event listeners or observers or whatever because unless that's there that unless that's where you always go to look I think it's hard to think okay, well this isn't. what I'm what I'm trying to find isn't in the code but like oh maybe it's in an event listener somewhere. Um and that bites us I mean that's bitten us plenty of times for the few places that we do have event listeners. It's like sometimes we don't think to look there until until we're a little frustrated. Um.

09:08.49
Chris Morrell
So I think that that like the one side of it I feel like you could just decide as a team like we're going to lean really into this like approach to blade components and say you know. You may see a stack of 10 blade components on top of each other and you just know like not necessarily all 10 of those are going to render. It's just like any combination of these 10 things may render for the current circumstances and I think that would probably be fine. Like if that was kind of just like the approach that your app took and it was normal. Um, it still would probably be a little weird for you know, a new developer to come to, but that's probably fine. You know we learn things quickly I think the thing that like I have an immediate like. Hell no reaction to is ah when you start doing eloquent queries in the view. You know when you start doing eloquent queries in the blade component because it's like it's just not obvious that that's happening and yeah I think you're really You're really likely to introduce some some weird performance issues whether it's an n plus one or something else. Um or just not. You know, not be aware of what's happening inside the application. But even there you know i'm.

10:33.36
Chris Morrell
I'm open to being convinced because I think like I I think it's it's easy to fall down that hole of like well this isn't appropriate for like this is not the proper place to do this thing so you should never do it here and it's like sometimes just way better to do it that way. So Like. I'm willing to be convinced.

10:52.71
Skyler Katz
Yeah I mean I'll say I'll say like in this in this example of a mailable. Ah, originally all of these queries like is California was a boolean that I was having to calculate in the mailable and then pass to the view. And then in the view I was just like if is California and then it was like if if is North Carolina and is North Carolina display time and like these were then just you know there were maybe 20 variables that I was having to just pass into the view and the mailable got.

11:17.12
Chris Morrell
Yeah, yeah.

11:24.42
Chris Morrell
Yeah, yeah.

11:29.70
Skyler Katz
Really unwieldy. You're like why we have to calculate all these queries. But now we're doing them all up here instead I was like oh the California in you know, component and it passed in the user and then it was like oh here's the query for should render and it's it's all contained I don't know.

11:45.80
Chris Morrell
Yeah, yeah.

11:49.38
Skyler Katz
it it those queries have to happen somewhere. It's not like the the queries don't exist if anything it's like more encapsulated you're like oh I will I'm in the California component and now I'm doing the calculation for California.

11:53.70
Chris Morrell
Right.

12:02.00
Chris Morrell
Yeah, what do you think bogged and should should components ever make eloquent queries for.

12:07.55
Bogdan Kharchenko
I mean it depends you know I think like a good example that I can quickly think of is say you have a component in your dashboard called like friend list you know and it's just like a Div and you know it renders only if you have friends and if you don't have friends it renders. Maybe there's another thing that it would render and um, you know you could basically wrap that component in if statement in your parent like blade template or you can have this should render function um basically decide on its owns like if there's a list of friends that were passed into this component.

12:33.60
Skyler Katz
Back.

12:47.18
Bogdan Kharchenko
Should I render myself and that would render potentially other components um like child components. Um, you know So I think that that could be like a pretty compelling reason for me to say like all right? Well if the data is passed in and. You know I can decide whether or not I'm going to render myself I think that's like a pretty decent pattern as far as actually making eloquent queries. You know I've been in a situation before where um, you know I would have a blade component say it was like a select 2 component. That's like the auto tag complete.

13:20.18
Chris Morrell
Yeah.

13:22.95
Bogdan Kharchenko
And all I wanted to do is just say like well if you pass me a bunch of Ids I'm going to go and to my tags table and load a bunch of those ids from the database fresh and I know that that component itself is never going to be I can't say never but. Likely only be rendered once or twice per page. So I'm willing to accept that. Ah, because otherwise you would have to like pass that data from a controller for example and somehow hydrate those fields. It gets a little bit messy as well. So I think there's a tradeoff I think.

13:40.97
Chris Morrell
Right? right.

13:57.37
Bogdan Kharchenko
You know Ah, even to this example, that skylar has been mentioning. Um, you know I keep going and going back to this idea. Well how do we get here right? Like how do we get to if is this California if this is that you know perhaps like there's a missing piece of like a database table that kind of dictates. What is being shown in some of these messages in the mailable and then maybe you wouldn't have to do all of this gymnastics inside of the component or somewhere else. So that's kind of where I stand.

14:28.40
Chris Morrell
Yeah I mean I think that's that's like that's what makes this comfort that when we get into the specifics. It gets complicated because the reality is you know sky is kind of even simplifying the situation like ah when you deal with. Hundreds of licensing bodies that each have ah potentially dozens of rules about certain ways you message people or certain ah notices that you can or can't show or blackout dates or all these you know it it just. You know I can imagine I can hear someone listening to this being like well that sounds like really bad architecture you know and the reality is you just have to trust us that this is really complicated and it's going to need it needs ah help. Ah, necessarily somewhat complicated solution. You know like there just there is no way to make ah you know 500 times 12 times every possible like ah decision point number of options like easy to to manage. Um, and so no matter what this was going to be something that was going to be a little tricky and but it's it is funny like when you talk about that like autocomp completee like ah select 2 thing I don't I I don't know exactly what it is but for me I'm like.

15:58.80
Chris Morrell
I can live with that doing a database query like I can because I think because I can imagine that it might you know like when you look at that thing and like it's like an x select to and you pass it a property called Ids or whatever like. It just feels like it's kind of implied that there's going to be some something happening in the background like that that handles it for you. Um, and I think maybe that's what it is is like I I don't think that I'm like hardline never do any. Eloquent queries in a blade component. Um, nor am I hard line like never you should never use should should render because I think should render or just like an if statement inside your blade component is perfectly fine. Um, if it's like. Ah, yeah, I'm dropping the friends list right here if they don't have friends just nothing's going to show and if they do it'll render the friends list like that feels perfectly fine to me and like I can also see like if I saw in the code like ex friends list. User equals user right? like you pass in the user and you're rendering a friends list component like I would just assume that that component is going to load a missing friends' relationship if it's not already loaded and like it's it's going to be aware of the database to some degree.

17:29.47
Chris Morrell
And that feels that feels fine to me too. So it's like I've all I've already accepted that I'm not opposed to any of these things. But for some reason ah still like thinking back to looking at that code I'm just like ah something about it felt wrong.

17:46.13
Skyler Katz
Yeah I mean I think too though like you know, let's say let's say your friends list component and so in your view, you're like at if user friends count or is not empty on the collection then here's the component. Um, you know, but then and this may be in multiple places in your in your application and then you know now you want to change how you're determining if they have friends. Maybe you want to show potential friends if they're new now you've got to go to all the places where you had the if statement as opposed to like. Ah, just open up the friends component and recalculate in the should render and you're good to go. You've you've just finished the the feature. Um, you know right away and this is a little thing but when I'm writing a blade. You know you got your your html.

18:42.96
Skyler Katz
And now you've got this if statement and then you're indenting. Ah you know deeper in and like in an email every time you indent in it's like going to do weird stuff in Outlook which a lot of our users use. Um and so kind of nice to be able to just keep the indentation nice and. Let the component decide should we render I mean that's a little thing but now it's still there.

19:04.80
Chris Morrell
Um I I have I have no quals with with pointing out the aesthetics for sure you didn't even have to make the outlook argument for me to be convinced to that on that point. Um, yeah, no I mean well okay.

19:23.36
Chris Morrell
There's 2 different things going on here I I can I can I can find ah like a supporting argument and a counter argument and ah and I can't figure out which one is right because it's like it's a question of like coupling versus colocation kind of right like because the same. That same argument that you just made could be true of like um, a like a css like ah, an old school bem style css component right? where you're like well I have this like card component and card header. Ah, key component our card card class and card header class and card body class or whatever and if I ever want to change the way cards look I just go and update the card class and it updates across the entire site and the end result is you have to create a card to class because you don't. You don't know what you're going to break when you change the card class. Ah so you're always afraid to change anything because because of that exact you know the thing that that we thought was a power is actually like you know a huge liability and that's why tailwind became so um. So popular or that's ah, a reason why why a tail one became so popular. So like that it it feels a little bit like that of like okay well now if this logic lives inside my component I have to.

20:52.33
Chris Morrell
Have to think like if I go change this for this one page. Do I want that to cascade across all the other pages that use this component but on the flip side I think you're absolutely right? that like um, finding ways to sort of put all the. All the stuff that belongs together together. You know this I think there's ah we've talked about this before like this appreciation in 2023 2024 of like colocating code. Um, yeah, there is a really compelling argument to say like.

21:29.88
Chris Morrell
Instead of having to do all this stuff in your controller or in some sort of helper object that you pass through the controller to the view to the blade component like the blade component is just nice encapsulated responsible for the whole whole decision and all the data that it needs and like. You can just delete that whole component if you ever don't need it anymore and like you don't have to like walk up the chain of all the calls like that's really compelling too right? It's kind of like which one of these two things is it or is it both I'm I'm not sure.

22:05.54
Bogdan Kharchenko
And yeah I mean I will say like 1 you know I think you know we shouldn't be nailing screws you know because that's the wrong tool for the job and vice versa like you have to kind of make a decision of what's appropriate I mean obviously having components has been like a huge. Game changer like I've refactored like huge if statements that did like less than greater than this date and very complex logics that I didn't understand until like name methods that live inside colocated in the component class and. You know, even if I have to do this additional sql query or just pass data into it I don't know it's just improved my I don't know ah coding ability and um, you know co-locating code in general has been fantastic and the way I look at it those if statements. Um. Ah, really related to a view you know and maybe some of those if statements come from like you know various models but they're really specific for this component how they operate. So even if those like logical you know functions lived in another helper like it's still. You know I know how likely you would reuse those same thing where you like yeah show five friends only that's really specific for this component. It's not really a application wide thing. Um, so I don't know I really think that you know you have to um.

23:36.72
Bogdan Kharchenko
Sometimes just do 1 thing or the other I don't think it's a hard no in any way on either way.

23:41.46
Chris Morrell
Yeah I mean that this we we have to ignore the fact and we wouldn't be allowed to have a podcast if we accepted the fact that the answer is it always depends though.

23:54.22
Skyler Katz
I mean I think I think too like there's there's the potential. The potential testability of like you've got this complex logic of if something can show and so you have a you know a. Php unit test that has a data provider of a bunch of different things that are going to return true or false and you can test by just newing up the component class and calling should render and determining if if all of those you know different scenarios are true instead of having to like let me create. Create a couple of different users and and then like call this get and assert that html doesn't have a certain thing in it. Ah.

24:38.72
Chris Morrell
Um, right? Yeah no I mean that's that's I I think yeah that is compelling too. I I think that there's.

24:48.76
Skyler Katz
Yeah I'm not I'm not sure that you should do a thing because you can test it differently but ah, but it is is another tick.

24:54.49
Chris Morrell
Sure it's another tick on the one side. yeah yeah I mean I think that for me, it's a little bit of like ah how close to intuitive can this be right. and I and I think like you know back to what bhadin said it is it depends obviously and it's like I think that maybe the solution is kind of both like maybe you pass in things that feel appropriate to pass in but let the component do things that feel. Appropriate for the component to do and like maybe it's just ah, finding a little bit of a different balance where you know and where you're like you're making it so that the call at least gives some hint about the fact that it's like conditional or. Um, yeah, or or you're commenting above the block of of components being like you know the reason why there's 15 stacked components here is because only 4 of them are ever going to render for any given scenario or something like that I guess that would be fine too. But yeah, it's still I don't know I'm still not satisfied.

26:10.94
Bogdan Kharchenko
I I suppose it really depends on kind of like how you decide to structure your application. You know I don't think it's um, you know, just bad idea to just say like well this is like the login dropdown component and then there's also like the logout Dropout component. And typically you would just say like well if user is authenticated or if Aut show this thing and you would just do like some sort of partial include or else do this other thing I mean if you decide that you don't like that pattern in your blade components and you're like well I'm just going to have a login. Drop menu and a logout drop menu or whatever that is and those menus themselves like the logout drop menu can determine whether or not, you're logged in show different submenus or whatever the case may be and they're just stacked on top like I think that's perfectly fine in my book like there's an. If statement happening either way. Um, and ultimately this stuff gets boiled down into a cached view. So I Don't think there's that much of a performance hit right.

27:09.60
Chris Morrell
Right? right.

27:19.19
Chris Morrell
Right? I don't I don't think there's really a performance implication either way because like you said you know the the logic has to be executed wherever it gets executed and I mean I think that's another big piece of like in our specific scenario. Um.

27:36.11
Chris Morrell
The other issue is like is this logic only going to be executed here or are you going to end up like duplicating this because you know in that scenario. It's like well North Carolina has these special dates when you're not allowed to take ah continuing education exams and that's going to affect. The messaging in this email, but it's also going to affect 15 other places in the app you know? and so I think that that's another that's probably another consideration is like is the logic that you're executing in your component really really view specific or is it something else. Because that would be another hint at which which pattern you're going to reach for because like that that was that was certainly another reason. Um, why we decided to kind of like go down another path is like we knew all all of that logic that we were using in that mailable was. Eventually going to be needed to be extracted out anyway for a bunch of other conditionals and so like yeah it it does feel like there's like 1 element of like you just have to decide is this a style of. Code that you like or that your team wants to embrace and then it it is really just like ah you have to use your best judgment on how you know how autonomous these components really should be.

29:08.35
Bogdan Kharchenko
So. The only thing I was going to say thinking about like a real solution to this issue that skyyler and we all been dealing with are contemplating on how do is like what if we actually had like a helper function that. You know, ah went state by state and like returned the the views computed effectively and all you would have to do is just like loop through this but collection object and just display this stuff you know and that way all you're passing down is like this collection of like pre-computed. Component not component but just like the text that used to show and it could be a list of components that do various functions. But ultimately you're just passing 1 collection saying hey for each one of these things. There's just like a list of messages and warnings or whatever that are shown. Um, and all of a sudden you know you're passing 1 item in it's co-located and somewhere else in some sort of helper function and you know you can reuse that somewhere else to get those messages into your email into your webpage or wherever it is.

30:17.81
Chris Morrell
Yeah I mean I I think that solves the like the messy if statement problem like I can see um you know and another place where we have this is like depending on about 5 or 6 different like. Nested levels of factors. Your billing page is going to display differently like depending on what kind of plan you're on and what kind of membership you have and you know are you paying by credit card online or paying by check and invoice or like all these different all these different scenarios contribute to what. Messaging you're going to see and what components you're you're going to see and that's like a huge tangled mess of if statements. Um, that like felt like I mean I honestly still feel like it's ah it's pretty much the best. The best we could do with like the complexity that we were trying to deal with but I could see an argument for like yeah pulling that out into a single class that effectively just um, you know does a bunch of sort of nested loops and builds up. Ah, you know html string that you just wrap in ah you know that you just pass down as html and I don't know that that would end up being better. But I think it's kind of a cool approach when you have this sort of.

31:50.90
Chris Morrell
Like lots of lots of conditional logic that you need to like use for specifically for for the view because I think that's where it it feels really bad. You know, like in other places you can. They're just there are a lot of more well establishlished patterns for like cleaning up. Ah. Complex conditionals. But at the view layer I Just don't think there's the like canonical way to do that at at least in my mind I don't know.

32:19.99
Skyler Katz
Yeah I mean with that billing Scenarios I was just looking. We have 21 different states that a user could be in when it comes to billing and what plan we're supposed to show and who who has it and like the level of abstraction was we just created all these different scenario queries and. Passed in things. But yeah, the if statements ah like they felt gross to me when I was working on that feature too and I think had I realized there was a should render I might have ah utilized it then but meant that and that test is gnarly because we're texting that.

32:43.99
Chris Morrell
Yeah, yeah.

32:58.63
Skyler Katz
Specific Html strings are showing up or not showing up um on the page.

32:59.82
Chris Morrell
Yeah.

33:03.28
Bogdan Kharchenko
Is the challenge with that. Just the fact that the if statements are like hard to parse like as you're going down is that kind of where it is where you see like a benefit of extracting you know those conditionals into like a method on the component that would like help. Decipher what that if statement's doing is that part of the situation or just kind of like you know the the children of like all the states that you know this thing could be that it could just render different items.

33:31.62
Skyler Katz
Oh.

33:41.61
Bogdan Kharchenko
I Don't know if that makes sense.

33:43.70
Chris Morrell
Um, I mean it's tricky because on one hand the reality is it's just it's a tree with a lot of branches and like. It just is Complex. You know what you say 26 different difference 2021 different scenarios and those scenarios are like there's a few like top level ah conditions and then each of those top level conditions have a few subconditions depending on like.

34:00.19
Skyler Katz
21 different different scenarios.

34:16.75
Chris Morrell
Um, various pieces and so like it is I mean part of the problem again is just like this is a thing that was really complicated but you know if I step back if if this were in just like a class and I had. All of this nested logic. You know I would just start extracting it out into named functions and even if the nesting was you know, still visually a little bit intense at least it would just be like I can read each function name and see Okay, this branch is about like. People with lifetime billing who do have billing history and this branch is about people who are like who have never paid but like you know,? whatever, whatever the scenarios are um, you know, being able to extract things out into functions. Um. Ends up, you know, becoming a way to label that branch of the logic and you can do that with partials or Blade components. But it's not exactly the same because um, that is its own entire. Sort of isolated Space. You know, whereas when you're just extracting parts out into functions you you just have a little more flexibility I think I don't know maybe the solution here is that we just want. Um you know.

35:52.19
Chris Morrell
Ah, Blade component would be ah the better, a better approach and you know using should Render would would have helped there but it's the same I don't know it's tricky.

36:02.58
Skyler Katz
That's hard to say because a lot of these were like if like I'm looking at the I'm looking at the top level View. You're like if you have an active subscription and you're not a non billable user and you're not on a team plan then display an include but then. Next block says if you're not a not billable user and you're not on a team plan display. Some management options. So like we wouldn't want to recalculate over and over again. Whether or not someone is a billable user. So some of these queries and it might be hard to realize that.

36:28.74
Chris Morrell
Right.

36:38.97
Skyler Katz
That query is being used in multiple places if you don't have it in the controller or the mailable but you're doing it individually. You do lose some impact of like what what is this? what it data is already available. Ah.

36:43.59
Chris Morrell
Yeah, yeah.

36:52.47
Chris Morrell
Right? Yeah I mean you could argue that you can just like do that as like a performance review right? Where just like ah maybe you're not going to worry too much about making sure that everything is perfect in the way you're loading your data for like a. Feature that just isn't very actively used and then like if it becomes more actively used you pay a little bit closer attention to um, ah the the querying and the data fetching and all that stuff like it could be the same here. But yeah, the the question is like do you feel like extracting that logic. Into sort of like some object that you just like pass that object down and then just render it and it's responsible for figuring all this stuff out like would that would that feel better. Do you think or would it just kind of be like moving the problem to somewhere else.

37:47.48
Bogdan Kharchenko
So like an object like a separate class or like a component object class.

37:52.22
Chris Morrell
Um, well well I was thinking kind of I was trying to explore the the idea that you had of like what if there was just this collection that you could just iterate over and it just decides what pieces to render kind of internally and I'm just I'm just wondering is that like.

37:59.79
Bogdan Kharchenko
Sure.

38:10.97
Chris Morrell
Is that the type of thing that you could reach for to solve these complex cases right.

38:14.99
Bogdan Kharchenko
I Mean you can certainly? You can certainly do it like right now because I just pulled this code up because you know and to see what was going on right now we're just assuming that this code just renders on this blade view but you know we could potentially send it as an email we can potentially show it as like a popup on somebody's Dashboard. You know there's. Different mechanisms to push this data. So yes, if we were faced in in that position we would have to extract it effectively and recompute this in various places and it wouldn't be a component. It would have to be like a standalone object that just renders or renders text. Maybe you want to send them a slack message or. Whatever the scenario is um so I think like for for this scenario you know it could be converted into a view component. Um, but you know if we like I said if we decide to expand the scope of where shown the view component is not going to cut it either. It will have to be like a helper.

39:09.49
Chris Morrell
Right.

39:12.17
Bogdan Kharchenko
You know class with something so I like again it really depends on what that scenario is.

39:18.87
Chris Morrell
Um, yeah I mean oh go ahead.

39:20.79
Skyler Katz
I Don't know I mean well I was going to say like well I was working on a feature. You know we're we're working on migrating to stripe and um with like we want to get admins. Want to get an email when some. Stripe webhooks come in that we're unsure of like what to do in the system and so we have just this base email that gets sent like this event happened to this user? Um, but then there were a handful where like well their subscription was updated and so we wanted to know what was changed. And so now we have this class that's like checking to see if the event has some custom views that it should display and we generate those custom views and then pass them to the main view and ah it. It's sort of kind of gross to do I I think it's what we are doing here. Maybe um, but the code's not in production yet. So doesn't doesn't matter like we can change it. Um you know, but sort of this other class somewhere else determining. What.

40:26.25
Chris Morrell
Doesn't matter yet.

40:34.76
Skyler Katz
Is going to render in the view also obfuscates ah and it could just be a naming problem like custom views as a variable name just kind of sucks. So.

40:42.24
Chris Morrell
Right? yeah yeah I mean I think I think that there are places where this like you know this is kind of coming to the idea of inversion of control right? like you give. Ah, you have a feature that needs to just sort of like open up and let someone else be responsible for like some part of it right? It's like I know that I'm not the best 1 to answer this question so I'm just going to provide a way for someone else to answer this question and I think that can be a really. Powerful, um concept but it definitely. Yeah, it can also be um, you know it's it's like a layer of abstraction for sure. Um, and that's kind of I mean that's the tradeoff that we're picking with the hooks. Um that essentially. We are introducing this new layer of abstraction that is a little less direct. Um, and I think the tradeoff is good in that case, um, but it's kind of the same thing as this custom view. It's like I know that every once in a while you might want to render a little bit more than. Default view and rather than have like a bunch of like bespoke mailables for these scenarios that are almost entirely the same except for one little difference like we're just going to give you a place to throw a little bit of content. Um, and I think you know I think.

42:14.73
Chris Morrell
Thinking back on that particular feature. The reality is probably just we should just have a customer updated profile mail and then the problem goes away but it's a solution though that is ah is certainly appropriate in places. Um, and yeah, it's. That's kind of what we're getting at here is just like we know this email may need some specific like specific messaging in certain spots depending on all sorts of different scenarios. Um.

42:52.65
Chris Morrell
How do we do it.

42:55.71
Bogdan Kharchenko
So I mean so I don't know if you wanted to get into hooks but I know that when you and Skyler were kind of working on it I didn't have a chance to really dive deep into it. Perhaps you can give me like a thirty second elevator pitch. Ah, refresh my mind on how it actually would work. So.

43:15.00
Chris Morrell
Skyler. Do you want to? I'm curious. You do you want to try to pitch it because I'm curious if I have.

43:17.91
Skyler Katz
I mean my my like snarky. Yeah, my snarky response would be like I think that hooks is why wordpress became the most popular platform to build websites with and and power the internet and because it a lot plugin developers to just access. Hooks into the the lifecycle of a request on wordpress and and make things. Um, you know make things hook into to wordpress's core as the website was rendering. That's not really exactly how packaged Chris Chris made in a fever dream. But of ah of commits but it's sort of sort of why? yeah.

43:58.76
Bogdan Kharchenko
Yeah, okay yeah I mean I yeah I could see how that would work sure how about your version.

44:01.20
Chris Morrell
Um, well it is well yeah I mean I would say I would I would I I think I said this on the the episode with Kala but I'll I'll say it again. It's it's like both the reason that wordpress is so popular and also the reason why everyone hates programming wordpress plugins and themes because on 1 hand you know the hook system in wordpress ah provides so much power and flexibility that.

44:25.80
Bogdan Kharchenko
Ah sure. Okay.

44:36.16
Chris Morrell
Plugin developers can really augment the platform to do whatever they can imagine um because no matter how I mean we all like to think oh if I provide the right interfaces and extension points and like you know. Break all my code out into really nice isolated ah classes that have their own like each heather on interface like somehow I can make my code perfectly extensible but like you can never imagine all the scenarios that someone's going to need whereas like kind of the beauty of the. Wordpress hook system is just like we just give you spots to execute code and you do whatever the heck you want? you know you can we pass some things in you can pass some things out and like we have no idea what you're going to do with it. Um, and so so hooks. Ah, it's a. GlHDHooks if you want to check it out. Um, essentially is a package that lets you expose that functionality in your code right? So hooks is not so much meant for user land code as it is for either like package level code. Or places in your application that need sort of extreme flexibility. Um, and so it kind of comes in 2 parts. The first is closer to what Caleb and I talked about um, where essentially you just drop a trait onto any class right.

46:09.77
Chris Morrell
And then inside that class you can make ah calls to like this call hook and you pass it a name and you pass it any number of variables. Um, and that just. That becomes an extension point in your class right? So like the example that I've used is um, you know you you might have like a request somewhere in the the request response lifecycle you want to want to let people like. Hook in at the request side and then hook in at the response side. So like you would expose a call hook right? before you pass the request through your application and then you would add a call hook after. You receive the response that you're going to return to the user and now you have these like 2 points in time. Um, that ah that that like are extensible. Um and then on the flip side a ah consumer of that Api would. Call like you know Router Colon Colon hook um and that gives them back an object that lets them call each of those extension points and the cool. The the reason that it's sort of it gives you this object that.

47:33.49
Chris Morrell
Covers all the hooks inside of a given class is is this is something I would have never thought of but but Kala pointed out a lot of times you need to like orchestrate things between different hook points. So for example, like in that request response ah lifecycle stuff. Um. Ah, really good example would be like request timing and with request timing you want to like grab the times stamp that the request came in and then you know you calculate the difference between the timestamp. But when the request the response went out so you need the original value to so being able to kind of to. Define all of your hook calls together for a given class gives you the opportunity to kind of orchestrate between them in an interesting way. Um, and it it handles. There's there's also some stuff around just like needing to handle data into the hooks and data back out of the hooks that I won't get into. But um, the thing that I realized was that same concept is kind of perfect for this view problem because now in your view. You can just put like xhook give it a name and pass it as many properties as you want and. In your application. All you do is view Colon Colon hook you pass the view name as the first argument and thanks to the incredible larall idea you get view name autocomplete on that call for free. Um, and then you just pass it the name of the hook that you're hooking into um and.

49:05.20
Chris Morrell
Ah, closure and now you can hook into that point in time and if you don't pass it a closure. You can just pass it a view and that will render that view in that location or you can actually pass it anything that implements the Html interface. Um, and so the reason that. Feels like such a good solution to this email problem is um, kind of going back to the original requirements. In our case, we know that um, kind of going back to to it's North Carolina right that has the the black updates. Um.

49:43.40
Skyler Katz
Yep North Carolina

49:43.81
Chris Morrell
Going back to this North Carolina situation North Carolina has has a requirement that no one can take courses for continuing education during these these blackout periods. Um, and we need to present that in. Um. You know if someone's in the middle of a course we we may need to present that to them like oh you started the course but like you need to stop until the blackout period is over or if someone's trying to start a course we need to present it to them or if we're sending someone like ah an email about a course like a course reminder. We we may need to check like normally we would send out a reminder now but is this about is this person licensed in North Carolina maybe we need to hold back like there's a bunch of different places where that logic that same single piece of logic impacts different parts of the app. And so being able to essentially have a single class that holds all of the North Carolina licensing logic um that basically makes the call once like does this blackout date stuff apply to the active user. Um. And if so it can hook into the email view and it can hook into the reminder logic and it can hook into the like course start view and like all it can hook into all of those places. Um, you know that's that's like the.

51:17.31
Chris Morrell
The power of this like inversion of control like you've you've given you've you know, sort of rescinded control of these points and said like someone else is going to know better What to do here and now we have this nice really really focused class that um only has to do the logic Once. Ah, we can coordinate that with like a parent object that ah runs the logic for all these different licensing bodies. So to the degree that any of that logic is shared um you can handle that in the parent and you're not having to do extra data Loading. So It's like it is really powerful I think and I. And I think it's great for this this circumstance and I think it's It's potentially going to play out to be a really good way to handle these scenarios where you just don't know you know that this isn't going to need to be changed. But the number of different ways that it could go is just too hard to reason about you know you kind of need to break it up into rational chunks. Um, you know it's all theoretical right now we haven't actually implemented it So You know we may do another episode in a month being like.

52:28.19
Bogdan Kharchenko
Sure sure.

52:32.25
Chris Morrell
Well, we were wrong about that.

52:36.28
Skyler Katz
So I mean I I will say too that like the way that this was solved originally in the code that's still running today is massive numbers of if statements in Thousand line files and it works but it's very hard to reason about and so um. You know we like we've experienced the pain of what this is and are trying to figure out what a different solution is and so um, it's if statements worked for for many many years but time to to try something different.

53:00.36
Chris Morrell
Right.

53:09.00
Chris Morrell
Absolutely yeah, this.

53:13.71
Bogdan Kharchenko
So I have.

53:14.15
Skyler Katz
Um I don't know that I would be like let's use hooks in my weekend project I mean maybe but it might just be more confusing.

53:20.49
Chris Morrell
Right? No I Think that's that's kind of the thing that I keep on coming back to is like this is not the right solution for most people right? Don't don't jump to using hooks because it's like it is. It's adding a layer of complexity that you. You probably don't need unless you're dealing with these like really really large scale. Ah conditional situations you know or you're building something that like if you're building something that should support plugins I think is ah a great is a great option and you should check it out for Sure. You know.

53:56.57
Skyler Katz
Totally.

53:57.47
Chris Morrell
But sorry Bodin I cut you off. So.

54:00.19
Bogdan Kharchenko
No, no, no. Um so I have 2 questions one in this example of you know, kind of pre-computing this North Carolina Data for the view. Maybe the mailable or wherever the thing is you know like where would that code be called right? Is it like. And the app service provider somewhere or like in a controller it gets computed for all of those like their macros I'm assuming and all these um you know logic trees or whatever they are. Are basically right there and then computed or it just gets passed to that view or whatever else and then it gets called and that's where the computation actually happens does that make sense.

54:43.82
Chris Morrell
Yeah I mean Yeah, yeah, no, it totally does I mean I think we may be getting in the weeds a little bit but I'm happy to go there. That's that's kind of the point. Um, so I think that um the the approach that I imagine.

54:48.98
Bogdan Kharchenko
Sure.

55:01.52
Chris Morrell
Is that you would have like a singleton orchestration object of some sort like ah you know, ah registry of all of the different like extenders or whatever you want to call them. Um, and. That singleton object is going to be something that like internally memoizes what has been called and whether like whether things have been called or not like what its current state is um and like you'd need a way to reset it because like. in in a lot of cases. It's going to be just like 1 user inside of a request lifecycle and you don't have to worry about it. But if you're like looping over a thousand users. You need to be able to reset that state between each user or like a thousand circumstances there needs to be some function where you can kind of just like wipe that slate clean, but in general. I would imagine. Yeah you have this like single object that internally knows what's been run. Um, and so then in your controller you just like load that object out of the container. Um and just call like a ah method. That's like. Make sure that everything has been run either run it now or like if it's already been run then you're good to go. Um, you know some sort of just like register hooks method and if the hooks have already been registered then that's just a no-op. Um, if they haven't it registers all the hooks. But.

56:28.38
Chris Morrell
Essentially yeah, that's kind of my idea is as close to the point where you you know you're going to need one. Um, you would just call that and that way you're not like executing all this logic all the time you're only executing it if ah if you need it right. And yeah, it's going to be you know I think um, caching or memoizing in different ways like the the logic of which hooks need to be registered for any given user any given scenario like the tradeoff there is going to be tricky because. It is really dynamic. Um, but it's also very complex because like I said there are just so many different licensing bodies. Ah and any given user can be in want of many different so circumstances. So like that's going to be a challenge for us to solve. But. I think that's ah generally a good pattern for this type of approach that feels right? where you're just like you kind of have 1 parent object that's responsible for um, initializing all of the the objects that actually register the hooks and that way each. A sort of child object is responsible for just doing its own logic. Um, but you still just have like 1 thing to interact with you know? um.

57:55.47
Bogdan Kharchenko
So I see okay that makes sense and I guess one other question about hooks and you know that's that's all I got for you Chris um, you know all the positive things that you've said about wordpress and the negative things about wordpress hooks. You know, like what is the likelihood of getting into that same trap that wordpress kind of has where you know you you can install say a package and it's also using hooks and you know maybe it's injecting something into your template that now you don't want you know and. You know like do you want somebody to just say like yeah oh you're using hooks for your footer. Let me just put something into that footer. Um, you know like could there be a situation like that where then you're like scratching your head how to disable. You know some sort of automatic script loading or something like that.

58:44.18
Chris Morrell
Um, yeah I mean I think on one hand that's like that is just a fundamental problem with like a pluggable system right? If you are if you're installing a plugin that executes within your application like you're just taking on some some risk or you're taking on like. The choices that the author of that plugin made right? And if you don't like the choices that they made like you either have to um you know, try to get them to change it or find something else or fork it or what you know?? whatever? Um, so you know I I think you're right? that. That extensible systems just have that problem I think from my perspective the thing that makes wordpress hooks so awful to work with is that that is the primary interface for everything. Um.

59:39.57
Bogdan Kharchenko
You Whether this is just like sugar coding some stuff within your application.

59:40.11
Chris Morrell
I don't think well I I just think there are places where using a hook feels appropriate. Um, and there are other places where it doesn't and I think for for a bunch of probably. Perfectly reasonable reasons you know wordpress kind of went down this path of everything is a hook and every time we need a new extension point. We add new hooks because this is the way things are done um, but I don't think that that would be how you'd build an application like that today I think you may still. You probably would still want to have those same types of extension points I think like this hooks concept is really great and you know like we're probably going to add it to verbs. We're probably going to use it in our app like I think it's a good idea but I don't think it's the right way to extend. Everywhere right? and just like in in larall like in larave you could like you you could say ok if you want to change if you want to add the ip address of the the. Requesting user um to the the payload of any job that gets queued right? and a re a reasonable thing would be okay, we'll just write your own um queue driver. You can extend the wordpress one and just override the the um.

01:01:17.12
Chris Morrell
The method that generates the payload and call the parent generate payload and then just augment that and that's like that's a fine approach. Um, but it's not a good approach like ah Laravelle decided to like expose ah create payloads using. Helper function. Um, exactly because like you want to do that often and you don't want to have to like own your own queue Driver. Just so that you can add a little bit of data to the queue Payload and so I think hooks is exactly that It's like lots of times. Ah, just registering a different implementation of a specific class or just passing a closure somewhere or you know there's a lot of other ways to extend code that are often better. Um, and so you would just use hooks in the places where it really made made sense like that would be my. My take.

01:02:18.49
Bogdan Kharchenko
Yeah, that sounds like a compelling you know mechanism to hook into your system. Yes.

01:02:26.60
Chris Morrell
There you go So The question is if we go back to the very beginning like are we ah are we ever going to ah put some. Eloquent driven conditionals inside of a should render moving forward.

01:02:50.73
Skyler Katz
Depends when you're on vacation.

01:02:52.54
Chris Morrell
Ah, oh no.

01:02:53.77
Bogdan Kharchenko
Yeah I mean I think what we should do is you know we just put a hook call in there and we just dispatch this hook thing and have should render you know call that hook function and whatever wants to render it or doesn't want to render it.

01:03:07.23
Chris Morrell
There you go.

01:03:12.89
Bogdan Kharchenko
You know we can just yes.

01:03:14.14
Skyler Katz
Ah, the worst of both worlds that's Bogman's approach

01:03:14.80
Chris Morrell
Can we even better. Can we add a hook and then register an event dispatcher inside the hook so that you can listen for that event and and trigger something that then triggers the hook to trigger the should render to. To Return False think about it.

01:03:36.72
Skyler Katz
Absolutely.

01:03:37.69
Bogdan Kharchenko
I Love it. It's It's certainly overineered I'll say that. Ah yeah I Honestly don't know. Yeah I Honestly don't know if you know there is a concrete answer I feel like all of these things have their pluses and minuses and.

01:03:42.88
Chris Morrell
Ah, oh man. Yeah I was a fun one.

01:03:55.40
Bogdan Kharchenko
You know maintenance cost and you know just lifecycle stuff So I don't know it's It's a really challenging hard. Yes, or no, so.

01:04:01.86
Chris Morrell
yeah yeah I know Skylar. Do you think you're going to be using this pattern in your own stuff now.

01:04:09.87
Skyler Katz
I mean I think I I don't know ah my my my code writing outside of work hours is like you know close to zero because I have a two year old who is like dad stopped being on the computer.

01:04:21.75
Chris Morrell
Sure.

01:04:26.83
Skyler Katz
But um I I you know I figure like should render is in the framework like at some point Taylor merged it. So I feel I mean it's not documented but I I like should render over some if statements and I definitely think in in. Any work that I'm doing that's not Editor Natchi like it's just probably not big enough to warrant using hooks. Um, it's like I'd probably still stick to should render. But I you know my app has 0 users so doesn't matter.

01:04:50.50
Chris Morrell
Right.

01:05:02.10
Chris Morrell
Ah, yeah I mean honestly since since we first had this conversation I mean I I have I've definitely found myself leaning towards um like blade only components. Um, but I was thinking like I merged in 2 blade components that like at the root have an if statement since since we had this initial conversation. So it's like clearly I have bought into this idea I can't remember where they were but um I don't think.

01:05:22.38
Skyler Katz
Is.

01:05:33.11
Skyler Katz
Is that.

01:05:40.55
Chris Morrell
I Don't think there's anything wrong with it I think that like yeah being able to just drop in a blade component and know that it's going to. It's going to do something if it needs to is great. Um, it's just like how how far down that path. Do you go.

01:05:55.35
Skyler Katz
Yeah I think if it was a new project if it's a new project I think I would use should render I recognize if you're in an existing project that has a format like introducing this new thing in 1 place that then you don't use anywhere else like that. Can feel bad. Um and in confusing because you're I don't know where I don't know where to look for this. So.

01:06:17.80
Chris Morrell
Right? Yeah,, That's I mean that's fundamentally what it comes down to is like you have to pick your conventions and stick with them even if like even if sometimes you bump into something where it's like well arguably this could be a little better doing it a slightly different way. But it's like is it better enough to force people to have to figure out like the difference this one time. Um, probably not you know unless it really is and then and then you do it right? like? um. That's definitely a piece of it as well.

01:06:55.15
Skyler Katz
Or Chris just goes away for a weekend and comes back with a hey guys check this out. Let me show you this package that I wrote at 2 a m.

01:07:02.90
Chris Morrell
I I like I I showed Skyler I was like I call him up on tuple and I'm like what do you think of this as a solution to this problem and he just like is quiet for 15 seconds and then he's just like. Your brain works a totally different way than mine. So.

01:07:20.89
Skyler Katz
Yes, like where we just think so differently and like you called me up I don't know this tuple is like 10 a m on a Monday I was just like what is happening I haven't even finished my coffee yet, you're just dropping drop and hooks hooks you are.

01:07:21.35
Bogdan Kharchenko
Yes, welcome to the club skylet.

01:07:33.84
Chris Morrell
I was so jazzed I was so jazzed.

01:07:39.77
Skyler Katz
Was cool I was still also in defensive mode because we were still going back and forth about my Pr you know so I was like ah I don't know but I do I do think hooks will be better for for us in this context.

01:07:41.63
Chris Morrell
Sure That's fair.

01:07:43.80
Bogdan Kharchenko
Yeah.

01:07:51.70
Chris Morrell
Nice, Well is there anything else. Ah that we want to touch on before we call it or or any non non view hook related stuff that that's on your mind before we call it a day.

01:08:05.14
Bogdan Kharchenko
No I think we could have covered everything.

01:08:08.93
Skyler Katz
I Think we're good.

01:08:09.17
Chris Morrell
All right? We'll see how this ah this whole video thing goes. Maybe there'll be ah all I'll selectively clip some some bits that make me look really good and and post them on Twitter and it'll be great. You'll you'll love it.

01:08:12.72
Bogdan Kharchenko
Yes.

01:08:23.95
Skyler Katz
Perfect, Great! Great! Well bogged and maybe you should take the headphones off put on your your cowboy hat you know.

01:08:28.69
Bogdan Kharchenko
Oh yeah, that's right? Oh my god.

01:08:29.97
Chris Morrell
Oh yeah, yeah, you got to put the hat on for the last minute we told ah bogden that he needed to bring his cowboy hat and he he actually showed up with it. But then he couldn't couldn't use the headphone. So.

01:08:37.15
Bogdan Kharchenko
Yes, um.

01:08:44.64
Bogdan Kharchenko
Yeah, unfortunately they don't make Cowboy had headphones compatible so they're probably called Airpods. Um.

01:08:48.63
Chris Morrell
I I bet you they do actually I bet you somewhere? Ah right? yeah.

01:08:57.59
Skyler Katz
Yes, you know those ten gallon hats though that you know some of those some of the the westerns have.

01:08:58.78
Bogdan Kharchenko
Yes,, let's overengineer headphones for. Ah, yes.

01:09:07.78
Chris Morrell
Ah I Still think that I bet you somebody has has made like over the ear headphones that work with a cowboy hat because like it's just got that that has to exist in the world right? and.

01:09:19.76
Bogdan Kharchenko
Yeah I mean it must because yeah I mean it must because you go to Texas which is where I got this hat and like every other person has a cowboy hat and you think to yourself like how did they not like how do they wear like you know the big headphones like there. There must be a solution.

01:09:21.80
Skyler Katz
Um, enough country music stars.

01:09:38.67
Bogdan Kharchenko
Someone's out there just missing either on lot of money or is already super rich from this idea.

01:09:41.56
Chris Morrell
There you go? Well if it doesn't exist now we know what the next side hustle is.

01:09:48.94
Bogdan Kharchenko
Yes, all right guys.

01:09:48.98
Skyler Katz
Perfect.

01:09:52.43
Chris Morrell
All right? Well Ah, until next time.

01:09:55.98
Skyler Katz
See up.

01:10:05.14
Chris Morrell
And with the video everyone gets to watch us wait for the outro music all right see? Yeah oh no I said see and then you were talking.

01:10:11.43
Skyler Katz
You know when do you cut it. You know.

01:10:14.21
Bogdan Kharchenko
I get.

Creators and Guests

Chris Morrell
Host
Chris Morrell
Father of two. Mostly talking about PHP/Laravel/React on Twitter. He/him.
Skyler Katz
Guest
Skyler Katz
YIMBY | PHP | Improv | Cycling | Civics | He/Him
Handling complicated view logic w/ Skyler Katz & Bogdan Kharchenko
Broadcast by