Move that logic out of your view
Joel Clermont (00:00):
Welcome to No Compromises, a peek into the mind of two old web devs who have seen some things. This is Joel.
Aaron Saray (00:08):
And this is Aaron.
Joel Clermont (00:16):
I always enjoy getting such good advice from you, Aaron, and pull request comments.
Aaron Saray (00:21):
Here we go.
Joel Clermont (00:21):
You never get frustrated or say, "Joel, why would you ever do that?" It's always just constructive feedback. I joke, but I was looking at a pull request recently and I thought the subject of the discussion might make for an interesting topic today. Because it was around testing... Well, not really directly about testing, it was more about where to put logic. And really I think your principle was to try to keep logic out of the blade view and try to keep it more in the controller action. I'll set up the scenario and we can talk through the specifics of it and then I think it'll come back around to testing. That's kind of what I took away from it.
In this particular case, I don't have to get too detailed with the requirements, but basically, we wanted to show an alert on the page in a specific scenario. In this particular case, if we were looking at a page that had to do with a certain part of the country, then show this message that something had moved and where to find it. In the blade view we used includeWhen, which is a really nice little helper, and brought in a partial, passed in a message. It worked great. And what did you say to that approach, Aaron? What was your feedback? Do you recall?
Aaron Saray (01:48):
Yeah. I said, "Excellent. Let's go."
Joel Clermont (01:51):
Aaron Saray (01:52):
No. To fill in a little bit of context here, that includeWhen is a logical sort of thing but I want to look at stuff as very simplistic. If we're going to do ifs or control loops inside of a blade, it has to be the simplest version of something, right?
Joel Clermont (02:11):
Aaron Saray (02:11):
In order to do this custom message that would appear on this blade file, we have a couple different types of decisions that we can make that will determine whether we're just going to show this message or not on the blade. The first one, and that includeWhen, is probably some sort of logic where it was like, well, I mean... It was a state so we're matching a particular state. If this object is in this state then includeWhen, when that is true do this. Okay, that makes sense. And inside that partial was maybe the hardcoded message or something like that. Because it was just a special one-time off thing. It was going to be there for a while but it was just a one-time sort of message.
Joel Clermont (02:58):
Yeah. There was an alert component we already had used, which accepted a message. But you're right, the message we were passing into that component was hardcoded in the blade view as well.
Aaron Saray (03:08):
The one logical sort of thing that we have in our view was if something we know about our model or an attribute of our model is of a certain state or value, then do this thing. I find that interrogating the models specifically like that can be a little bit too much logical intensive, too much business knowledge even, inside of our blade files. In our blade we want to actually display a view, we want to display things. We don't necessarily want to do too much logic. I mean, simple, very small ifs. Like, if this is there, then do it, if there's a loop of these then show the loop. But I don't want to have complex sort of business-related things. And I looked at this statement as or is this message is more of a business-related thing. If it's, "Our business says if you're in this state, then you have to follow this sort of alert," or whatever. It was a little bit more of a just a, "Hey, does this exist? Yes or no," it was something more specific. When I see something like that, I want to see that moved a little bit further up into an area where we deal with logic, like the controller.
Joel Clermont (04:16):
Right. In this case, it was a very simple change, but basically the conditional, "Are we in state X?" moved out of the blade and up into the controller, and then it passed. So it said, "If we're in state X, then the message equals X, Y, Z," and pass that into the view. Then we still had an includeWhen in the view but it was, "Do we have a message or not?" And, "If we don't have a message, don't show it. If we have a message, show it." It might seem like kind of splitting hairs, but your point is business logic versus presentation logic. The business logic is, "Am I in state X?" The presentation logic is, "Should I show a message or not?"
Aaron Saray (05:04):
Joel Clermont (05:04):
I liked the suggestion. I think it might've been the first time you actually had a good constructive suggestion for me in a PR, normally my code is so perfect. But it was a little treat for me. No.
Aaron Saray (05:19):
Joel Clermont (05:20):
But I want to talk about a secondary benefit too. Because this might seem arbitrary, like, who cares if you have a little bit of business logic in a blade view? It's not going to break anything.
Aaron Saray (05:34):
Joel Clermont (05:35):
Who cares? Aaron cares.
Aaron Saray (05:38):
Joel Clermont (05:38):
Okay. But another side benefit other than making Aaron happy was testing. We typically like to test, you know feature tests, and mainly there we're looking at the controller and kind of side effects. But we don't go real heavy with blade tests like assertSee or assertSeeText or things like that. Like, we do it occasionally but we try avoid it just because it tends to be, I don't know, a little brittle. It's kind of a more verbose test. In this case, I was actually able to do a much better test just looking at the controller and what it was passing to the view without having to make assertions about what the view was doing. I felt like that was another nice side effect that came out of that too.
Aaron Saray (06:26):
Yeah, instead of rendering the view in that particular instance and seeing if you saw the message inside of it, you could just check a certain view has that message. Or make sure it's not empty or make sure there's a value in it. I get that, yeah. I think the final sort of benefit, I want to wrap it up here real quick, is that the logic we had in that custom sort of message was based off of a state but the placement of the message made sense if there was some sort of alert for that page. It wasn't like hidden somewhere, it was right at the top. It was sort of place that you might put in an announcement anyway.
And by moving some of that logic out and just using that custom message sort of variable, now if we are in, let's say, a different state and there's a different message, we can pass in a message in that custom message. So we've now moved our logical stuff all into that one controller instead of having to write multiple ifs inside of that blade. Like, "If there's this scenario then display this message, if there's that scenario display that message." Instead, we handle setting the message in the controller and the blade is much simpler. It says, "If there's a message, I'll show it."
Joel Clermont (07:41):
No, that's great. Another benefit.
Aaron Saray (07:50):
I'm of the age that I kind of grew up with grunge music and then Korn and those sort of nu-metal rock and stuff, so I always had like a little soft spot for them. But that's when you're 18, you're 20, 25, whatever. And time goes on, music changes and whatever. I'm preparing myself for those to be called oldies.
Joel Clermont (08:13):
Aaron Saray (08:13):
I mean when you think about it, the oldies that we grew up with were just our parents' music.
Joel Clermont (08:19):
Yeah, like Led Zeppelin.
Aaron Saray (08:20):
We're not that oldies but, yeah. I don't really think about this too much. But the other day I was in a local coffee shop and I'm listening to it, and it's the edited version. I'm listening to some music and it's playing in the background. I'll say the edited version. But it was really slow, sort of relaxing and it was like, "I wanna... you like an animal."
Joel Clermont (08:44):
Aaron Saray (08:47):
And I was like, "What is going on? Why does this sound familiar?" Turns out it was a slow version of a Nine Inch Nails song playing in a coffee shop. And I was like, "What is going on here? This used to be the crazy music that we listened to as kids and our parents hated," or whatever. Now it's the background music inside of a coffee shop.
Joel Clermont (09:06):
It was like the smooth jazz version of the song?
Aaron Saray (09:08):
Yeah. Well, it was not even smooth. It was like, you know how folk singers do covers of stuff?
Joel Clermont (09:14):
Aaron Saray (09:14):
It was just super slow and just... I'm like, "What?" And people are just sitting around, I'm like, "Does anyone notice this?" And I mentioned it to the barista who was also the owner, and he was like, "Yeah." He goes, "It's my favorite playlist." He knew what he was doing.
Joel Clermont (09:32):
Well, I'm going to keep an ear out next time I'm in an elevator to see if there's a Korn version of Muzak in the background.
Aaron Saray (09:40):
Oh, it'll be juvenile. "Back that thing up."
Joel Clermont (09:42):
Aaron Saray (09:43):
But playing in an elevator.
Not everyone likes a podcast, maybe you've just stumbled here by accident. Maybe YouTube's more your thing.
Joel Clermont (09:56):
If you want to check out our YouTube channel, head over to masteringlaravel.io, down in the footer, click that YouTube link.