Migrations, Factories, and Seeding, with John Bonaccorsi
Matt Stauffer:
Welcome back to Laravel Podcast Season Four. Today we're talking to John Bonaccorsi, lead programmer at Titan about database migrations, factories and seeding. Stay tuned.
Matt Stauffer:
All right, welcome back to Laravel Podcast Season Four, where every single episode is about a specific topic, and today we are talking about migrations, factories and seeders with my friend, the factory king, John Bonaccorsi. John, other than being the factory king and my friend, could you introduce yourself to the people?
John Bonaccorsi:
Yeah, absolutely. My name is John Bonaccorsi. I live in New Jersey with my wife and my golden retriever. I am a lead programmer at Titan, which just means that the host of this podcast interviewing me right now is also my boss. I have been informed that if this episode does not perform well, I will be fired. Please do not-
Matt Stauffer:
There's going to be consequences.
John Bonaccorsi:
Please don't tune out because my job depends on it.
Matt Stauffer:
In Peter Pan they do that, where people had to do something for the fairy to live? Did they have to clap or snap or something?
John Bonaccorsi:
I think you're more of an expert on that than me but ...
Matt Stauffer:
Oh my goodness, do you call me Peter Pan. Now, I have to look up-
John Bonaccorsi:
Having kids I...
Matt Stauffer:
... Tinker Bell.
John Bonaccorsi:
It's been a while since I ...
Matt Stauffer:
That's true. My kids did watch it. I watched it with my kids. Hold on, Peter Pan, Tinker Bell, how do you even Google this? Bring back to life maybe. I'm not really curious and they told all the kids who are watching, "You need to do blah, blah, blah."
John Bonaccorsi:
I thought they need to clap or something like that.
Matt Stauffer:
That's what I was saying. It's like something clap. Don't let Tink die, clap. Yep. All right. Yeah, so anyway, if you want John to keep his job and you're listening to this right now, whenever he says something really smart, just clap in your car, in your crowded office. I guess it's COVID, so it's not a crowded office. But at the bus stop or whatever, clap and that'll help him keep his job.
John Bonaccorsi:
Matt will hear it. Yeah.
Matt Stauffer:
Yeah, I'll hear it. I'll hear it wherever I am. Even if I'm sleeping, I will wake up and I will hear the clap. My microphone is not staying up. Okay, cool. Cool. Cool. John, if you ... We're talking about three individual topics, which is totally unfair, because I'm going to ask all these questions to you three times.
John Bonaccorsi:
Sure.
Matt Stauffer:
But for everyone who doesn't know, migrations, factories and seeders are database related. I didn't want to do them as the same as the database, because I really think they deserve their own treatment, and there are some ways that they are often used in spaces that are the same, but it's really three different topics. I'm going to have to ask you the five year old question for all three of them. Let's start with migrations. If you had to explain database migrations to a five year old, how would you do it?
John Bonaccorsi:
I'm going to try. I'm glad I'm getting this question three times because it was my most dreaded question.
Matt Stauffer:
Oh, yeah, great.
John Bonaccorsi:
The cynical answer to me was, I would never try to explain this.
Matt Stauffer:
Yeah, that's true, touché.
John Bonaccorsi:
I feel like the majority of people, they start answering it like as a 22 year old, so I'm going to do my best here to really answer this like I would answer for a five year old. Bear with me, it might be nonsense.
Matt Stauffer:
Do it for the claps. Do it for the claps, John.
John Bonaccorsi:
There we go. All right, so migrations, if I had to say migrations for a five year old, I would say that similar to how you have a booklet or a guide that teaches you how to build things in Legos and stuff like that, migrations are just like that, where the Legos are synonymous with the pieces of your database, and migrations are the instruction booklet about how to build it.
Matt Stauffer:
That's really good.
John Bonaccorsi:
I think that's the most straightforward response I could give there.
Matt Stauffer:
I think that was very good. I think it deserve some claps. I only have one criticism, which is the word synonymous.
John Bonaccorsi:
That's just synonymous
Matt Stauffer:
Use said synonymous, because it's 100% the way you normally talk, I know you. If we were to take that and replace the word synonymous, well, the good thing is the audience of this podcast actually does know what that means so we're good. You did pretty good.
John Bonaccorsi:
There we go.
Matt Stauffer:
Goal for number two is just don't use word synonymous and you're good to go. The next one is how do you explain database factories to a five year old.
John Bonaccorsi:
This is the tough one and this is the one that I honestly thought about the most. You're really going to have to bear with me here, but I'm going to give it my best shot. You know how when you're like a little kid, and you're watching a TV commercial, and there's like ... it's sort of like a robot toy, and the robot in the commercial, you have a little kid and he's playing with the robot, but he has this full landscape and he's using the robot to punch down buildings. The buildings are made of blocks, and they fall apart and it looks so cool. You're like, "I need this robot." You order the robot and it comes to your house. But playing with it isn't quite the same as in the commercial.
Matt Stauffer:
As the commercial.
John Bonaccorsi:
It's not as exciting because you don't have these buildings to destroy. It's not the same thing. You end up taking a bunch of Coke bottles or Pepsi and you stack them up and then you have the robot punch them, and that's about as best as you can do. I would say that those Coke bottles are the most similar thing I can think of to factories in Laravel, which is that you have this world, and you're building something up and it's crude, but it's basically just there so that your robot can knock it down. If we're going to complete really this metaphor, I'd say that, you're the little kid. The robot is your app and the building is the factories.
Matt Stauffer:
Okay, I like it. Our apps are destroying our data, punching it down like a robot.
John Bonaccorsi:
I should have ... You know what, I like that you caught me there, because I think the robot is really your tests, so I'd say that.
Matt Stauffer:
There you go. That's good.
John Bonaccorsi:
That's what I meant to say.
Matt Stauffer:
I like it. I like it. That's good. That was really fantastic. There was a word you used in this one, I was going to tease you about but I got so distracted by imagining our apps just destroying our databases and it made me really happy.
John Bonaccorsi:
I'm just trying to distract you from my grammar. This is what I do.
Matt Stauffer:
The thing is, it's good grammar.
John Bonaccorsi:
Oh is it?
Matt Stauffer:
It's fantastic grammar. That's the thing. It's like when you speak to a five year old ... Here's a total side note to everybody for this section. First of all, when you speak to a five year old, you do need to dumb it down a little, because they don't know the same words, and they don't kind of process things the same ways. But the person who ... There's a few people in my life who treat children and pets as if they're more capable of advanced speech than we tend to think of them as, and the pets and children around these people are always the brightest.
Matt Stauffer:
I think that there is, while you do have to dumb down your talk to a five year old little bit, in terms of the grammar and the vocabulary, I think it's a lot less than we tend to assume. You're on the train for eventually having kids and them being super brilliant, because you're synonymous six month old, what's up? All right.
John Bonaccorsi:
That's a fair point.
Matt Stauffer:
The third one, how do you explain seeders to a five year old?
John Bonaccorsi:
This is the ... Yeah, this is a tough one. I'd say that if we're going to stick on the previous metaphor a little bit and if you have this world ... If you're building up that landscape in your house to look like the commercial and you have your buildings and stuff like that, if you ever had like, if you started to do that over and over again and you had your fake police station, which is made out of Coke bottles and you had your hospital which is made out of whatever other kind of bottle or whatever, whatever kind of plan you have in your mind or on paper of where all those things go in your little landscape, that is your seeder.
John Bonaccorsi:
That is kind of ... How things are built up in multiple different ways, and then what you're grouping those things together and stuff like that. That's a little rough. I'm going to be honest with you. I don't know if that fully tracks. I don't know if any of this fully tracks, but ...
Matt Stauffer:
Well, it makes sense.
John Bonaccorsi:
That's the best I can do.
Matt Stauffer:
I like it. It was metaphor that was the word I was going to tease you about. "What's a metaphor Uncle John?" Okay, so I like it. I'm trying to imagine this metaphor. We're creating this little pretend world and the buildings we're building represent our data, right?
John Bonaccorsi:
Yes.
Matt Stauffer:
Okay. A factory makes it really easy to make a certain type of data, right? It's like a factory is like a pre-planned idea of how to make like a hospital or something like that, or you saying a factory is like a bottle is that what you ...
John Bonaccorsi:
Yeah, I'd say like a factory is like ... Yeah, I think that grouping of bottles like your fake little hospital. But yeah ...
Matt Stauffer:
Then seeder is like a whole plan of a whole thing, right?
John Bonaccorsi:
Exactly.
Matt Stauffer:
Like a bigger ... Okay. Yeah, yeah, I love it.
John Bonaccorsi:
Exactly.
Matt Stauffer:
Regardless of five year olds or buildings, I've never thought about the fact that in many ways, seeders are just bigger factories. I love that idea. I don't know if you did that on purpose. But it's a really cool way of coming at it with your brain. Yeah, you did it on purpose because you're smart.
John Bonaccorsi:
Yeah, I think people talk more about seeders, but I think that is ... I think I always think of them as groupings of factories, so-
Matt Stauffer:
That's awesome.
John Bonaccorsi:
... same thing, yeah.
Matt Stauffer:
Yeah, totally makes sense. I just never had thought of them as just like a bigger section of the same thing. Okay, cool. Now let's talk ... I don't want to walk right into common use cases because you did such a good job of keeping it to five year old that I do want somebody now ... Let's talk about somebody who has been writing PHP for 20 years, but just doesn't understand how these topics are going to be used. Can you tell means a little bit about how you would use migrations, factories and seeders each in the same places or different places? What are each of them used for in your day-to-day Laravel app?
John Bonaccorsi:
Yeah, absolutely. I think that migrations, if you think about ... If you're new to Laravel, and you're probably not new in general to web apps or databases and stuff like that, so anytime that you are building an app and it has a database, you're going to have, those databases are going to have tables and columns and all kinds of stuff like that. Basically, what migrations allow you to do is, basically create a schematic for those tables and those columns, so that no matter where you are, no matter if you're on a different computer, if you're on a different server, if you're on production, if you're on staging.
John Bonaccorsi:
If you're ... wherever you are, that you can always build up the exact same database with the exact same structure based off of those migrations, so you're not having to remember to write down, "Oh, add this column here and make it null or give the default value of this or that." It's all right there in code for you and it keeps track of that. That's typically when I'm using migrations. I think one of the interesting things about migrations is that, it has a secondary use, which is managing content that is the same across all databases or all, basically all instances of your database.
John Bonaccorsi:
That is probably one of the things I remember being most tripped up as, as a new Laravel programmer is like, I remember hearing about migrations and then hearing about seeders and being like ... When it came to adding data into the production database that needs to be there in every environment. For instance, that might be a list of states or a list of countries or if you're writing a blog, a list of blog topics that needs to be there in every environment, they're always the same, all that kind of stuff. I remember Googling six years ago, how do I do a production seeder?
John Bonaccorsi:
Because that was the only way to think about adding content to me was, what is a production seeder? The answer was, I think really this didn't get solidified to me really until I came to Titan, which is like, "No, your migrations are not only for managing your database structure, but for any kind of content that is intrinsically connected to the database." That might be things that ... list of states that are in every environment, or countries or whatever that may be. I think that's a little bit ...
John Bonaccorsi:
I don't know, I think it's not really natural for a lot of people to think about it like that. A lot of people get tied into think about, no migrations are just for schema.
Matt Stauffer:
Schema, yeah.
John Bonaccorsi:
Doing to write a command, add this data, whatever it may be. But, no migrations are really the perfect place to manage data that is consistent across environments. After doing it for a while, it feels good to me. I'm not saying that there couldn't be a better solution for it. Sometimes it still does feel a little achy. But for the most part, it's a pretty elegant solution and that's the second kind of major use case, I'd say there are for migrations.
Matt Stauffer:
Before you jump to the next one, I love that idea because one of the things that helps you ask the question of is a migration or a seeder or something else good for this is, does the app function without this data? If the answer is yes, then it's probably seeder data because in the production application it will probably be replaced by real user data. But if the answer is no, I get to a page where there's a drop down that should show me a list of all of our corporate locations or whatever else, and that page literally doesn't work without this data.
Matt Stauffer:
That may be an indication. Now, that's not always true. There's some things where you have to have at least one user, but that doesn't mean the users migrated data, right?
John Bonaccorsi:
Right.
Matt Stauffer:
But a lot of times where it's like underlying structures of the application rely on this data, and the data is going to be the same across all installs and we might modify it like once in a while, but probably not, those are all really good signs that that data is more architectural, right?
John Bonaccorsi:
Right.
Matt Stauffer:
If you could even consider storing that data just in a hard coded array somewhere, that might be a good spot for migrations. Is that a good way to think about it for you?
John Bonaccorsi:
Yeah, exactly. Yeah, it's same thing. Yep.
Matt Stauffer:
All right. Cool. I interrupted you. The next step was factories and seeders what they are for an actual programmer who has been programming not a five year old.
John Bonaccorsi:
Yeah, so I think the best way to talk about factories is that, once you have your table set up, anytime ... Once your app in general is setup, and that include your migrations and your database, your table and when you're testing that app. When I say testing, I don't just mean automated testing, but I men even just testing a lot of people do, which is manual testing, clicking around the app and stuff like that. You're going to find yourself in situations, where you need data that would typically be created by users.
John Bonaccorsi:
For instance, if you're writing a blog app and it posts in the database so that you make sure that the blog has the right content or something like that, you put yourself in a situation where you go, "Okay, well, how do I get this data into the database?" You could manually create it. You could just go to the app itself and write your blog and add the content, and it would be there and stuff like that. But then more you realize, maybe I need a blog post that's archived, or one that's unpublished, or one that's written by somebody else.
John Bonaccorsi:
Before you know it, if you're manually creating all these different types of entities or this data, it's just you're in for a world of pain there. It's just, it's hard. If you're on a different environment, all sudden, maybe you do that locally, and then you're on staging and you don't have all that data, and you go, "Oh no, this is really bad." Basically what factories are, is a way or a way to get data, fake data into your database. They sync ... In terms of Laravel, they sync up basically directly with your Laravel models, and they connect one to one there.
John Bonaccorsi:
They give you a way to basically on the fly generate fake data for the database. They work hand in hand with this other PHP package called Faker, which allows you to fill out the columns in the database. Let's say you have a blog and your blog has a title and has content, and obviously when you fill those things out, you need a title and you need content, and maybe you need topics or something like that. Factories work with Faker to generate that data on the fly. It'll give you a fake title. It'll give you fake content.
John Bonaccorsi:
Can give you random numbers, it can give you Booleans whatever that may be. That's basically it and they also have this concept. They have a lot of different concepts. But factories also have this concept of state so that if you have a column in your database that is published or is, which is true or false in your database, depending on now this is a blog app, you could instead of having to set that is published column the true or false every single time you use this factory, you could create an unpublished state.
John Bonaccorsi:
Once you use that state, it would automatically set that column to true or false, depending on what the state was. That's the idea there is just basically the high level there, just get fake data into your database that you don't have to do it all yourself manually. Then in terms of seeders, because I think seeders work hand in hand obviously with factories, we talked about this earlier about how seeders are essentially groups of factories, I think that is the way that I typically use them, which is just a way to group factories together.
John Bonaccorsi:
Because, if you're writing an app and you have a flow going and you know, "Okay, I have a blog and it needs comments and it needs topics and it needs this or that," that's not one factory, right? That's like three at least. You have your topics, you need your connection between the topics and the blog. You need your comments and all that kind of stuff. You need users who fill out those comments. All of a sudden you're using 10 factories out of nowhere. Seeders are basically ways to group similar stories. If you have like, "Okay, I need ..."
John Bonaccorsi:
Maybe you have an unpublished blog seeder or something like that and that creates an unpublished blog that you wrote, an unpublished blog that someone else wrote, an unpublished blog from three years ago, an unpublished ... Whatever it may be, it's just going through and grouping your factories together. I think all these ... Seeders in particular are kind of, they're general enough that a lot of people use them in a lot of different ways. But that's typically the way that I use them. It's just think of them as a grouping for factories.
Matt Stauffer:
I love it. It's so funny, because even for me to say like that even seems remotely transformational. It's like, "Well, duh Matt, of course, that's what they are." But it's interesting because sometimes with factories and seeders and migrations, the concept is simple, but really knowing when to use it and how and where in which things it solves other than the core, can sometimes take your brain a little bit to wrap around, which is one of the reasons I have you on and just, I didn't mention this, but for anybody who doesn't know, so John has been ...
Matt Stauffer:
He wrote a podcast on or he wrote an article on the Titan blog that I'll link in the show notes about factories. He also was on the 20% time podcast, which is the type podcast a month ago or something like that, and talking about this idea of how to use factories in an organized way, that makes a ton of sense and addresses a really common problem, but in a way that just thinks a little bit freshly about factories. We maybe will go in that in the end ... If we had gotten to the point where we really feel like we've covered everything else, we might go into that. I don't want to go into it yet because I don't know if it'll make sense yet.
John Bonaccorsi:
Sure.
Matt Stauffer:
But definitely go check those both out. But one of the reasons I brought John on this podcast is, because I think that he has been thinking about alternate ways for us to encounter and approach these three things, migrations, factories and seeders in a way that I think a lot of us will benefit from, but not a lot of us have actually taken the time to do so. Anyway, if anybody feels these things are really simple on the first hand, good. I'm really glad you feel like you got it. On the other hand, these are one of those things where sometimes you're going to go, "Wait a minute, how should I have done that or what should I have used?"
Matt Stauffer:
Or you'll encounter a problem and not realize that these are tools you should use for that problem. I think that's why it's really great to have John, because he explains and understands these things in a way that gives us more, maybe permission and ideas for how to use them in different contexts. Anyway, that's one of many reasons I have John here. One of the other ones is his epic beard and his luscious hair that you all unfortunately miss out on, but just trust me it's there.
John Bonaccorsi:
Just visualize it.
Matt Stauffer:
Yeah, exactly. All right. Normally at this point in the conversation I ask, when is the last time you use the system? But of course, you use all of them. But I would say, let's go really quickly and go through what you just said. But I want to take it from, just to give me bullet points. When you're working with migrations, first of all, what's the most common use case for a migration?
John Bonaccorsi:
Yeah, I mean, the most common use case for a migration is that you have a new table in your database, and you need to build it out and that's just it. Yeah.
Matt Stauffer:
Yep. Then the second most common is modifying or deleting tables?
John Bonaccorsi:
Modifying ... Yeah, modifying tables or adding data or something like that, that's kind of further down the list. But 90% of the time when you're making a migration, it's because you have a new model that you want to build or a new entity and you just need a table for it.
Matt Stauffer:
Yep, totally. With factories, the most common, what's the most common time you use factories?
John Bonaccorsi:
Yes, this might be different across people. But for me, the most common time I'm using factories is when I am writing an automated test in something like PHP unit, or whatever framework you may be using. You need there to be data in the database for that test to build its world and that's the most common time. I'd also say there's a very, I'd have a second bullet point here. I'd say that the other most common thing is if you are on a server, and you just directly need some data in your database right now, maybe just like, you fire up PHP Artisan Tinker, you go in there, you make 10 factories or whatever it may be and you get your data right away without any clicking around the UI.
John Bonaccorsi:
That's probably, depending on if you're a developer who is more experienced in writing tests or something like that, you're probably going to be more towards the first one. But if you're a developer who's not quite there yet, you're probably going to be using the second one.
Matt Stauffer:
Yeah. The third would probably just be in your seeders, right?
John Bonaccorsi:
In your seeders, yeah.
Matt Stauffer:
For anyone who's not familiar, so Tinker is the command line tool, because I don't think we've done our command line one yet. It's a command line tool that allows you ... If you've ever done Ruby, it's like a repl. If you haven't, don't worry about it. Actually it is a repl. It's like whatever Ruby's repl's called, which I can't remember now. But anyway, you're going into there and when you type a command, it's a read evaluate print loop. When you type a command and hit enter, Tinker evaluates it against your Artisan or against your Laravel application.
Matt Stauffer:
If you were to write something like, user, colon, colon, all which we learned last week or in the database episode would give me all the users in the entire user table, it would go run that command as if something was doing it and then it would return it back to you, so it's print and then it would give you the next line that you can work with it. One of things that John mentioned is something I do on almost every single application when I spin it up, which is rather than seeding users for yourself, because then you end up with seeders that just have to have your name and your username and your password for every time you spin up a new version of your app.
Matt Stauffer:
Instead, when I spin up a new app, the first thing I do is I go PHP Artisan Tinker and then I say, basically, what you're saying is user equals, and then you're making like a factory of the user. Then you would just set the properties to be your own, or especially if you need things there that you don't need to set anything like, let's say, he had mentioned, maybe you want 10 blog posts in your thing, you would just say, basically use the factory to create 10 blog posts. Hit enter, and then it'll just be in the database there.
Matt Stauffer:
I wouldn't have even thought of that. I'd use that all the time and I wouldn't have put it at the top of my mind, but you're absolutely right. That's a super common case for that. When are seeders most commonly used?
John Bonaccorsi:
I'd say seeders are most commonly used in ... For me, I can only ... I guess I should just answer for myself. For me, seeders are most commonly used to set up data, groups of fake data for an actual staging site. That typically just tends to be the time I must use it. For instance, we have a product called Field Goal. You can be a field goal user with a free trial or there's four different types of subscriptions. Basically, it's just your typical SaaS service and you have all these subscriptions. For that site, whenever I'm working on it and I'm making changes to it, I want to test 10 different types of accounts, like a user who has a free trial, but that free trial has expired, a user who is still in their free trial period, a user who has a subscription but canceled and blah, blah, blah.
John Bonaccorsi:
Doing that over and over again, just it was rough. What I did was on Field Goal, I have a seeder that creates a bunch of fake users with all those different things, free trial, expired, no subscription, subscription but it's this plan, blah, blah, blah, blah, blah and they all have these very specific emails. It'll be like, userwithfreetrial@test.com or something like that.
Matt Stauffer:
Exactly.
John Bonaccorsi:
Basically, whenever I need to test staging or whatever I'm testing locally, I'll just run that seeder and then I immediately have 10 accounts with every different type of user at my disposal. The great thing about that is, the staging site gets blown up, which sometimes that happens, right? Today someone writes a command, the database gets wiped, who knows what happens. It's not your concern, because you just rerun that seeder and all sudden you have all the data that you ever needed and you're good to go.
Matt Stauffer:
Yep. You can also run the same seeder on your local machine, and then if your local machine dies, you don't worry about losing the contents of your database, right? Because you just clone it to the new machine and then run your seeder and then boom, it's fully populated as well.
John Bonaccorsi:
Exactly. Yeah.
Matt Stauffer:
Yeah, good call.
John Bonaccorsi:
I think there's a second way that people use seeders as liners. There's been a little drama in the Laravel community in the last couple months, which we can maybe get into later if we're talking.
Matt Stauffer:
Yeah, I'd like to.
John Bonaccorsi:
A lot of people also, I think, whenever you're looking at like these things, there's always going to be duality of people, who are using it on the fly to get data into an actual app, so they can hand test the app. Then there's going to be the second subset of people who are primarily using it to write automated tests. Same thing with factories, you can run it in Tinker, you can run it in the test route or something like that, or you can run it in your test. With seeders, it's the same thing, you might be running a seeder on your staging site and that could be fine. Just like I just described, or a lot of times people are using them to group factories in their tests and their automated tests.
John Bonaccorsi:
That's the second and those things can, they're not mutually exclusive. You could create a seeder for your test, and then also use it on your actual site if you wanted to. But I'd say if we're talking about the two most common use cases of seeders, to me it's easily those two.
Matt Stauffer:
All right. One of the reasons and I put a note for us to talk about drama later, but I do want to note that one of the things because I remember I said that you all are, it's not quite time for us to talk about John's particular approach in his blog posts and stuff like that. But there is a note, which is that John's idea that he introduced most publicly, and this is not the only unique thought he's had, but the one that's most probably is something around organizing your factories and is organizing your factories using PHP classes rather than organizing your factories using seeders.
Matt Stauffer:
Obviously from this podcast, you can hear that he does both in different contexts, and that's where some of the drama is, but I did also notice here, which is something I didn't actually know, which is that there's also a Laracast video where he says, "To do this we'll use a technique that I first learned from John Bonaccorsi blah, blah." I will make sure I link that one in the show notes as well, because we got to get the Laracast John Bonaccorsi one as well.
John Bonaccorsi:
Actually, can I tell you this real quick?
Matt Stauffer:
Yeah.
John Bonaccorsi:
Jeffrey Way not that I know him at all or have any interpersonal relationship with him. But he didn't even tell me that he did that video. Someone tweeted that to me.
Matt Stauffer:
He just snuck it out.
John Bonaccorsi:
I'm a big fan of Laracast. I've watched it for 10 years, whatever how long it's been around, I've been a fan. Someone tweeted me once and was like, "I watched your Laracast video," and I was like, "What?"
Matt Stauffer:
My what?
John Bonaccorsi:
I was like ...
Matt Stauffer:
You're mixing me up with the other guy with the rich hair and the handsome beard.
John Bonaccorsi:
Yeah. Jeffrey, next time hit me up.
Matt Stauffer:
That's fine. For anyone who doesn't know Jeffrey is a wonderful human. He's also an extraordinary introvert, like one of the most introverted people I've met in my entire life. That's not actually that abnormal.
John Bonaccorsi:
That he did it. I'm fine with it.
Matt Stauffer:
Yeah, totally. It's super cool. Yeah, I'll link it out to all of you. okay, cool. Cool. Cool. Let's get back to where we were because I will jump around a million times. Okay, so did I have you talk about seeders too, yes?
John Bonaccorsi:
Yeah.
Matt Stauffer:
Where you normally ... Okay, cool. Yeah. That's where we were. All right. The next section of this podcast is usually, what are some times the system is tripped you up or what are common challenges, or what do you wish everyone knew about the system? Now you can say all of those, but I definitely want to make sure we end on the what do you wish everyone else knew about the system? Let's start with, are there any common go yous or any common challenges or any places where any of these three systems trip people up, because they're not thinking about it right or they don't understand something or anything like that?
John Bonaccorsi:
Yeah, totally. I think anything can trip somebody up, and I've definitely been tripped up by all three of them. We've touched on some of those trip ups already just indirectly. But one of them, not to go too far in it because we've already talked about it, but using migrations as content matters. That is a big thing that trips people up. They try to avoid it. They think it's wrong, whatever it may be. That's probably one thing with migrations. Another thing with migrations, I think is that people at first, maybe don't realize that, they're immutable.
John Bonaccorsi:
That's kind of, if anyone isn't familiar with what that means, it just basically means that, once a migration has run particularly on your production environment, it cannot be changed. There's a caveat there. There's a 0.0001% time where that, maybe you get a little weird and you do change it, but I'd say there's, you really should never be changing migrations that have already been run. That's because, if anyone's unfamiliar with the migration system in general, basically the way that it works is that, your migrations are just files.
John Bonaccorsi:
They're just PHP classes. They're special classes, but they're basically just these classes. When they run against an environment, whether that's staging or local or production or whatever it may be, when they run Laravel stores that migration has been run in your database in a migrations table. The problem, the reason we say migrations are immutable is because once they run that one time, they never run again, when you run PHP Artisan migrate. Sometimes when we've been talking with clients or people who are new to Laravel and they never had, been familiar with this, they'll be like, "How do I changed the column and migration that ran three months ago and it didn't pop up?"
John Bonaccorsi:
It's like, "Well, no, if you create a table like a user's table or blogs table or whatever it may be, and then three months down the line you need to add a new is published column two it, you're not editing that existing migration. You're creating a new migration that says something like, create or add is published column to users or blogs table or whatever it may be.
Matt Stauffer:
Exactly, yeah.
John Bonaccorsi:
That's definitely a trip up for migrations. I think that there's also dealing with like foreign keys sometimes or indexes in migrations, can sometimes be tricky, just based off the name. I know what the index is in particular. You can pass it in two ways and they both mean slightly different. If it's an array of things one thing and if it's not an array, it means a different thing. I still get tripped up by those things sometimes to be quite honest with you. There's little moments like that but to me, those things they get ... Working with databases in general can be hard. Figuring out what is the right type of content, what is, when do I need an index?
John Bonaccorsi:
What kind of index do I need? Do I need a foreign key here? Those aren't necessarily particular to migrations themselves. That's more just like database ...
Matt Stauffer:
Database architecture.
John Bonaccorsi:
... that everyone has. I don't know if I'd pin that on migrations, but that's where they'll most likely bubble up for you, because that's where you're doing ... That's where you're working with those things.
Matt Stauffer:
Yeah. It can often be easy to not notice that ... There was a thing I did for like, I think we discovered it was a year or two, where I changed the creation of an index after the creation of the column. I just did it fluently like table arrow, whatever and then right after that, I did the arrow for the column, and it didn't error out and I thought I'd seen it somewhere. It turns out; I was silently not creating those indexes that whole time. The one of the got yous on migrations is that if you run them without ever actually going over to look at your database app, then you might not notice that things aren't working the way you want.
Matt Stauffer:
I definitely would just tell people, while it's magical that we can create and define our schema and code, it's still worth going over your database app at some point, just making sure that you have what you think you're going to have. The cool thing about factories or about, well about factories and seeders especially in migrations is that, your database is not a special pony that you have to take care of. It goes back to whatever the previous podcast was, where we were talking about cattle versus pets.
Matt Stauffer:
Your database, other than your production database, which should be special and wonderful and everything like that, but all your other databases, you should be able to just destroy them and spin them back up very quickly, right? Even to the point where if you want to open up that database app and mess a whole bunch of stuff up, or you're not sure if it's the right state, get comfortable with destroying the entire database and migrating it from scratch all the time. The more confident you are, you can do it one time, the more flexible you are to spin up new servers or whatever in the future.
John Bonaccorsi:
Yeah, absolutely.
Matt Stauffer:
All right. Do you ever modify old migrations, like ever at all?
John Bonaccorsi:
Yeah. Yeah, I do.
Matt Stauffer:
Can you give me a couple examples of when you might do that?
John Bonaccorsi:
Yeah, so a couple things I'd say and this is ... I'll go with the easiest one first, which is that sometimes I'm just a little neurotic and I don't want to add a new migration for a column. I never do this on a client site. I'll say this. This is when I'm Wild West cowboy John having his local projects.
Matt Stauffer:
Working on your own thing.
John Bonaccorsi:
Yeah, whatever it may be. Sometimes I want my migrations to be perfectly in sync or in line with my models. If I have 10 models, I want there to be 10 migrations. I did this recently with my side project, which is where I went back and I made all the migrations as if they were perfect, and I know exactly what everything was when I first did it. Then I went to my migrations table and I deleted the old ones. Then I did a bunch of Hocus Pocus and ...
Matt Stauffer:
That's hilarious.
John Bonaccorsi:
How necessary you feel that is, is up to you. I like it. I would never do it on a client project where it's like a danger. I might do it on an internal project if I was like, had approval and they were like, "Yeah, let's do it."
Matt Stauffer:
I did that on a personal project once where it's the same thing is like, everything was perfect except one thing. There wasn't any super important data and it was all backed up. I went, and I just went into SQLPro or TablesPlus or whatever and I just modified the column. Then I changed that same modification in the original migration, and I felt a little bit dirty and a little bit magical at the same time.
John Bonaccorsi:
There's something about. It's like the call to void, you just want to do it.
Matt Stauffer:
Yeah. Like you said, would never do it on a client project, but just sometimes you do that.
John Bonaccorsi:
Yeah, if I'm responsible, then I'll just take the risk.
Matt Stauffer:
Exactly, I'll take the risk. Have you ever and would you ever recommend in any context, deleting all the old migrations and then replacing them with one single migration that creates the database at a certain given state? Let's say that the apps been running for a long time or something? Are there any contexts in which you would recommend that?
John Bonaccorsi:
Yeah. I'm actually doing that right now for a project, which basically is that, this project was ... It's been around for a long time and they used migrations originally for a little bit. Then basically what happened is that they stopped or somebody stopped and all sudden, you had some people using migrations, and you had some people hand going into the database and adding columns and adding indexes and stuff like that and so...
Matt Stauffer:
Which you should not do by the way everybody. Not to shame anybody on that project, but just in general, do all your database modifications to schema in migrations period.
John Bonaccorsi:
Yeah, and the point of building up this kind of schematic is that you can reuse it. If someone's hand making changes, and then they forget to do it the same way, it's just becomes a dangerous situation. That is a situation, where there's two ways you can approach that. You can try to fix the existing migrations, or there's even some tools out there that generate migrations based off of your database. Those tools are phenomenal, and I wouldn't even begin to know how to write one myself, but I just never had success with them. There's always some-
Matt Stauffer:
They're never perfect.
John Bonaccorsi:
They're never perfect. There's always some weird collation issue with my SQL or there's some index that didn't get properly named, I've always had a problem. Basically, the reason that you would do what Matt just described, which is delete all of your old migrations and make one migration that just imports a SQL dump essentially is that, if your production database is so woefully out of sync with what the schematic of the migration say they are, that's when you would just go back and delete them.
John Bonaccorsi:
Then that also involves going into your database and deleting those migration columns in your database, so that's another thing that now you're already editing data and the production that gets messy too. It's not an ideal situation. There's no elegant way to fix it. But that is the time when I would just go scorched earth and delete everything.
Matt Stauffer:
We at Titan have done this, three, or four or five times, at least, probably more that I don't know about, where we were able to make it work using that tool. There's one main tool, I forget what it's called, but I'll link it in the show notes that generates migrations from your database. But every time it's been a tiny bit imperfect. If you do use a tool like that, you really have to sit side by side with your newly migrated thing that came out of that tool, and then with the actual production database and ensure that you catch everything, and you'll probably have to tweak that migration file at least a little.
Matt Stauffer:
Sometimes, like John said it just doesn't work. That is certainly more ideal where you have a single primary migration that represents everything up till then, versus a SQL file. But sometimes you end up having a SQL file, but I would note that when he says a SQL dump, he does not mean a data dump. He means a SQL schema dump.
John Bonaccorsi:
Schema dump.
Matt Stauffer:
If you do end up having to do that, you go into something like tables plus or SQLPro, you hit export SQL dump, and then uncheck with data. All it will do is write a single dot SQL file that describes the entire creation of your SQL database, and then your first migration instead of migrating everything will actually just open up that file and run it on your database and that's migration one. Then migration two is whatever the next migration you create, and sometimes you got to do it. Again, just like John said, there are things that we do at times because they're the only things that can be done. That doesn't mean we would recommend doing them unless you have to, and this is on that list for sure.
John Bonaccorsi:
Yeah, and I think one thing to note is just that, I could be wrong about us, but I'm 90% sure that Laravel aid is going to ship the way to do that directly.
Matt Stauffer:
Oh cool.
John Bonaccorsi:
I think Taylor built in a way that you can do some kind of command and it will take it, export of your database schema and create a migration for it. I could be making this up, but I'm 90% sure that that is an actual thing that's happening.
Matt Stauffer:
If I had known that was potentially coming, I would have pushed this episode out a little while, but oh, well. But if it does come out, I'm going to do my very best to remember to come back and add it to the show notes here. A, if you come back and then Laravel 8 is released and you don't see in the show notes, hit me up on Twitter at @stauffermatt and I'll add it, but B if Laravel 8 is out, you should be able to go there and preferably, hopefully see it in the show notes as well. Awesome. Are there any other got yous or common challenges people run into? Or is there one or two or three things that you really wish that everybody knew to do or not to do when working with these things?
John Bonaccorsi:
No, I think there are some other challenges and things that you ... reasons that you might even edit an old migration. One thing I just want to mention, it might be hard to talk through so I'll try to make it as simple as I possibly can. But I do want to note it because as we're talking a lot about people managing content in their migrations, this could potentially bite some people pretty badly. It bit me for the first time. It totally caught me off guard very, very recently. That is that ... and again I'll try to do it as simple as possible.
John Bonaccorsi:
But basically what had happened was, I had a migration ... Let's just say we have a user's table. We have a migration that creates a user's table, and then we have a second migration that says like, "Add something to that user's table," like an admin user that's always going to be there, right?
Matt Stauffer:
Yeah.
John Bonaccorsi:
In that migration, I did something like user create and I put it in an admin email, and I put in whatever it may be, and then that was good to go. That was perfectly fine. Then what happened was, many months later and many migrations later, I had another ... I basically needed to make users soft delete. If anyone is unfamiliar with soft deletion in Laravel, which you may be, it's basically that, typically if you delete something from the database, it's gone. It's gone from the database. What soft deletes essentially allow you to do, is they add a deleted at column to whatever database it is.
John Bonaccorsi:
In this case, if you're at users table you would have a deleted at column which has a timestamp on the user's table. When you delete, "delete" the user via like Eloquent with user delete or whatever, it wouldn't actually go away from the database. It would just set that timestamp to false. It would give it a timestamp and say, "Okay, this thing is now deleted." Basically, I added a migration to add the soft delete column to the users table and also add the trait which you need on the model for the users table, and good to go and everything worked just fine.
John Bonaccorsi:
Then later, when I went to rerun all those migrations, again for some reason, just setting up a staging site or doing something locally, when I went to rerun them, that original migration I'd made that created the admin user, failed.
Matt Stauffer:
Really?
John Bonaccorsi:
Yeah, and the reason why it failed was because the user model, which is the class I was referencing in that first migration, now had the soft deletes traits on it. Because of that, it's expecting also to have this deleted at column, which at the time of that first migration did not exist.
John Bonaccorsi:
Now Laravel is trying to load up the user model and saying, "Oh, the user also has a soft delete. It also has this column." But actually it didn't yet at this point in time in the migration timeline.
Matt Stauffer:
Did you just change the time of the migration, so it ran after the soft deletes migration?
John Bonaccorsi:
That'd be one way to do it. Basically, what I really did was that, I went in and I use DB table users instead to create the...which then I went back and edited that original migration that created the admin users-
Matt Stauffer:
Perfect.
John Bonaccorsi:
... and I changed it, so instead of using the models to do user create, I did DB table users create, which is a more raw way of doing queries in Eloquent.
Matt Stauffer:
You used the quick the Query Builder instead of Eloquent?
John Bonaccorsi:
Yeah.
Matt Stauffer:
The Query Builder is just basically straight SQL queries that you're building with a convenient syntax, right? It doesn't know about soft deletes or anything?
John Bonaccorsi:
Exactly. The differentiator there is to is that Laravel is not loading the model. It's interacting directly with the users table in that case, and so there was no, it didn't matter if it had soft delete straight or not. That was one moment again, where I had to go back and edit an existing migration and I just thought like, "Oh man, this is ... This will totally impact the way that I write migrations moving forward," because that is a very real scenario that could happen. But no, other than that kind of stuff, I don't think there's anything really that I wish that people knew.
John Bonaccorsi:
There's this whole migration conversation about do you have a down method, if you don't have a down method and for anyone listening, that just means, migrations have an up function which builds up the database and theoretically have a down that deletes the table that you're migrating or whatever, maybe and some people are...
Matt Stauffer:
Give me some fire John. Do you write them or no? Do you write a down method or no?
John Bonaccorsi:
I do write them. Mostly just for consistency sake, but I don't ... But to be honest, I probably don't need to, just because ... I do it because I've always done it basically. But in reality most people when they're dealing with migrations if they need to rerun them or something, they just delete the entire ... They do a migrate fresh.
Matt Stauffer:
I was going to say, when is the last time that you ran Artisan migrate rollback? Because that's the only time it's going to be used right is rollback?
John Bonaccorsi:
Yeah, that's the only time when it would really be used would be the rollback method. I feel like the only times I've had to do it is when I'm in an ideal situations with data from someone else's database that I'm working with locally, and I don't want, to go too far back or I don't want to have to re import the database.
Matt Stauffer:
Got it.
John Bonaccorsi:
It's mostly when I'm in a situation that's a little sticky, but in an ideal world where you have seeders and you have everything perfect, then you have no need for it in reality.
Matt Stauffer:
One of the reasons that people most commonly pitch the idea of a down method is, let's say you did a deploy to production on some massive website and it breaks everything. A lot of people say what you do is, you'd roll your code back one commit using Git or Envoyer or whatever, and then you'd also then run PHP Artisan migrate rollback, so you'd rollback your database back one commit. In theory that works, although a lot of people that have talked about that circumstance since have said, "What I'd rather do in that circumstance is write a new migration that brings it back to the original state."
Matt Stauffer:
I don't know if I like that idea, only because if you're rolling your code back, and then you're adding a new migration forward, you're going to get into some very complicated code statuses because that new migration ... If you migrated your database in that code to a state that wouldn't work with the rollback code, you got to rollback your database too. I do think that that is the most compelling reason that if that's a workflow that you'd consider, it's the most compelling reason to consider writing those down methods. That said, I can't tell you the last time I actually used it.
Matt Stauffer:
But if that type of stuff happens, I have found that rollbacks almost always break something else like rollbacks in the code and stuff like that, and I tend to instead take the whole site down, do a fix locally and then push the fix up. In which case, you don't need to roll back the database because you're just fixing whatever that minor bug is. But there's some environments where that's not possible. The bigger the more enterprise the more process there is, the more likely it is you're going to want a down method.
Matt Stauffer:
The more you're a single person working on a project, or smaller teams or more agile teams or whatever else, the more likely you're going to be at least open to not using the down method. Whether or not you do is up to you.
John Bonaccorsi:
Yeah. I also think that sometimes people forget to test their down methods locally.
Matt Stauffer:
Yes, that's true.
John Bonaccorsi:
Then run them when you need them all sudden and all sudden it goes, like actually your foreign key exsists and you go, "Oh my god, what was the point of even ..."
Matt Stauffer:
That's true.
John Bonaccorsi:
Yeah. I've definitely and I've done it myself. I've forgotten to test my down migration. Also, I'm just afraid sometimes to run PHP Artisan migrate rollback, because I sometimes can't remember which one does which. I'm like, "There's refresh, there's whatever rollback then there's like, there's the other one fresh," and I'm like ...
Matt Stauffer:
Refresh.
John Bonaccorsi:
Which one does which and then I get scared, and I just do a new migration or something.
Matt Stauffer:
Every single time I'm working on my local database, and I need to throw it away and start from scratch, I've got a certain command that I run. Before I tell it, I want to know what is your command that you run when you need to just wipe your database, start from scratch?
John Bonaccorsi:
Yeah, it's ... It's like PHP Artisan MF or something like that, which is migrate fresh, I believe. I think it's even maybe PHP Artisan MFS which is like migrate, fresh and then siege.
Matt Stauffer:
Refresh, space seed.
John Bonaccorsi:
I think that's the one I'll typically do.
Matt Stauffer:
Yeah. I actually have ... You did Artisan alias to do that?
John Bonaccorsi:
Yeah, I guess it's like ...
Matt Stauffer:
Or did you just use MFS?
John Bonaccorsi:
I think it's just ... No no, it's like a ... or yeah, it's probably, yeah, I think it's just like MFS which is like then it does in the background all those commands.
Matt Stauffer:
Yep.
John Bonaccorsi:
Yeah, yeah.
Matt Stauffer:
I have the same thing. The cool thing is even if you don't do the bat shortcut they were talking about, you can type PHP, space, artisan space, migrate, colon, fresh, space ... Is it dash, dash seed or seed, forget which. I'll put in the show notes too.
John Bonaccorsi:
Yeah, I think it's dash, dash seed.
Matt Stauffer:
Once you get those shortcuts you don't remember. But that command all in one, it doesn't work because the old one which was I think refresh, migrate refresh, would try to run all your down methods. Then if any of your down methods are broken, you don't actually have an easy way to do this. What you do is instead you just run migrate:fresh and that just says delete all the tables in this database, and then migrate them fresh and then if you do dash dash seed or seed or whichever it is, I think it's dash dash seed, then you also get the fresh seeded version, all your seeders.
Matt Stauffer:
That's one of the most useful things about having good migrations and good seeders is, anytime my data gets in a bad shape, or I want a fresh install or whatever, I just do MFS or what expands to PHP Artisan, migrate, fresh, seed and then all of a sudden, I've got a perfectly functional probably, what 10 seconds later, five seconds later, I've got a brand new fresh install to work with and it's pretty freaking fantastic.
John Bonaccorsi:
Yeah, yeah, absolutely.
Matt Stauffer:
All right. Let's talk about some of the miscellany that I took notes about earlier. The first one was, when do you know that it's time to move from keeping a particular consistent set of data in the code to like ... By consistent set of data, I mean that that stuff we were talking about earlier, where we're talking about data that you need it for the app to run, it's not user data. Maybe it's a list of all your tags or a list of all your labels or whatever else it ends up being, when do you know that it's time to move that data from code just being an array and a class somewhere to the database?
John Bonaccorsi:
Yeah, that's a good question. I think I probably tend to be more aggressive than most people in putting things in the database when they could maybe go in a config file. But I'd say that anytime it gets relational, if you have like a list of states in a config file, you have 50 of those and then that's fine. But all of a sudden, if you need to store which states that the user lives in or something like that, or has been to or something like that, all of a sudden, having those states in the configuration file, you can't link the user to the state, because the state has no idea, it has no concept.
John Bonaccorsi:
Of course, there are ways you could do that. You could store the name of the state completely instead of an ID or something like that. But when you get to the point where you need to maybe query against this data, that's my first kind of like, "This should probably be stored directly in the database."
Matt Stauffer:
Yeah, same here. This is a little bit of 201 advanced stuff. But Caleb Porzio released a tool called Sushi. What Sushi does is it allows you to have an Eloquent record, or an Eloquent model that's backed not by a database century, but it's instead ... In theory, it's backed by just some ... like an array you have in your PHP. In reality, you write out that array, and then Sushi actually creates a little mini SQL like database, which is basically like a really super preferment database in a file on your device, and then it saves it in there.
Matt Stauffer:
The benefit of Sushi is that you both can store the data that you're migrating in code, but you can also get relationships-ish. I don't know if there's any constraints in relationships because you're storing that data not in the same database. But I think it does some work to basically, if you say, "I've got Sushi ID number five and that's Oregon and you say, "Oregon arrow cities," I think Sushi takes the responsibility of figuring out what ID Oregon is, then looking for the cities with that. It's still not the same because for example, you can't do a foreign key, a correctly constrained MySQL foreign key to a SQL like database, right?
Matt Stauffer:
Even if it does work the way I'm thinking right now, it's still limited. John's solution right now is absolutely the best. I think the one downside is that, it's the most robust, but it's also maybe the most work. I might start with keeping something in array or a config file. I might move into Sushi and then I might move from there into actually using a seeder like you're talking about that. But I do ... One of the downsides ... I feel I've run into a circumstance, where when the list of data that I wanted to see that way changed.
Matt Stauffer:
Let's say, they said, "There's only five tags ever. We don't want users to be able to add their tags," and later they're like, "Actually, there's only six tags ever." One of the tags is like earlier in the list, then all of a sudden your relationships could all break, and so you have to decide how am I going to handle adding that sixth tag in such a way that it doesn't break the fact that all these things are related to tag number two? I can't change which tag is tag number two.
Matt Stauffer:
But even in that circumstance, the answer, for me at least has been and I'm curious your experience has been, well add tag number six, and don't sort them by ID. Sort them alphabetically or something like that, so it doesn't matter what order they're in. Is that your thinking as well?
John Bonaccorsi:
Yeah, totally. Nothing should ever be in my mind that dependent on the ID being a certain ID. But yeah, absolutely. I'd say sorting them by the name alphabetically, or we've been in situations where they need a particular order, and you create an order column, which you order by that and that's not a big deal at all.
Matt Stauffer:
Totally. If you're a little daunted by the idea of having to maintain an order column, because what happens if I need to reorder them and then now do I have to change all of them? It is possible but usually, if you do have to change that type of thing, it's going to happen once on a small set, and you just got to deal with it. If it's happening once on a complicated set, you could write a one off PHP script that modifies all them and bumps all the ones over integer ID two, it bumps them all up by one. Not ID two, but sort two.
Matt Stauffer:
But if you're actually dealing with it in the front end, there's a ton of JavaScript and PHP libraries that make it super easy to just say, "Move sort item number four, right below sort item number two," and these libraries, whether it's a jQuery library or a view library or PHP library, take the responsibility of incrementing that sort number because this is such a common problem. I do think that the number one criticism of the idea of putting core data in via a seeder is solved by not sorting by ID.
John Bonaccorsi:
Right. Yeah.
Matt Stauffer:
Yep. I love it. For anybody for whom that was really hairy, sorry, but we're trying to get in a little bit of this miscellany. Okay, so the next one is, you said in the last couple of months, there's been some drama in the Laravel community around seeders and stuff. What's the drama? Is it a good time to talk about it or no?
John Bonaccorsi:
Yeah, I mean, sure. It's not that big of a deal. But I remember basically what this ... It goes back to my post about model factories and how you can improve them and stuff like that. But there was a point where a lot of people I think online were pushing for something like that, and the response from some people higher up in Laravel including Taylor at the time I remember he made a tweet about it was like," I never really use factories." He almost was saying like, "I don't feel the need for factories to be improved."
Matt Stauffer:
What? I missed all of this. Oh my goodness.
John Bonaccorsi:
You didn't see that?
Matt Stauffer:
No. Was it the one where you ... that issue set open forever?
John Bonaccorsi:
No, that was different.
Matt Stauffer:
I saw that one. No, I didn't see this at all. Wow.
John Bonaccorsi:
Yeah, so Taylor, at some point had been like, and he wasn't having a conversation with me, but he tweeted like, "Does anyone use ... I feel like you don't really need better factories, because I use this group things with seeders and then I have my test run, run seeders and stuff like that."
Matt Stauffer:
I feel I must have been out of commission at this point like it's vaguely familiar. Man, I use factories every day.
John Bonaccorsi:
Yeah, and the argument of course is not like that you don't use factories, because obviously even your seeders typically do use factories, so even if you're not and that was kind of the crux of...
Matt Stauffer:
But you don't need them to be better, yeah, yeah.
John Bonaccorsi:
His argument was like, "Do I need them to be better or if they're all getting shoved into seeder anyway that's named well? Who cares?" I thought that like there was ... When I read that tweet, I'm a big factory guy so when I read that I was like, there was going to be massive backlash against this.
Matt Stauffer:
You're like, "I'm stabbed in the heart?"
John Bonaccorsi:
Yeah, and I just thought everyone's going to jump on this guy and it's going to be, they're all going to be upset about it and actually it ended up being way more 50:50 than I thought it would be.
Matt Stauffer:
Interesting.
John Bonaccorsi:
A lot of people were like, "Yeah of course. I just throw everything in a seeder and call that seeder for my test and then ..." Other people were like, "No, no of course you need better factories and stuff like that. It was a whole big mess and I really thought that it was the death of better factories even being a potential thing in Laravel, and luckily again to go a little bit towards Laravel 8, Laravel 8 is shipping with improved factories that are similar to the concept I wrote about in my blog. I think I told you this.
Matt Stauffer:
I really should have recorded this one after Laravel 8. I'm so sorry. I just didn't even know this is all coming. This is awesome.
John Bonaccorsi:
Yeah. A lot of it actually is, Taylor has actually been talking a lot about this stuff, so people probably do know about it even if Laravel 8 is not out by the time that this is, obviously not when it records but when it goes out but yeah, so it ended up being that ... I think he came around and I had a chance to talk with him a little bit about it a couple weeks ago and I asked like, "I remember seeing that tweet and seemed like you were very anti the idea, now you're coming back around to it."
John Bonaccorsi:
He was like, kind of what I just said was like, he realized that, well, factories and seeders are not mutually exclusive. If factories are better, it makes seeders better. There's really no excuse not to improve factories and so that's kind of ... But there were some pretty ... People were getting pretty amped up about it for a while.
Matt Stauffer:
Get a little feisty. I like it.
John Bonaccorsi:
Yeah, it was a little spicy.
Matt Stauffer:
I like the feist and the spice about how to do things well and to help how to improve things versus like judging people for not programming the way you program or whatever other stupid spice can happen sometimes. Cool. All right. As always, I just looked at the time and realized we've been talking forever and I can keep talking forever. Okay, getting towards the end, is there anything else about migrations, factories and seeders you'd like to talk about? After this, I do want to really quickly go over your idea of class based factory. Other than that, is there anything else you'd really like to talk about on this topic?
John Bonaccorsi:
I don't think so. Not that directly relates, is unrelated to what you're referring to. I think that'd be ... Yeah, I think we can get into that.
Matt Stauffer:
Okay. Yeah, so essentially, I'm going to rely on people listening to the probably 30 minute long, 20% time podcast with you and reading your article, which I'll link in the show notes, which is titled tidying up your something with class ... Tidying up your test with class?
John Bonaccorsi:
PHP Test, yeah.
Matt Stauffer:
Okay. Yeah. Check that out and I'll link them in the show notes too. But can you give us the short version of your idea there?
John Bonaccorsi:
Yeah. Basically, if you've ever used Laravel factories, they're really great but they feel ... I think in the other podcast I said, they feel like a hammer when you really maybe want to drill. They're really great, but they're very, very simple. When you get to the point where you're making a lot of ... when you're using factories a lot and you're dealing with data that is deeply relational and every time you need to create a user, you also need to create blog posts for that user and you also need to create comments for the blog post.
John Bonaccorsi:
Basically when you're using factories like that with very related data, you can end up having a setup that's 50 lines long or something crazy. It's really wild. Basically, and that's ... The only reason that happens is because factories are by their original design, just a little dumb and not in a bad way, but they're just very simple. They're just they get data into the database. Basically the most complex thing they really do is like states and that's it, which to me was very antithetical to the Laravel way of doing things, which is that everything is so polished and so easy and so fluent.
John Bonaccorsi:
If you're writing a query with Eloquent you can probably guess without even knowing what exists that you could write a query, with just guessing method names. To me that is the experience of being a Laravel developer and factories were the one place where to me ... I can put up with a lot of stuff. I don't even ... Sometimes optimizations get released for Laravel and go, "I don't even think about that. That didn't bother me." But factories really bothered me for a long time. I was talking with a couple of the people from Titan at one of our own sites, and we got into this big long discussion about factories and how we can improve them.
John Bonaccorsi:
Basically the end of that I just realized like, "Well, why not just create a simple class, a basic PHP class, nothing, just normal PHP class that returned the factory." For instance, if you would normally do like factory user, create and then pass in an array of data for that user with a name and an email, whatever it may be, what if instead of that you had a user factory class with a create method, and you pass the array to that method and then that method passed it directly to the factory. If you're listening to this, you might think like, "Well, who cares?"
John Bonaccorsi:
That's just a direct ... You're just abstracting away the factory create method. But in reality, what's actually happening there is that you're unlocking the power of object oriented programming. Once you're inside of a class, you have the ability to make fluent methods and you can change chainable methods or write methods that are whatever you want. The simplest way that I can outline this idea and the topic of the blog post is that, what I call class based model factories are really just simple classes that return factories, and then you can add whatever methods you want to them.
John Bonaccorsi:
In our other example of, if you need a user with blog posts and comments for those blog posts, instead of saying, "User factory create and then blog create," and then you pass the user ID to the blog, and then you create the comments and then you pass the comments to the blog, and then all of a sudden you're 10 lines deep. Instead of that, what you do is you just say, "User factory with blog posts three, with comments 10 and create," and all of a sudden your 10 line monstrosity has become a one line readable-
Matt Stauffer:
Super expressive, yeah.
John Bonaccorsi:
... piece of code that reads like a book. That to me was much more in line with what the rest of Laravel felt like.
Matt Stauffer:
Yeah, and when I first heard about the idea of class based factories, model factories, I assumed it was going to be more like repositories which were very popular in Laravel and thankfully aren't anymore, where people would just write these, you'd have one method that would be something like colon, colon, with three users and five, whatever's and then there'd been message right after it, there'd be like with five users or whatever. This idea of being a fluent chain where you can add and modify, it feels so much more Laravelly and it feels so expressive.
Matt Stauffer:
I love the idea that I can write those sentences. But I can write them by chaining, by fluent chaining not write them by massive method names. If I don't need comments, I just leave off the method, the comment method or whatever, then I'm good to go. I love how it reads. I love how it simplifies things too.
John Bonaccorsi:
Yeah, they're pretty ... To me, they've been very powerful to change the game for factories for me, so I've enjoyed working with them.
Matt Stauffer:
Total side note, but yesterday I wrote a test that had I think 12 lines of mocking setup code. Now, I'm totally disconnected from this thinking like, "Can I build class based mocking arrays?"
John Bonaccorsi:
Mocking.
Matt Stauffer:
Yeah, could I do that? I'm now actually super curious. I might have to look at that after this. Yeah, you totally good. Okay, cool. What are some good ways for people to learn about this? I'm going to link to your interview in 20% time, I'm going to link to your Laracast, the Laracast talking about your way of doing it and I'm going to link to your blog post. Those are all about the specific context of class based model factories. But what about in general, how do you learn about migrations, factories and seeders?
John Bonaccorsi:
Yeah, it's a good question. I think that luckily the Laravel documentation itself is unlike most other frameworks or tools in general that it has phenomenal documentation. I'd say if you want to learn about them, definitely read obviously Laravel documentation. Of course, there's Laracast, which has a video for Laravel up and running for almost any, just from scratch to Laravel six and seven and whatever it may be. There's of course this great book that a phenomenal man wrote, named Laravel Up and Running, which just a really great guy and that has everything you would ever dream of needing.
John Bonaccorsi:
Just forget everything else I said and just read that book. I'd say those are your three core ones there. Anything else is just read some other open source projects. Luckily, I think the beautiful thing about this, everything that we talked about today even my concept of class based model factories, which maybe sounds scary, because it's like four words or whatever, but they're all simple. They're all simple concepts. There's always going to be a learning curve for anything that you're learning if you're new to it, but they are going to be things that you're doing everyday in any project, and it won't take you long to get a grasp on them. Books Laravel Up and Running, Laracast, documentation, you're set to go.
Matt Stauffer:
I love it. All right, so the last thing I do on each of these before plugs and how people can follow you is the fun moment, which as you're aware, you have no idea what it is when it's coming. At Titan, we often will respond to things that you say with a little emoji, that is the TV Guide logo. I'm not going to say too much more from there. But I do want to ask you as someone who knows a lot about TV, what do you think the best TV show of all time is?
John Bonaccorsi:
Yeah, my favorite TV show of all ... This is easy for me.
Matt Stauffer:
That was it. I didn't know that.
John Bonaccorsi:
Yeah, Avatar, The Last Airbender is my favorite TV show of all time. I think you're getting into it, you're watching it right now, if I remember correctly.
Matt Stauffer:
Yeah. My son and I are almost through the first season and it's freaking fantastic. I love it and I'd love to talk about it.
John Bonaccorsi:
Yeah, my dog is named Appa, which is after the character on the show. You might look at it and look at clips of it, you might think it's a kid show and it was designed for a younger age, and I was like 15 when I started watching.
Matt Stauffer:
It's accessible for kids.
John Bonaccorsi:
Oh, yeah. Yeah, it's great for them and it also has really deep storylines for adults. I love it and I still watch it. I just re-watched it, so it's great.
Matt Stauffer:
Yeah, literally every single time his sister's asleep because it's a little too scary for her he's like ... He'll come ... Let's say all three of us fell asleep for a nap at the same time or something like that, if he wakes up early, he'll come poke me and wake me up and like, "Let's go watch avatar." I'm like, "Okay," because I love it too.
John Bonaccorsi:
I do the same thing with my wife.
Matt Stauffer:
"Come on, let's go watch Avatar." She's like, "Just watch it by yourself." I love it. That is fantastic. See, I thought as someone who has a lot of opinions and thoughts about TV that you'd be like, "Oh, this is so hard. There's so many good shows." Wow, that was that was such a fantastically quick response. All right, cool. Avatar, Last ... It's on Netflix for anybody who's curious.
John Bonaccorsi:
It's on Netflix, and they're even making a live action version.
Matt Stauffer:
Live action TV version, though right?
John Bonaccorsi:
TV version. Yeah, they already made a terrible movie.
Matt Stauffer:
They made a movie that everyone says, "Don't even watch."
John Bonaccorsi:
Don't watch it.
Matt Stauffer:
I saw the thing about a live action TV version. I hope it's really good. This is going to be exciting. Okay, so last thing how can people follow you? Where are you on Twitter? What other mediums? What's your side project, all that kind of stuff?
John Bonaccorsi:
Oh gosh. I have about 400 followers on Twitter and I can't handle one more so don't follow me anywhere. I've maxed out.
Matt Stauffer:
Okay, there you go.
John Bonaccorsi:
It's too much responsibility for me. Yeah, follow Titan Co on Twitter. That's where you'll find anything that is actually relevant or interesting that I do anyway will most likely be retweeted. Follow the Titan blog. That's where I'll write anything that's actually worth reading. Those are the core things. If you are by an odd chance a fan of the TV show Big Brother, which I know most people here have probably never ever heard of ...
Matt Stauffer:
No, I don't think so. I think most people have heard of it, right?
John Bonaccorsi:
If you've heard of it or maybe you've maybe heard about 20 years ago, and you've forgotten about it, but I watch it. I have a side project called Fantasy BB.com, where it's like fantasy football for Big Brother. It's like ..
Matt Stauffer:
I love it.
John Bonaccorsi:
It's the one thing that I will plug, so if you're a fan of the show, check out that.
Matt Stauffer:
It's free, right?
John Bonaccorsi:
Yeah, it's free. It just costs me money. It's not free to me.
Matt Stauffer:
Yeah, right. I wish that I watched Big Brother because the idea of playing fantasy, because it's the idea of with that Survivor thing, where people get voted off or something like that. I feel like ...
John Bonaccorsi:
Yeah its basically Survivor but in the house.
Matt Stauffer:
I feel like you should ... No, I don't think you should. I would love to do that for every show I ever watched that was like that, where people get voted off. I feel there should be, you should make a sub-domain for each one like Big Brother dot whatever, fantasy reality TV shows dot com or stuff like that. Of course you have enough work on your plate right now. But wish I watched Big Brother because that sounds like so much fun, especially if you and your friends watch it across the country every week or something like that. That's so cool. All right, John Bonaccorsi, you are wonderful. I so much appreciate your time. Thank you so much for teaching us and sharing with us and just being a good guy.
John Bonaccorsi:
Yeah, thank you for having me. I'm a longtime listener, first time caller here so this has been great.
Matt Stauffer:
I love it. All right. Thank you all and we'll see you all next time.
John Bonaccorsi:
See you.