Home Blog

La mia prima applicazione con Laravel Jetstream e Livewire, in 48 ore. Ecco com’è andata

0

L’articolo di oggi inizia con un problema: mi sono scordato di pagare un dominio. Sforo di poche ore, niente di pazzesco, e recupero tutto immediatamente. Il mancato pagamento in tempo, però, crea un po’ di casino nei DNS e, per un paio di giorni, il sito non è raggiungibile. Odio questi contrattempi.

Ora, per vari motivi mi capita di comprare un bel po’ di domini ogni anno. Il mio provider, nel mandarmi i reminder, fa un bel mischione e sempre più spesso i domini più importanti spariscono in mezzo ad altri cinque/dieci alla volta.

Come ogni dev che si rispetti, mi sono detto: “perché non scrivermi da zero un piccolo software che mi ricorda dell’imminente scadenza?”

Essendo appassionato di prodotto, secondo voi, potevo mai scrivermi un semplice tool da linea di comando? Certo che no. Così è nato domain-check.it.

E da qui la sfida che mi sono proposto: creare un piccolo Saas ed usare Laravel Jetstream insieme a Livewire, di cui ho parlato qualche tempo fa con l’ottimo AlessandroEssendo un progetto piccolo ed avendo altre incombenze, mi sono messo una scadenza molto precisa: Domenica 2 Maggio 2021. Praticamente due giorni, considerando che sono partito Venerdì 30 Aprile, sul tardi (6 di pomeriggio).

In questo post racconterò com’è andata.

Le Premesse

La chiacchierata con Alessandro mi aveva intrigato non poco. Chi mi conosce sa bene quanto amo fare prodotto, sperimentare, lanciare un progetto e capire se risolve un problema. Da fuori (non l’avevo mai provato prima) avevo fatto qualche ipotesi su Livewire e Jetstream:

  • vanno bene per i progetti piccoli / mvp;
  • per progetti più grandi, il “mischione” di codice può diventare un problema;

In base a queste considerazioni mi sono posto i primi obiettivi:

  • l’applicazione deve fare due cose in croce, non di più;
  • non è necessario che vada divinamente su mobile;
  • non deve essere perfetto;
  • deve essere un minimo accattivante graficamente;
  • l’applicazione deve passare dalla mia testa al server in pochissimo tempo;

Bene. Come si fa?

Fatti delle domande prima di agire

Più che “come si fa”, innanzitutto mi sono chiesto “che si fa?”

Ho iniziato a buttare giù una prima serie di idee di feature per la prima release dell’applicazione. Non importa da quanto tempo scrivi software, è sempre una delle cose più difficili, perché la mente viaggia ed inizi a tirare dentro di tutto.

Ho così delineato le prime feature di base:

  • devo poter aggiungere/rimuovere dei domini da tenere sotto controllo;
  • voglio ricevere una mail quando il dominio sta per scadere;
  • voglio ricevere una mail quando il certificato SSL sta per scadere;

Oltre a questa feature base, ne ho voluta aggiungere un’altra “bonus”:

  • devo poter aggiungere/rimuovere domini non miei ma che voglio sapere se e quando torneranno liberi;
  • voglio ricevere una mail quando questi domini tornano liberi;

Sono davvero due feature, nulla di più. La cosa bella, però, è che da ognuno di questi punti, apparentemente semplici, si possono scatenare un’infinità di domande:

  • cosa devo salvare di ogni dominio?
  • come avviene il controllo del certificato? e della scadenza del dominio? ogni quanto?
  • quando devo ricevere la mail?

Ecco, questo è il momento in cui scatta il panico, ed è notoriamente più difficile muoversi.

Datti le risposte prima di agire

Quando entro in questa fase è davvero semplice perdere il controllo. Mi è capitato tantissime volte, in passato. Così adotto una tecnica semplicissima: parto da una feature e la riduco all’osso ogni volta che vedo possibilità di personalizzazione. Esempio:

  • Domanda: ogni quanto devo controllare se è il caso di mandare una mail per ricordare dell’imminente scadenza? Devo inviare più di un alert?
  • Risposta: una volta al giorno è più che sufficiente. Zero possibilità di personalizzare l’orario di invio, per il momento, alle 9 di mattina della timezone dell’utente è ok. Un solo alert, 3 giorni prima, basta e avanza.

Qui entra in gioco un concetto fondamentale che prima facciamo nostro e meglio è: le supposizioni che faccio sono, appunto, supposizioni. Possono essere vere o false, ma prima mi butto, prima so se effettivamente la mia supposizione è giusta, e se è sbagliata posso correggere il tiro velocemente.

Insomma, citando Tony Stark: “un bullone sì ed uno no, non devi farmi bello“.

Così alla fine ho delinato le feature principali in modo molto più preciso:

  • avere una lista di domini “sotto controllo”;
  • una volta al giorno faccio un check sul dominio (se richiesto) ed un check sul certificato (se richiesto). Se le scadenze si avvicinano, mando la/le mail;
  • avere una lista di domini non miei, ma che voglio sapere quando torneranno liberi;
  • una volta al giorno faccio un check sul dominio, se è libero mando la mail;

Per rendere l’app più “amichevole”, chiedo all’utente la sua timezone e faccio in modo che qualsiasi alert gli arrivi per le 9 di mattina nel suo fuso orario. Motivo: sono ragionevolmente certo che una mail di una scadenza alle 3 di notte non sia molto comoda.

Bene: possiamo scrivere codice.

Il primo impatto con Jetstream

Come prima cosa, ho avviato un nuovo progetto Laravel e ho installato Jetstream seguendo la documentazione, molto chiara. Ho deciso di installare la versione full-featured con i team (tanto all’inizio si possono disabilitare). Come il titolo lascia intendere, ho scelto il setup con Livewire.

Mi sono preso un po’ di tempo per esplorarlo. Un paio di chicche sono interessanti:

  • la possibilità di aggiungere in modo abbastanza semplice informazioni aggiuntive a quelle già presenti sulla tabella utenti;
  • il sistema di feature, che permette di spegnere/accendere specifiche funzionalità del boilerplate;

Spente le feature non necessarie (team, 2FA e qualche altra chicchetta) mi sono concentrato sulla creazione dei primi componenti. Il boilerplate di base che Jetstream offre è impressionante. A ben pensarci, la mia app deve “gestire” tre cose:

  • Utenti;
  • Domini;
  • Domini non miei da tenere sotto controllo;

Già al momento zero Jetstream mi ha tolto il 33% del lavoro da fare.

Dopo aver creato le prime migration ed i model, passo a Livewire…

Il primo impatto con Livewire

Livewire mi ha messo davanti ad una delle cose più difficili per uno sviluppatore: disimparare.

Ho notato, infatti, che spesso più andiamo avanti e più tendiamo a voler “fare le cose per bene”. Che è paradossale se ci si pensa: spesso studiamo cose che stanno agli antipodi (mi viene in mente lo studio di un linguaggio funzionale venendo dagli oggetti), ed applicare la nostra esperienza a quelle cose, per quanto naturale ci possa venire, è la cosa più sbagliata possibile.

Ci sono un po’ di cose che mi hanno fatto storcere il naso, di Livewire: una su tutte, il fatto che mi piazza le classi con le logiche dei componenti appena generati in “App/Http”, che generalmente associo al backend.

In un primo momento ho sentito un brivido percorrermi la schiena: venendo da React, vedere mischiato un metodo “render()” di una classe piazzata in una cartella chiamata “App/Http” mi ha fatto un po’ senso.

Poi ho ricordato: disimparare. E quindi sticazzi. Buttiamoci, vediamo come va e POI valuto.

Dopo la timidezza iniziale ho preso dimestichezza con il modo in cui i componenti vengono creati e mi sono messo l’anima in pace. Ho fatto tutto in poche ore riuscendo, comunque, a tenere i componenti abbastanza in ordine.

Il primo impatto con Tailwind

Per creare l’interfaccia utente, oltre a Livewire, mi sono affidato a TailwindCSS per avere un’impostazione decente di base.

Ora, il principio alla base di Tailwind è l’ampio uso di utility class. Questo significa che buona parte dei nostri tag HTML saranno infottati di classi css per qualsiasi cosa.

Il concetto è spiegato magnificamente qui.

Anche qui, questa faccenda può piacere o meno. All’inizio ero diffidente poi ho cercato di guardare le cose più dall’alto e ho capito meglio: ci sono talmente tante classi per tante situazioni che il 95% dei casi è abbondantemente coperto.

Per andare più veloce, ad ogni modo, ho “barato”: avendo bisogno di alcuni componenti leggermente più complessi (tabelle, widget ed altre piccole cose), ho comprato i componenti marketing + app su TailwindUI.

Nota: ho comprato il pacchetto completo (marketing + app) per potermi sbrigare anche a fare la home page.

Qui vale la pena fare un’osservazione: sono stati 200 euro ben spesi, se penso che mi hanno evitato ore ed ore di lavoro inutile.

Va detto che TailwindCSS di base è piuttosto scarno e manca di tanti elementi che secondo me andrebbero resi disponibili di default gratuitamente. Ma è una mia opinione e non vale una mazza. In ogni caso peace, non è una grande spesa quindi va bene così.

Alla fine della fiera, in questo modo, per un progetto piccolo o comunque poco esigente, hai tutto quello che serve per consegnare il tuo lavoro in tempi ragionevoli, se non record.

Un ecosistema che funziona

La cosa che mi piace di più dell’ecosistema di Laravel è che funziona. Ho tracciato un po’ il tempo usato per realizzare domain-check.it, ed ecco il breakdown:

  • analisi iniziale: circa 2 ore;
  • creazione del logo/icone/asset con Canva: 2 ore;
  • implementazione dell’applicazione: 12 ore;
  • implementazione dell’admin panel: 0.5 ore con Laravel Nova;
  • realizzazione della home page: 2 ore;
  • deploy sul server di produzione: 1.5 ore con Laravel Forge;

Quindi sì, nel titolo ho detto una stronzata 🙂 Non 48 ore, ma 20.

Questo ovviamente non è stato possibile perché sono bravo o bello, ma perché semplicemente l’ecosistema di Laravel è composto da tanti piccoli strumenti, free o meno, che lavorano in perfetta sinergia tra loro.

Ho già citato Nova e Forge, ma è stato fondamentale avere un sistema di code up and running in poco tempo con Horizon. Gratuito. Anche Jetstream è gratuito, e fa uso di altri package come Fortify.

Insomma, tanta bella carne al fuoco.

Concludiamo!

Millecinquecento parole dopo, cosa ho imparato da questa esperienza?

  • al contrario di quanto pensassi da “esterno”, Laravel Jetstream riesce a dare un notevole contributo, sul serio. Fornisce quello che serve per partire alla grande ed il sistema a feature è facilmente configurabile;
  • per Livewire e Tailwind c’è solo una considerazione da fare: non sono adatti a qualsiasi tipo di progetto, ma fanno il loro lavoro a dovere in caso di progetti non troppo grandi, o in caso di progetti anche grandicelli ma con tante interazioni semplici;

All’inizio dell’articolo avevo supposto come use case ideale l’applicazione piccola.

Adesso inizio a pensare che anche per una di “media” grandezza (in termini sia di utenti che di feature) possa cavarsela senza troppi bagni di sangue.

Vi aggiorno 🙂

Creare un’API GraphQL con Laravel? Ci pensa Lighthouse! – Parte 2

0

Direi che è arrivato il momento di concludere il nostro piccolo viaggio introduttivo alla scoperta di come creare un’API GraphQL con Laravel. Nell’articolo precedente, pubblicato un paio di settimane, fa, avevo spiegato le basi di Lighthouse e di come usarlo per creare, facilmente, un’API GraphQL usando il nostro framework preferito.

L’ultima volta ci siamo lasciati dopo aver visto, un po’ più da vicino, le prime query sulla nostra entità Movie.

Oggi vedremo più da vicino come funzionano le mutation, come vengono gestite le relazioni tra entità e, infine, qualche esempio su altri tool che Lighthouse ci mette a disposizione per facilitarci il lavoro. Pronti? Partiamo dalle…

Creare un’API GraphQL con Laravel? Ci pensa Lighthouse! – Parte 1

1

Ultimamente, nel mio gruppo Facebook preferito, mi trovo spesso a parlare di quali argomenti affrontare su questo blog. L’ultima volta è toccato al Deploy di un’applicazione Laravel su Kubernetes, che pare abbia dato notevoli soddisfazioni.

E oggi? Beh, questa volta daremo uno sguardo, insieme, a come possiamo mettere su senza troppi problemi un’API GraphQL con Laravel. Con l’aiuto di un package davvero speciale: Lighthouse!

GraphQL? Cosa?

Tecnicamente, GraphQL è definibile come un linguaggio da usare per richiedere e manipolare dati via API. Lo ha tirato fuori dal cilindro Facebook, ormai nove anni fa, prima di essere rilasciato pubblicamente nel 2015. Se si vuole studiare nel dettaglio il linguaggio in questione, questa è la fonte ufficiale a cui attingere.

Non mi dilungherò in ulteriori spiegazioni albertoangiolesche, ma gli elementi che bisogna conoscere per iniziare lavorare con delle API GraphQL sono tre:

  • Schema: come il termine suggerisce, è uno schema che descrive nel dettaglio tutte le possibili richieste che un client può fare all’API che costruiremo. Ad ogni chiamata, l’API verificherà tramite questo schema che quella in arrivo sia, effettivamente, una chiamata valida;
  • Query: l’operazione più semplice da fare, in un’API GraphQL, è chiedere dei dati. Una query è esattamente questo: un’operazione di lettura dei dati dal servizio;
  • Mutation: nel momento in cui abbiamo bisogno di modificare qualche dato, allora tocca usare una mutation. Il termine, infatti, descrive ogni operazione di modifica dei dati dell’API;

Rispetto ad una “classica” REST API, ovviamente, ci sono un po’ di differenze. Per citarne alcune:

  • un solo endpoint da interrogare, a differenza di diversi endpoint per REST;
  • per poter usare un’API GraphQL bisogna un po’ impratichirsi nel costruire delle query;
  • in GraphQL è possibile richiedere solo i dati di cui abbiamo effettivamente bisogno, un vantaggio non indifferente;

Due delle API con cui ho lavorato di più in tutta la mia vita sono GraphQL: quelle di Facebook Shopify.

E con Laravel?

Creare una GraphQL API con il nostro framework PHP preferito è, devo ammetterlo, sorprendentemente semplice. Esiste un package, infatti, chiamato Lighthouse, che semplifica di molto la vita dello sviluppatore in questo senso.

Vediamo quindi come installarlo e come prepararlo.

Installazione

Supponendo di avere un progetto “fresco” di Laravel, la prima cosa da fare è installare il package in questione, insieme ad un comodo tool per fare qualche test.

  • Laravel GraphQL Playground è un’utilissima web app, accessibile da browser, che possiamo usare per fare le nostre prime richieste all’API che stiamo costruendo;
  • Pubblicare il file schema di default, invece, ci permetterà di avere a disposizione un primo schema da usare come riferimento per le nostre query. Il package lo userà automaticamente per fare quasi tutto il lavoro!

La prima chiamata API

Visto che so bene quanto vi piace mettere le mani nella ciccia già da subito, vi accontento. Proviamo subito questo package, no?

Andiamo a curiosare nello schema che è stato pubblicato in graphql/schema.graphql.

Possiamo notare principalmente tre cose:

  • Troviamo un tipo User già definito. Corrisponde all’utente di una qualsiasi applicazione Laravel appena creata;
  • All’inizio del file troviamo due definizioni di scalari: Date DateTime. Sono delle definizioni che Lighthouse usa per trasformare automaticamente le date dei timestamp;
  • A metà del file, invece, troviamo le prime due query! Precisamente, il package ci mette a disposizione una query per recuperare tutti gli utenti dell’applicazione, ed una invece per recuperare i dati di un utente specifico;

Possiamo trovare più informazioni su come leggere questo file qui, sul sito di GraphQL, nella sezione dedicata al linguaggio usato per lo schemaDetto questo… facciamo subito una prima chiamata!

Per prima cosa, accediamo a Laravel Tinker per aggiungere al volo un po’ di dati di prova.

Fatto questo, accediamo al Playground andando a visitare http://localhost/graphql-playground. Inseriamo questa query nel pannello a sinistra:

e clicchiamo sul tasto “Play” per eseguire la query.

Già qui possiamo testare una delle cose più interessanti delle API GraphQL: proviamo a togliere “email” dai campi richiesti. La query verrà eseguita lo stesso, ritornando effettivamente gli stessi dati senza, però, la mail dell’utente. Niente male, per non aver scritto nemmeno una riga di codice, no?

Ok, adesso aggiungiamo qualcosa di “nostro”.

Un po’ di cinema!

Ho immaginato una piccola API per gestire film. Quelli che torneremo a vedere al cinema molto presto (spero). Senza strafare, partiamo da qualcosa di molto basilare.

Questo comando genererà il model, la migration ed una factory. Nella migration, aggiungiamo due colonne:

  • title, il titolo del film (string);
  • year, l’anno di uscita (uno small int sarà più che sufficiente);

Nella factory, modifichiamo il metodo definition così:

Non aggiungeremo altro per ora. Non scordiamoci di eseguire php artisan migrate e di generare qualche record di prova per la tabella dei film:

Bene, è tutto.

Torniamo al nostro graphql/schema.graphql. Seguendo la traccia di quello che abbiamo visto prima, dobbiamo aggiungere una definizione per la nostra nuova query. Proprio come per gli utenti, infatti, definiamo…

Cosa abbiamo aggiunto?

  • In fondo al file, la definizione del type Movie, che GraphQL riconoscerà adesso come Movie valido. Gli attributi sono quelli che abbiamo creato con la migration;
  • Tra le query, la prima, quella che ci permette di ottenere (paginati) tutti i film inseriti nel database.
    Nota: in generale preferisco usare la paginazione “CONNECTION”, che fa uso di un cursore. Potete trovare più dettagli a riguardo qui.
  • La seconda query invece è quella che ci permette di ottenere i dati di un singolo film partendo dal suo ID;

Fatto! Possiamo provare la nostra API. E no, non serve scrivere altro codice… bello, vero?

Riapriamo il playground e proviamo la query paginata:

O magari quella di ricerca tramite ID:

Insomma, neanche una riga di codice da scrivere, solo la specifica da compilare. Certo, questo è un caso molto basilare… cosa succederà in situazioni più complesse?

Nella prossima parte di questo articolo, vedremo insieme:

  • come definire ed usare le mutation, per modificare i dati della nostra API;
  • andare oltre le basi del CRUD e creare una logica “custom” più complessa;
  • come rappresentare le relazioni tra model, ed usare la stessa query in casi d’uso totalmente differenti tra loro;
  • altre funzionalità offerte da questo package, come l’uso del throttling per evitare abusi da parte di altri sviluppatori, la validazione dei dati in input, l’ordinamento dei dati e l’uso di middleware per mettere in sicurezza la nostra API!

La seconda parte arriverà tra qualche giorno (update, la seconda parte è qui)… quindi rimanete nei paraggi! Se volete, posso avvisarvi io tramite la newsletter! Potete iscrivervi su questa pagina oppure usare il form a lato.

A presto!

Deploy di un’applicazione Laravel su Kubernetes – Parte 3

0

Bene, è il momento di concludere questa serie di articoli in cui ho deciso di raccontare, scendendo un po’ più nel dettaglio, di come ho fatto il deploy di un’applicazione Laravel su un cluster Kubernetes.

Dove eravamo rimasti? Facciamo un piccolo recap, prima di procedere:

  • Nella prima parte di questa serie mi sono dedicato a quelle che sono state le mie necessità prima di arrivare a considerare una soluzione Kubernetes managed per la mia app. Non sono partito da Kubernetes da subito, non ne avevo bisogno e col senno di poi è stata la scelta giusta;
  • Nella seconda parte, invece, ho iniziato a mettere le mani in pasta. Ho spiegato come ho creato i vari componenti di cui avevo bisogno, dal cluster ai database, per poi passare dalla creazione dell’immagine da usare ed, infine, arrivare alla creazione delle varie risorse sul cluster;

Oggi ci occuperemo di quello che rimane. Vedremo, infatti:

  • come gestire la questione dei worker delle nostre code: l’applicazione che ho realizzato, infatti, fa un uso intensivo delle code. Su questo ho anche una chicca da condividervi, quindi continuate a leggere…
  • come gestire il discorso dei cronjob: altra parte fondamentale della mia app, smanettando e sperimentando ho scoperto un altro paio di cose interessanti che vi faranno risparmiare qualche mezz’ora di grattacapi;
  • lo spiegare a Kubernetes come e quando lanciare le migration, al termine di un deploy, nel modo “giusto”, o comunque più coerente;

Deploy di un’applicazione Laravel su Kubernetes – Parte 2

1

Continuiamo il nostro viaggio alla scoperta del deploy di un’applicazione Laravel su Kubernetes. Nell’articolo precedente, che vi consiglio di leggere se non l’avete già fatto, ho introdotto il tema parlando di come ho concepito il lavoro da fare e le motivazioni dietro le mie scelte.

Oggi, però, è il giorno in cui iniziamo a mettere le mani in pasta.

Quindi: cosa vedremo?

  • partiremo con la creazione di tutte le risorse necessarie su DigitalOcean, il provider di servizi che ho scelto di usareNello specifico, creeremo insieme il cluster managed ed i due database (MySQL e Redis) che ho usato;
  • daremo uno sguardo alla creazione delle immagini docker per l’app, che verranno usate dai pod del cluster;
  • infine, inizieremo a mettere le mani concretamente su Kubernetes, creando i deployment e service per la nostra app;

Iniziamo!

Deploy di un’applicazione Laravel su Kubernetes – Parte 1

3

Oggi voglio iniziare una mini-serie di articoli dedicati al deploy di un’applicazione Laravel su un cluster Kubernetes. 

Era un po’ che volevo farlo: imparare quello che ho imparato per me è stato molto stimolante e mi ha portato un sacco di benefici. Anche economici.

Prima di iniziare però voglio subito mettere un paio di cose in chiaro:

  • non sarà un tutorial “passo dopo passo”: ogni applicazione ha le sue necessità, le sue peculiarità e può necessitare di un setup totalmente diverso da quello che ho messo su io. Per questo motivo, racconterò la mia esperienza, cosa ho fatto e come ho risolto alcuni dei miei problemi, con l’obiettivo di fornire una traccia da seguire per chi si sta avvicinando ora all’argomento;
  • non sono un esperto di Kubernetes: le soluzioni che ho trovato funzionano perfettamente per me, anche se non è detto siano il meglio possibile. Trovo l’argomento molto affascinante ma NON sono ad un livello di conoscenze avanzato sotto questo punto di vista. Non aspettatevi un corso accelerato di Kubernetes su queste pagine!

Quello che leggerete sarà, insomma, un po’ un “diario” della mia esperienza.

Creare un Admin per Laravel con Orchid CRUD. Ecco com’è andata

1

Torno di nuovo a scrivere di Orchid, il progetto di Alexandr Chernyaev dedicato alla costruzione di pannelli di amministrazione con Laravel. Sto continuando ad usarlo e, devo ammetterlo, mi ci sto appassionando.

Il progetto è ben fatto, funziona bene ed ha una logica che mi piace molto.

Ho provato Orchid per Laravel. Posso farci un Pannello di Amministrazione?

1

In questi giorni ho passato un po’ di tempo a guardarmi intorno, alla ricerca di alternative a Laravel Nova per quanto riguarda la costruzione di pannelli di amministrazione con Laravel. Fino ad oggi, infatti, ho usato solo Nova e devo dire di essermi trovato davvero bene.

Sono però anche una persona molto curiosa: perché limitarmi? Così, tra una sbirciata a Reddit (quanta roba interessante che ci trovo!) e ricerche su Google, alla fine sono incappato in un progetto abbastanza particolare: Orchid.

Una “Bestia Strana”

Devo aggiornare la mia app Laravel, oppure no?

0

Ieri, girovagando come al solito tra le discussioni in cerca di idee, ho trovato un post interessante che parlava di come e quando aggiornare un’app Laravel. Mi ha sorpreso molto trovare pareri di ogni tipo:

  • “no, ma figurati, non aggiornare se non è strettamente necessario”
  • “aggiorna sempre!”
  • “io aggiorno solo ad ogni LTS”

… e così via.

Mi sono ricordato che ultimamente ho avuto un’esperienza ravvicinata del terzo tipo con un aggiornamento abbastanza “importante” di un’app Laravel.

Ho pensato di scrivere questo articolo per “riassumere” un po’ questa esperienza, nella speranza che possa essere utile anche ad altri.

Come usare (e non usare) i Seeder in Laravel

1

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.