No. 103

Titolo originale: The Design of Code: Organizing JavaScript

Pubblicato in: JavaScript

Scritto da Anthony Colangelo

C'è molto design nel codice e non intendo il codice che crea l'interfaccia utente, ma proprio il design del codice.

Il codice ben progettato è molto più semplice da mantenere, ottimizzare ed estendere, rendendo così gli sviluppatori più efficienti. Questo significa poter utilizzare più energie e maggior concentrazione per realizzare grandi progetti che rendano tutti felici: utenti, sviluppatori e stakeholder.

Ci sono tre aspetti del design del codice (o code design), di alto livello e linguaggio-agnostici, che sono particolarmente importanti.

  1. Architettura di sistema: il layout di base della codebase. Le regole che governano il modo in cui i vari componenti, come i model, le view e i controller interagiscono tra loro.
  2. Manutenibilità: il codice può essere migliorato ed esteso facilmente?
  3. Riusabilità: quanto sono riutilizzabili i componenti dell'applicazione? Quanto facilmente può essere personalizzata ciascuna implementazione di un componente?

Nei linguaggi meno stretti, e nello specifico in JavaScript, ci vuole un po' di disciplina per scrivere del codice ben progettato. L'ambiente JavaScript è così permissivo che è facile buttare pezzi ovunque e avere ancora tutto che funziona. Stabilire in anticipo l'architettura di sistema (e attenervisi!) fornisce dei vincoli alla vostra codebase, assicurandone la consistenza generale.

Un approccio che adoro consiste in un collaudato pattern del software design, il module pattern, la cui struttura estensibile lo porta ad essere una solida architettura di sistema ed una codebase manutenibile. Mi piace creare moduli all'interno di un plugin jQuery, che porta con sé un riusabilità fantastica, fornisce delle opzioni robuste ed espone una API ben fatta.

Di seguito, vi guiderò attraverso la realizzazione del vostro codice in componenti ben organizzate che possono essere riutilizzate in progetti futuri.

Il module pattern

Ci sono molti design pattern là fuori e in ugual modo molte risorse che li riguardano. Addy Osmani ha scritto un libro incredibile (e gratuito!) sui design pattern in JavaScript, che raccomando caldamente agli sviluppatori di tutti i livelli.

Il module pattern è un fondamento strutturale semplice che può aiutarvi a mantenere il vostro codice pulito e organizzato. Un "modulo" è solo un literal object standard che contiene metodi e proprietà e questa semplicità è l'aspetto migliore di questo pattern: anche chi non ha familiarità con i pattern del tradizionale software design saranno in grado di guardare il codice e capire all'istante come funziona.

Nelle applicazioni che usano questo pattern, ogni componente ha il suo modulo distinto. Per esempio, per creare una funzionalità di autocompletamento, dovrete creare un modulo per il campo di testo e un modulo per l'elenco dei risultati. Questi due moduli lavoreranno insieme, ma il codice del campo di testo non toccherà i risultati del codice dell'elenco e viceversa.

Questa sdoppiamento dei componenti è il motivo per cui il module pattern è ottimo per costruire una solida architettura di sistema. Le relazioni all'interno dell'applicazione sono ben definite: qualunque cosa sia in correlazione con il campo di testo viene gestita dal modulo del campo di testo e non viene disseminata per tutta la codebase, con il risultato di ottenere un codice pulito e chiaro.

Un altro beneficio dell'organizzazione basata sui moduli sta nel suo essere intrinsecamente manutenibile. I moduli possono essere migliorati e ottimizzati indipendentemente senza influenzare altre parti dell'applicazione.

Ho usato il module pattern per la struttura base di jPanelMenu, il plugin jQuery che ho creato per il menu system fuori dal canvas. Lo userò come esempio, per illustrare il processo di creazione di un modulo.

Creare un modulo

Per cominciare, definisco tre metodi e una proprietà che vengono usate per gestire le interazioni del menu system.

var jpm = {
    animated: true,
    openMenu: function( ) {
        …
        this.setMenuStyle( );
    },
    closeMenu: function( ) {
        …
        this.setMenuStyle( );
    },
    setMenuStyle: function( ) { … }
};

L'idea è di suddividere il codice in quanti più pezzi possibili, che siano il più piccoli possibile e con la maggior riusabilità. Avrei potuto scrivere solo un metodo toggleMenu( ), ma creare i metodi openMenu( ) e closeMenu( ) distinti fornisce maggior controllo e riutilizzabilità all'interno del modulo.

Notate che le chiamate al metodi e alle proprietà del modulo dall'interno del modulo stesso (come le chiamate a setMenuStyle( )) hanno come prefisso la parola chiave this: questo è il modo in cui i moduli accedono ai propri membri.

Questa è la struttura base di un modulo. Potete continuare ad aggiungere metodi e proprietà di cui avete bisogno, ma non diventa più complesso di così. Dopo che le fondamenta strutturali sono state create, il livello di riutilizzabilità - opzioni e una API esposta - può essere creato sopra a queste.

Plugin jQuery

Il terzo aspetto del codice ben progettato è probabilmente il più cruciale: la riutilizzabilità. Occorre un avvertimento per questa sezione: sebbene ci siano ovviamente dei modi per costruire ed implementare componenti riutilizzabili in puro JavaScript (siamo circa al 90% del percorso con il modulo di cui sopra), preferisco creare dei plugin jQuery per cose più complesse, per alcune ragioni.

La più importante è che è un forma di comunicazione non intrusiva. Se usate jQuery per creare un componente, dovreste fare in modo che sia ovvio per quelli che lo implementano. Creare un componente come un plugin jQuery è un gran modo per dire che jQuery è richiesto.

Inoltre, il codice di implementazione sarà consistente con il resto del codice del progetto basato su jQuery. Tutto ciò è positivo per ragioni esteteiche, ma significa anche (entro una certa misura) che gli sviluppatori possono predire il modo in cui interagire con il plugin senza troppa ricerca. Solo un altro modo per creare una migliore developer interface.

Prima di iniziare a creare un plugin jQuery, assicuratevi che il plugin non sia in conflitto con altre librerie JavaScript che usano la notazione $. È molto più semplice di quanto possiate immaginare: dovete semplicemente circondare il codice del vostro plugin in questo modo:

(function($) {
    // jQuery plugin code here
})(jQuery);

Poi, impostiamo il nostro plugin e vi inseriamo il codice del modulo creato in precedenza. Un plugin è solo un metodo definito sull'oggetto jQuery ($).

(function($) {
    $.jPanelMenu = function( ) {
        var jpm = {
            animated: true,
            openMenu: function( ) {
                …
                this.setMenuStyle( );
            },
            closeMenu: function( ) {
                …
                this.setMenuStyle( );
            },
            setMenuStyle: function( ) { … }
        };
    };
})(jQuery);

Tutto quello che occorre per usare il plugin è una chiamata alla funzione che abbiamo appena creato.

var jpm = $.jPanelMenu( );

Opzioni

Le opzioni sono essenziali per qualunque plugin realmente riutilizzabile, perché permetto la personalizzazione di ciascuna implementazione. Ogni progetto porta con sé un sacco di stili di design, tipi di interazione e strutture di contenuto. Le opzioni personalizzabili aiutano ad assicurarsi che adattiate il plugin perché stia all'interno di quei vincoli di progetto.

È un best practice fornire dei buoni valori di default per le vostre opzioni. Il modo più semplice per farlo è usare il metodo di jQuery $.extend( ), che accetta (almeno) due argomenti.

Come primo argomento di $.extend( ), definite un oggetto con tutte le opzioni disponibili e i loro valori di default. Come secondo argomento, passate le opzioni "passed-in". Questo farà il merge di due oggetti, sovrascrivento i default con qualsiasi opzione "passed-in".

(function($) {
    $.jPanelMenu = function(options) {
        var jpm = {
            options: $.extend({
                'animated': true,
                'duration': 500,
                'direction': 'left'
            }, options),
            openMenu: function( ) {
                …
                this.setMenuStyle( );
            },
            closeMenu: function( ) {
                …
                this.setMenuStyle( );
            },
            setMenuStyle: function( ) { … }
        };
    };
})(jQuery);

Oltre a fornire dei buoni default, le opzioni diventano quasi una auto-documentazione: chi guarda il codice può vedere subito tutte le opzioni disponibili.

Mostrate quante più opzioni possibile. La personalizzazione aiuterà nelle implementazioni future e la flessibilità non fa mai male.

API

Le opzioni sono un modo fantastico per personalizzare il modo in cui funziona un plugin. Un'API, d'altro canto, abilita le estensioni della funzionalità del plugin esponendo metodi e proprietà da cui può trarre vantaggio il codice di implementazione.

Se da un lato va benissimo esporre il più possibile attraverso una API, il mondo esterno non dovrebbe avere accesso a tutti i metodi e a tutte le proprietà interne. Idealmente, dovreste esporre solo gli elementi che saranno usati.

Nel nostro esempio, la API esposta dovrebbe includere delle chiamate per aprire e chiudere il menu, ma nulla di più. Il metodo interno setMenuStyle( ) gira quando il menu si apre e si chiude, ma il pubblico non ha bisogno di accedervi.

Per esporre una API, fate restituire un oggetto con qualunque metodo e proprietà desideriate alla fine del codice del plugin. Potete anche mappare i metodi e le proprietà che restituite a quelli all'interno del codice del modulo: qui è dove la magnifica organizzazione del module pattern si mostra in tutto il suo splendore.

(function($) {
    $.jPanelMenu = function(options) {
        var jpm = {
            options: $.extend({
                'animated': true,
                'duration': 500,
                'direction': 'left'
            }, options),
            openMenu: function( ) {
                …
                this.setMenuStyle( );
            },
            closeMenu: function( ) {
                …
                this.setMenuStyle( );
            },
            setMenuStyle: function( ) { … }
        };

        return {
            open: jpm.openMenu,
            close: jpm.closeMenu,
            someComplexMethod: function( ) { … }
        };
    };
})(jQuery);

I metodi e le proprietà della API saranno disponibili tramite l'oggetto restituito dall'inizializzazione del plugin.

var jpm = $.jPanelMenu({
    duration: 1000,
    …
});
jpm.open( );

Lucidare le interfacce per developer

Solo con alcuni semplici costrutti e alcune linee guida, ci siamo creati un plugin riutilizzabile ed estensibile che contribuirà a renderci la vita un po' più semplice. Come con qualunque altra cosa facciamo, sperimentiamo con questa struttura per vedere se può andar bene per noi, per il nostro team e per il nostro workflow.

Ogni volta che mi trovo a creare qualcosa che ha del potenziale per essere riutilizzato, lo scompongo in un plugin jQuery basato su moduli. L'aspetto migliore di questo approccio è che ci costringe ad usare - e testare - il codice che scriviamo. Usando qualcosa man mano che lo realizzate, identificherete rapidamente i punti di forza, scoprirete i difetti e pianificherete i cambiamenti.

Questo processo porta a un codice testato per i campi di battaglia, pronto per contributi open source o per essere venduto e distribuito. Ho realizzato i miei plugin (più) ordinati come progetti open source su GitHub.

Anche se non state creando qualcosa che verrà rilasciato al pubblico, è tuttavia ancora importante pensare al design del vostro codice. Il vostro io futuro vi ringrazierà!

Illustrazioni: Carlo Brigatti

Share/Save/Bookmark
 

Discutiamone

Ti sembra interessante? Scrivi tu il primo commento


Cenni sull'autore

Anthony Colangelo

Anthony Colangelo è developer in Happy Cog a Philadelphia. È uno di quegli ibridi front-end e back-end developer che ama tutto, dal responsive design alla programmazione object-oriented. Potete trovarlo su Twitter, dove parla di sviluppo (e probabilmente anche di spazio).