Two seasoned salty programming veterans talk best practices based on years of working with Laravel SaaS teams.
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:07):
And this is Aaron.
Many years ago I became a Microsoft Certified Professional.
Joel Clermont (00:20):
Ooh.
Aaron Saray (00:20):
Yeah, it was Windows 2000 server.
Joel Clermont (00:25):
Wait, I don't see it on the wall behind you, Aaron. You don't have it framed?
Aaron Saray (00:29):
No.
Joel Clermont (00:29):
No, okay.
Aaron Saray (00:30):
No, it's in a booklet somewhere hidden away from anyone. I wasn't really going to tell anyone until this podcast, but one of my favorite things about that class and those set of learnings and everything we did though was the whole roles and permissions and all those different things that you learn about in Windows. Then using bitmask maps and all those different things and just really getting into that. Then I remember when I moved to PHP there wasn't much of a system like that available.
Joel Clermont (01:05):
Yeah, it was totally different.
Aaron Saray (01:07):
Yeah, you kind of had to roll your own for everything. Laravel came around too and it's not built-in per se, there are some permissions stuff. But there's that roles package that we use by Spatie, or whatever their name is. I always forget how you pronounce that. I love using that because then I can finally get back to using my whole roles and permissions and setting those things up. I think we've kind of talked about that before.
Joel Clermont (01:35):
Sure.
Aaron Saray (01:35):
You know, how we really like that. But there's something about that that really kind of grinds my gears or bothers me a little bit when I see certain people implement this in certain ways.
Joel Clermont (01:46):
Okay.
Aaron Saray (01:47):
And it's, if you are going to go and hard-code into the code your checks for permissions by their name, like can update this blog post or can sell this product, or whatever. But then you allow permissions to be added, created, and deleted via a web interface.
Joel Clermont (02:07):
Okay, like pick a lane. How are both of these things supported? Is kind of what you're saying.
Aaron Saray (02:13):
Yeah. If you're going to do something via that web interface, it's way more complicated than just picking and creating them and aligning them. You have to have a whole bunch of infrastructure inside of your product, inside of your code base to understand that all the roles and permissions and all those sort of things are dynamic. You'll really never ever have a situation where you can hard-code in some stuff if you can dynamically create permissions.
Joel Clermont (02:42):
All right. Yeah, I'm tracking with you. Because you're right because the permission check has to be done in code. I was trying to think if there's like a fancy way to do it. I guess you could go really nuts and have a UI for mapping routes to permissions or something, but that feels even worse.
Aaron Saray (02:57):
Well, yeah, and then you'd have to do routes and you have to do specific... not everything, not every permission is to a route.
Joel Clermont (03:05):
Yeah, it's more granular. A lot of times it's like, you can do this thing to this resource not just access that route.
Aaron Saray (03:11):
I get why people might think they want to do that because it takes away... Maybe it's easier if you make it as a dev tool for yourself.
Joel Clermont (03:18):
Sure, yeah.
Aaron Saray (03:19):
That you can just add some permissions. Because you're putting stuff into the database, especially with a lot of these systems, the one we use. But that's really not a great idea and there's one core reason why I kind of go back to that. Which is, when you go and make your product and you hard-code in the names, which is what we do a lot, then it is almost basically required that you have that sort of information available at the time that that code is deployed or right when it is. Right during the migration or the deploy step or something like that. So you'd really have to deploy your code and then immediately be clicking boxes in the UI. And I don't know about you, but I'm normally not hovering with my finger over a button waiting for the code to be deployed and clicking something else.
Joel Clermont (04:07):
Yeah. If only there were a system for making database changes when we roll out new code. That's what you're saying.
Aaron Saray (04:14):
Yeah. Thanks for that, you leading me up to that. A lot of times when we do our deployments we'll work something like that into the migrations. There are other packages and services out there where you can run one-time commands and stuff like that too. If you're going to do something like that, that's fine. Like, the one-time command during deployment. But we just normally put them in our migrations. And the reason is because it is a database-based thing that is important for our app to be able to function correctly. That's really what I think the migrations are. They're a database manipulation tool for our app to function correctly. So when we create new permissions or change roles and permissions and all those different things, we'll do that a lot of times in a migration. Which I think is pretty unique to a lot of projects I've seen.
Joel Clermont (05:06):
I'm sure there's probably somebody yelling at the computer right now or MP3 player right now. Because there's a whole debate, like is it weird to put data seeding? Essentially that's what it is even if you're not using a seeder in a migration. But I like your clarification because it's like it's not just data. Like, we're not adding users but it's like, "This is critical data for just the core functionality of the system." As you were talking, production for sure, it's important. But even like local dev environments, right? You build a feature, Aaron, that adds some new permission. So what? The next time I check out the code, I'm supposed to remember that or go check that box in my app? If it's a migration, I just run the migrations and I get that data. We all kind of stay on the same page, so I'm with you.
Aaron Saray (05:56):
And just to be clear. We're not talking about putting them in seeders. That is an option that some people have reached for but this is really about... this is something that's core, that's actually a mix between our database and our code. So when you're doing something like seeders that generally is something, I don't know that isn't necessarily a 100% required for the code to run. It may run but be limited. So if you're going to add zip codes or something like that you could put that in a seeder because the code will run, it just won't find any zip codes. Maybe if you have a zip code lookup. Whereas, if the permission is missing and someone visits it's going to actually be an error, a 500 error.
Joel Clermont (06:38):
Yeah, we're in such agreement here. Are you ready for me to throw a question back at you?
Aaron Saray (06:45):
Ooh, give it to me.
Joel Clermont (06:46):
Not that you would ever do that to me on the podcast, so I just... anyways. But, okay, let's say somebody is fully on board with permissions. Because you're right, the fact that they have to be implemented in code I can see a much stronger argument for not having a UI for that. But what about roles? The idea, "Well, our business is changing all the time and we don't want to have to open a ticket and have a deploy every time somebody invents a new role or wants to give an existing role access to a new permission." I don't think we have the code argument there, do you have a strong argument why we wouldn't even recommend a UI for defining roles and assigning permissions to roles?
Aaron Saray (07:29):
I mean, I don't have a strong argument except for you probably aren't doing it as many times as you think. If you had to do it once every two months-
Joel Clermont (07:40):
That'd be a lot.
Aaron Saray (07:40):
... it seems like a lot but at the same time, there's a lot of code required to make an interface to test it, to do all these different things. Then the safeguards of having someone who is unfamiliar with the system maybe undo things and bring down functionality for that. So I would say, in that case, if that's really an issue, prioritize those as tickets that get done or whatever, as part of this system. So I don't have a strong argument against it I guess. I can't use the same things but it just doesn't seem like a great idea.
Joel Clermont (08:17):
Yeah. I mean, it kind of aligns with one of the reasons I gave, which was consistency between environments, right? It would be a little weird if production has all these roles and permissions assigned to them and then locally as the developer, I don't have that, or I'd have to go recreate that. Like, "Hey, we got a bug in production and it's this guy with this role with these 74 permissions". Like, well, now I have to go create all of those mappings and stuff. So I like your idea, it doesn't happen as often as you think. But I also think that it leads to some potential inconsistencies and really authorization is kind of a key part of a system. So having that bespoke for every developer on the team and maybe between staging and production like that, it just doesn't seem great to me. Even though I can see the appeal of being able to do it ad hoc for those cases where you want that.
Aaron Saray (09:10):
I think that that makes your testing, your unit tests, infinitely more complex but also in the same way less accurate. Because you're testing that if it is properly configured there's no access to this thing, but who's to say it's properly configured?
Joel Clermont (09:27):
Yeah. I'm just thinking too, like the way we write our tests. First of all, just to not give the wrong impression, you never check for a role in your authorization layer, you check for permissions. However, I've noticed when we write tests, we might say something like, "Test Admin can do thing X and test Captain can do thing Y." So you use those terminologies, first of all, it gives you quicker setup in the factory when you're creating a user of a certain role. But it makes the tests more readable. You could do all of that purely at a permission layer without using roles but there is something nice about having conceptual roles baked into the system. And you lose that if you allow them to be just like ad hoc edited in a user interface somewhere.
Aaron Saray (10:12):
Yeah, I think really comes down to, I would say, no UI for creating, editing, or deleting permissions. And really consider if you actually want to open that can of worms for the UI for creating, editing, and removing roles. You probably don't.
Joel Clermont (10:30):
Just one kind of last small question. What do you think about a user interface or just seeing what the roles and permissions are? Do you have any feelings about that?
Aaron Saray (10:42):
Yeah, it's a great idea.
Joel Clermont (10:43):
Well, that seems very reasonable of you, Aaron. And I'm glad that you finally conceded one point to the roles and permissions of other people.
We live in the great state of Wisconsin. I don't think that's a big secret, it's on the footer of our website. And one of the things-
Aaron Saray (11:02):
Now that you know.
Joel Clermont (11:03):
Yeah. Now, in Wisconsin, we're known for things like cheese and custard. And there's Culver's, which is a chain around here and it's kind of spread out in the US. But on there, they have a different flavor every day so when you drive past it there's the name of the flavor of the day. We started a game in our family to make outrageous versions of the names of the flavors. For example, the other day they had a flavor called OREO explosion. I say, "You know, what's even better than an OREO explosion? Is like OREO industrial accident." Or something just like going OREO devastation. Just like, whatever it is take it to the next logical extreme.
Aaron Saray (11:47):
I don't think I've done that. But I do remember back in the day before the internet was big, my grandma would get to, I think it was a newspaper, that had the week's worth of Culver's sort of things. She would cut it out and then she'd hold it in front of us and be like, "If you're good one of these days, we'll get one of these flavors." And say you had to be like, "I want to be good because I want chunky Rocky Road on Thursday," or something.
Joel Clermont (12:16):
No, what if it's a flavor you didn't like? Like, "I'm just going to be as bad as I want today, I don't even want it."
Aaron Saray (12:20):
There's no flavors I don't like.
Authorization and permissions are pretty tough, but you know what's even harder sometimes is validation. I wish there was a tool that could help me with that.
Joel Clermont (12:33):
Oh, Aaron, do I have the tool for you? Head over to masteringlaravel.io and up in the menu, click on validation. Why don't you try out that validation worksheet? You might love it.