Come usare (e non usare) i Seeder in Laravel

1
760

Qualche giorno fa ho pubblicato un articolo sulle migration in Laravel che ha suscitato molto interesse, più di quanto mi aspettassi. Nel pubblicarlo in giro, in tanti mi hanno fatto qualche domanda sui Seeder.

Se le migration sono uno strumento molto usato ma poco compreso nel profondo, i Seeder vengono adoperati sensibilmente meno. Onestamente, non ne capisco nemmeno il perché, vista la loro comodità.

In questo articolo parlerò un po’ di di Seeder, di come funzionano e di quanto mi hanno aiutato nel lavoro di tutti i giorni.

Cosa sono i Seeder?

Partiamo con le basi. Al volo eh, sono pigro.

I seeder sono classi molto utili del framework che ci permettono, in modo relativamente semplice, di aggiungere dei dati di test nel nostro database. Tendenzialmente si trovano in database/seeders e, nonostante in questa directory possiamo già vedere un primo DatabaseSeeder.php, in realtà ne possiamo creare quanti ne vogliamo.

Ogni seeder ha un metodo run, eseguito quando la procedura di seeding viene avviata.

Dentro questi metodi run possiamo fare generalmente due cose:

  • scrivere dati di test sul database: ad esempio, per preparare il database con i dati che servono a lavorare in locale con la nostra app;
  • eseguire altri seeder: una delle cose che preferisco, perché in caso di sistemi più complessi mi permette di preparare dei seeder che combinano altri seeder insieme;

Alla luce di queste due possibilità, analizziamo qualche caso d’uso pratico dei seeder.

Preparare i dati per lavorare in locale

Partiamo dal caso base. Una delle cose che faccio spesso è creare tanti seeder quante sono le entità di cui ho bisogno per lavorare in modo accettabile con un database in locale. Dopodiché, prendo questi seeder e li richiamo tutti dal seeder principale.

Supponiamo di aver creato quattro seeder per un mio ipotetico blog: UserSeeder, PostSeeder, TagSeeder e CategorySeeder. Non devo dirvi che dati vanno ad aggiungere, vero? A quel punto, li richiamo dal DatabaseSeeder principale.

Così facendo, mi basterà semplicemente un

per iniziare a lavorare sulla mia app. Senza considerare, a questo punto, quanto è semplice coinvolgere un altro collega se l’ambiente di sviluppo è così semplice da tirare su.

Preparare i dati per i test

Altra cosa che faccio spesso, con i seeder, è crearne di specifici per i miei test. Qualche tempo fa ho lavorato ad un’applicazione che prevedeva un piccolo motore di ricerca interno per video, un’entità fondamentale dell’app stessa.

Ora, prima di procedere dovete sapere due cose:

  • usando il trait Illuminate\Foundation\Testing\RefreshDatabase in un test, possiamo resettarne i contenuti ad ogni nuovo test;
  • grazie al metodo seed che questo trait ci mette a disposizione, è possibile far corrispondere ad ogni TestCase (o singolo test, perché no) un set di seeder specifici;

Ora, in questa app a cui stavo lavorando avevo già un seeder VideoSeeder. Tuttavia, volevo qualcosa di più specifico per il motore di ricerca. Così, mi sono creato un altro seeder SearchVideoSeeder, specifico per tutto quello che riguarda i video “da cercare”. In questo modo:

  • mi sono gestito con calma un po’ tutti i casi di cui avevo bisogno;
  • non ho rotto nessuno dei test precedenti, basati sul VideoSeeder base;

Meno test rotti = cliente più contento = meno sbattimento = Francesco più contento.

Preparare i dati per lavorare con feature specifiche

Concludo questo piccolo excursus sui seeder per parlare meglio di una cosa che mi hanno chiesto in tanti questi giorni. In un modo o nell’altro, la domanda di base è:

  • Cosa faccio se devo cambiare branch e i dati che ho non sono consistenti?

Questo è esattamente il caso d’uso perfetto per i seeder. In generale, infatti, quando lavoro con branch diversi mi comporto così:

  1. mi assicuro che ci siano i seeder con i dati giusti per ogni branch a cui lavoro. In questo, avere più seeder piccoli (invece di un grande seeder che fa tutto) rende il flusso di lavoro molto più veloce. In caso di progetti complessi arrivo tranquillamente ad avere seeder che richiamano seeder che richiamano seeder;
  2. applicando lo stesso principio alle migration, mi assicuro che ci siano tutte le migration necessarie a riprodurre il mio database per come mi serve;

Proviamo ad immaginarci un esempio di questa situazione:

  • ho un blog, i cui post possono fare uso di tag. In questo momento, i tag sono rappresentati come un array JSON all’interno dell’entità post stessa;
  • in una successiva iterazione decido di poter taggare anche i media che carico sul sito. L’array JSON in Post, quindi, non mi basta più. Devo creare una tabella “tags” a parte;

Come mi comporto?

  • sul branch principale avrò una migration della tabella post con relativo campo “tags”. Il mio seeder PostSeeder si occuperà anche di aggiungere dei tag a caso per i miei post;
  • sul branch della nuova feature, invece, avrò le migration necessarie a creare la tabella dei media e quella dei tag. Di conseguenza, il mio PostSeeder non si occuperà più di popolare i dati in “tags” (quel campo non esiste più in Post!) ma avrò altri due seeder, uno dedicato ai Media ed uno dedicato ai Tag (che magari si occuperà anche di mettere questi in relazione con i vari post e media);

Se da fuori può sembrare tanto lavoro, pensiamo bene al fatto che tutto questo dovremo farlo una sola volta. Una volta impostato il lavoro, potremo tranquillamente passare da un branch all’altro ed eseguire

tornando operativi in tempo zero.

In generale, la regola che seguo è: mi trovo ad avere difficoltà quando cambio branch? Ok, è arrivato il momento di aggiungere/modificare/cancellare qualche seeder.

Concludendo

Insomma, così uso i seeder in Laravel. Sono davvero tanta roba e mi aiutano tantissimo nella vita di tutti i giorni, soprattutto quando mi trovo in un periodo in cui lavoro a progetti diversi.

Sapere che due comandi mi permettono di ricreare con certezza assoluta un ambiente di lavoro “sicuro” dal punto di vista della consistenza dei dati è qualcosa che per me ha un valore notevole.

Voi li usate? Qualcuno vi ferma dal farlo? Denunciatelo. Qualcosa vi ferma dal farlo? Fatemi sapere che ne pensate! Spero di esservi stato utile.