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 Alessandro. Essendo 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 🙂