laravel / blog-contest-may-mayhem

240 stars 16 forks source link

The Good, the Bad and the Ugly of seeding data in production #90

Open Elhebert opened 6 years ago

Elhebert commented 6 years ago

https://dieterstinglhamber.me/the-good-the-bad-and-the-ugly-of-seeding-data-in-production

connectkushal commented 6 years ago

nice article, was useful. thanks :)

Lloople commented 6 years ago

Currently applying it at work. Good explained and useful information 🙂

rizqidjamaluddin commented 6 years ago

I'd personally suggest using artisan commands specifically geared towards adding production-level data. Make them idempotent - check for data's existence before inserting anything - and make sure they're all properly wrapped in a transaction so it doesn't fail halfway through.

Then you simply attach that artisan command to your deploy script of choice, and add it to your readme setup so new developers know about it. By making the command idempotent, you can safely call it on every deploy, and you can just add more stuff to it as time goes on. I usually wind up adding an artisan app:setup command for my projects, which sets up default roles and admin users if they don't exist yet.

This is definitely a good and relevant topic to bring up for discussion - I think the pattern should be used more!

cwhite92 commented 6 years ago

The idea in general is sound, I often use migrations to seed production values. For example if I add a post_statuses table, I might use the DB:: facade to insert some statuses from within the same migration.

What I'd suggest you avoid is calling artisan commands or using Eloquent models in your migrations. Your migrations are meant to be immutable. Once they're run on production, they shouldn't change (any additional changes should be additional migrations). Artisan commands and Eloquent models are not immutable, they evolve over time in response to changes in requirements.

There might be a migration from three months ago that uses an Eloquent model to insert some values into the database. It's worked great for three months, but because of some new feature or bug fix, a developer has to change that Eloquent model and slightly modify its behaviour. Now that migration from three months ago has silently changed its behaviour as well. You may not think it's a big deal, the migration has already run in production. But if you ever need to migrate your local database from scratch, or heaven forbid, roll back that migration, it won't work the way it did 3 months ago.

So in general, I very much like seeding simple prod values from inside migrations. But only static values using the DB::insert() facade because you can guarantee that it will work for that point in time. Anything more complicated should use a separately run artisan command like @rizqidjamaluddin mentioned. Just my $0.02 :)

Elhebert commented 6 years ago

Thanks for the feedback! Lots of useful information there.

@rizqidjamaluddin I hadn't thought about using transactions, definitely a great idea! Going to do this from now on.

I also like the idea of having a single Artisan command to handle the setup of the app, but sometimes the data added after the initial setup isn't really there to set the app up. And from a naming point of view, it bugs me a bit 🤔

@cwhite92 I hadn't thought about Artisan command not being immutable, that a good point. As for Eloquent Models, I never use them for seeding purposes, I tend to seed static data with ye ol' DB::insert.