Penpot: l’alternativa open source per design UI/UX e collaborazione tra designer e sviluppatori
Penpot è un software di design open source e gratuito, pensato per rivoluzionare il modo in cui team multidisciplinari progettano interfacce utente e prototipi interattivi, unendo design e codice in un unico ambiente collaborativo.
Nato dall’esperienza di Kaleidos Open Source, Penpot si presenta come una piattaforma web-based, multipiattaforma e altamente adattabile, che sta rapidamente…
I MIGLIORI STRUMENTI DI PROTOTIPAZIONE IA E UX PER IL 2019
I MIGLIORI STRUMENTI DI PROTOTIPAZIONE IA E UX PER IL 2019
LA PROTOTIPAZIONE, SENZA ALCUN DUBBIO, SVOLGE UN RUOLO INDISPENSABILE NELLA PROGETTAZIONE DELL’INTERFACCIA UTENTE / UX.
Testare un’applicazione, un sito web o un ecommerce, dalla progettazione alla messa online sta diventando sempre piu’ importante, direi… essenziale. Il motivo è puro e semplice, enorme risparmio di tempo unito alla miglior user experience possibile. Di solito, i prototipi…
The FormBox is a desktop vacuum former that lets you start a production line from your tabletop. Based on vacuum former technology, powered by your vacuum cleaner.
Formbox. Macchina per creare stampi e forme in pochi secondi.
The FormBox is a desktop vacuum former that lets you start a production line from your tabletop. Based on vacuum former technology, powered by your vacuum cleaner.
Stampare in 3D o non stampare in 3D: il Barometro di Materialise risolve i vostri dubbi amletici
Stampare in 3D o non stampare in 3D: il Barometro di Materialise risolve i vostri dubbi amletici
Tutti, in tutti i settori industriali, hanno ormai sentito parlare delle magie che la stampa 3D può fare per il business tagliando i tempi di prototipazione e, in alcuni casi, permettendo la realizzazione rapida di serie brevi o di strumenti per l’utilizzo finale. Le possibilità sono davvero infinite ma – come diciamo spesso – solo perché si può usare la stampa 3D per fare qualsiasi cosa, non…
Quando quattro laureati del MIT, la più famosa scuola di tecnologia al mondo hanno deciso unire le forse e inventare qualcosa di assolutamente rivoluzionario. Il risultato? Mimo, il più avanzato baby monitor sulla faccia della Terra e uno dei primi esempi veramente funzionali di wearable technology. Mimo è una tutina in cotone organico con un sensore lavabile.
Validazione degli Object Path - Una soluzione per validare gli oggetti profondi
[Read the English version]
Premessa
In primis, che cos'è un object path? È una personale interpretazione dell'indentificatore che definisce un chiaro percorso da un oggetto radice fino ad un nodo membro qualunque.
Il problema
Indice
La soluzione n. 1 - istruzione IF
La soluzione n. 2 - le funzioni
Variante n. 1 - il binding
Variante n. 2 - prototipazione
La soluzione n. 1 - istruzione IF
Come prima soluzione, si può prendere in considerazione un'istruzione basilare, molto spesso usata per questi casi:
if ( object && object.foo && object.foo.bar && object.foo.bar.baz ) { // fa qualcosa }
l'istruzione IF verificherà la validità (cioè, se esiste) di ogni identificatore, e solo se tutti gli identificatori risulteranno validi, essa eseguirà il relativo blocco di codice.
PRO
Il suo intento risulta chiaro a chiunque osservi il codice
È veloce grazie al tipo di valutazione a corto-circuito dell'istruzione IF (al primo identificatore non valido, si ferma).
CONTRO
Più profondo è il percorso, maggiore sarà il numero di identificatori richiesti per eseguire l'istruzione. In casi particolari, ciò può portarci ad avere un'istruzione IF piuttosto lunga e confusa
Se usata con oggetti del DOM, l'esecuzione sarà più lenta a causa delle basse prestazioni del DOM nell'accesso ai suoi oggetti.
La soluzione n. 2 - le funzioni
Come appena visto, la soluzione basata sull'istruzione IF è piuttosto buona quando l'object path non è particolarmente profondo, oppure essa non deve interagire con oggetti del DOM.
Ma, cosa succederebbe se si avesse a che fare con un oggetto molto profondo? Peggio ancora, cosa accadrebbe se si dovesse verificare più di un object path, magari con differenti profondità e (ciliegina sulla torta) dovendo accedere al DOM?
La soluzione analizzata prima non è ottimale come può sembrare. Ma possiamo risolvere questo problema usando un approccio funzionale.
Per prima cosa, quindi, dobbiamo definire la nostra funzione:
var safeObjectPath = function safeObjectPath( object, properties ) { var path = [], root = object, prop; if ( !root ) { // se l'oggetto radice è null/undefined ritorniamo immediatamente return false; } if ( typeof properties === 'string' ) { // se viene passata una stringa (es., 'foo.bar.baz'), // prima la convertiamo in un array di nomi di properietà path = properties ? properties.split('.') : []; } else { if ( Object.prototype.toString.call( properties ) === '[object Array]' ) { // se viene passato un array non dobbiamo fare altro che // assegnarlo al nostro array interno temporaneo path = properties; } else { if ( properties ) { // se il tipo di parametro non è stringa o array // ritorniamo con un falso logico return false; } } } // se il path è valido oppure vuoto ('' o []) ritorniamo con un vero // logico (perché l'oggetto radice è di per sé un path valido), // altrimenti ritorniamo un falso logico. while ( prop = path.shift() ) { // AGGIORN.: all'inizio era stata usata la sola istruzione if..else, // ma in caso di membri oggetto inesistenti poteva generare una // eccezione. Ora, grazie al contributo di @tarikozket // (https://coderwall.com/tarikozket), è stato corretto introducendo // anche un costrutto try..catch. try { if ( prop in root ) { root = root[prop]; } else { return false; } } catch(e) { return false; } } return true; }
Ora si ha la possibilità di verificare gli object path, usando un approccio funzionale, come nel modo seguente:
var module = { foo: { bar: { baz: 'hello' } } }; // verifica che `module` non sia null o undefined safeObjectPath( module ) // -> true // verifica che `foo.bar.baz` sia un percorso valido all'interno di `module` safeObjectPath( module, 'foo.bar.baz' ) // -> true // come sopra, ma utilizzando un array safeObjectPath( module, ['foo', 'bar', 'baz'] ) // -> true // verifica che `foo.baz` sia un percorso valido all'interno di `module` safeObjectPath( module, ['foo', 'baz'] ) // -> false
Come si può osservare, questo approccio permette di verificare differenti tipi di percorso (stringa o array, così si può anche generarli dinamicamente), e con una semplice istruzione (la nostra funzione) è possibile verificare percorsi di qualsiasi profondità. Non importa se 1, 5, 10, o anche 100 nodi di profondità.
PRO
Istruzioni più corte anche con percorsi profondi
Supporto a percorsi definiti in stringhe o array
Supporto a percorsi di qualsiasi profondità
Caching dei percorsi intermedi. La verifica degli oggetti DOM è più veloce rispetto alla soluzione n. 1
CONTRO
Le funzioni sono generalmente più lente di un'istruzione IF
Il suo scopo potrebbe non essere immediatamente chiaro a coloro che leggono il codice sorgente
Variante n. 1 - il binding
Ora che ci si è fatti un quadro generale di come si possa gestire la validazione di un object path, è possibile provare a spingersi oltre questa seconda soluzione, puntando a qualche modifica più avanzata.
Come si è potuto vedere, la funzione ha la possibilità di lavorare con ogni tipo di dato (dal momento che in javascript quasi tutto è un oggetto). Quindi, il primo passo potrebbe essere quello di rimuovere l'argomento object e sfruttare le potenzialità del binding. Per fare ciò, sarà necessario apportare qualche lieve modifica:
var safeObjectPath = function safeObjectPath( properties ) { var path = [], root = this, // prima, si assegnava `object` prop;
È stato rimosso object dagli argomenti, ed ora root viene impostato uguale a this. Ora la funzione farà sempre riferimento al contesto dell'oggetto al quale è stata collegata. Per usare questa versione modificata, si avranno a disposizione diversi modi:
Comunque, come si può vedere, queste nuove modifiche introdotte non forniscono alcuna miglioria pratica, perché si dovrà ancora collegare la funzione tramite i metodi apply(), call(), o bind(), rendendo di fatto il codice più lungo di prima e più complesso. Perciò, ora si vedrà qual è il passo finale per migliorare e rendere davvero utile questa funzione per le nostre necessità.
Variante n. 2 - prototipazione
Sì, posso già sentire lì fuori legioni di sviluppatori lamentarsi perché non è una buona pratica quella di prototipare direttamente negli oggetti nativi. E sì, avete ragione. Ma non si può non tenere da conto l'enorme utilità che questo tipo di metodologia può fornire (tra parentesi, Prototype.js ha fatto la sua fortuna grazie a questo approccio quindi, perché non dargli anche solo un'occhiata? ;).
(function(root, factory, undefined){ var Object = root.Object; try { // Ci assicuriamo di non fare pasticci con 'Object'. // Se il metodo non esiste, viene sollevata un'eccezione // che si incaricherà di aggiungerlo. Object.isSafePath(); } catch (e) { // Questo aggiungerà automaticamente il nuovo metodo a tutti // gli altri oggetti. Object.prototype.isSafePath = factory(); } }( window, function(){ return function ( properties ){ var path = [], root = this, prop; if ( typeof properties === 'string' ) { // se viene passata una stringa (es., 'foo.bar.baz'), // prima la convertiamo in un array di nomi di properietà path = properties ? properties.split('.') : []; } else { if ( Object.prototype.toString.call( properties ) === '[object Array]' ) { // se viene passato un array non dobbiamo fare altro che // assegnarlo al nostro array interno temporaneo path = properties; } else { if ( properties ) { // se il tipo di parametro non è stringa o array // ritorniamo con un falso logico return false; } } } // se il path è valido oppure vuoto ('' o []) ritorniamo con un vero // logico (perché l'oggetto radice è di per sé un path valido), // altrimenti ritorniamo un falso logico. while ( prop = path.shift() ) { // AGGIORN.: all'inizio era stata usata la sola istruzione if..else, // ma in caso di membri oggetto inesistenti poteva generare una // eccezione. Ora, grazie al contributo di @tarikozket // (https://coderwall.com/tarikozket), è stato corretto introducendo // anche un costrutto try..catch. try { if ( prop in root ) { root = root[prop]; } else { return false; } } catch(e) { return false; } } return true; }; }));
Ciò che è stato fatto qui è abbastanza semplice (spero :D). Si usa una IIFE per installare il metodo nel prototipo di Object usando un pattern factory. In questo modo, si può essere ampiamente sicuri di non rischiare di sovrascrivere un metodo eventualmente già presente con lo stesso nome.
È stato anche rimosso il controllo interno di convalida del nodo radice in quanto, in questo caso, se non si ha un oggetto valido, non sia ha neppure un riferimento al metodo.
Detto ciò, tutto quello che resta da fare è richiamare il nuovo metodo, ogni volta che si necessita di verificare un object path: