Domande frequenti su SmooshGate

Che baciata è successo?!

Una proposta per una funzionalità in linguaggio JavaScript chiamata Array.prototype.flatten si rivela incompatibile con il web. L'invio della funzionalità in Firefox Nightly ha causato l'interruzione di almeno un sito web molto popolare. Poiché il codice problematico fa parte della libreria diffusa di MooTools, è probabile che il problema interessi molti più siti web. (Sebbene MooTools non venga usato abitualmente per i nuovi siti web nel 2018, era molto popolare ed è ancora presente su molti siti web di produzione.)

L'autore della proposta ha scherzosamente suggerito di rinominare flatten in smoosh per evitare il problema di compatibilità. La barzelletta non era chiara per tutti, alcune persone iniziavano a credere erroneamente che il nuovo nome fosse già stato deciso e le cose peggioravano rapidamente.

Che cosa fa Array.prototype.flatten?

Array.prototype.flat, originariamente proposto come Array.prototype.flatten, unisce gli array in modo ricorsivo al valore depth specificato, che per impostazione predefinita è 1.

// Flatten one level:
const array = [1, [2, [3]]];
array.flat();
// → [1, 2, [3]]

// Flatten recursively until the array contains no more nested arrays:
array.flat(Infinity);
// → [1, 2, 3]

La stessa proposta include Array.prototype.flatMap, che ha un aspetto simile a Array.prototype.map, con la differenza che appiattisce il risultato in un nuovo array.

[2, 3, 4].flatMap((x) => [x, x * 2]);
// → [2, 4, 3, 6, 4, 8]

Che cosa sta facendo MooTools che causa questo problema?

MooTools definisce la propria versione non standard di Array.prototype.flatten:

Array.prototype.flatten = /* non-standard implementation */;

L'implementazione flatten di MooTools è diversa dallo standard proposto. Tuttavia, non è questo il problema. Quando i browser forniscono Array.prototype.flatten in modo nativo, MooTools sostituisce l'implementazione nativa. Ciò garantisce che il codice basato sul comportamento di MooTools funzioni come previsto indipendentemente dalla disponibilità di flatten nativo. Finora stai andando bene.

Purtroppo, succede qualcos'altro. MooTools copia tutti i suoi metodi di array personalizzati in Elements.prototype (dove Elements è un'API specifica di MooTools):

for (var key in Array.prototype) {
  Elements.prototype[key] = Array.prototype[key];
}

for-in esegue l'iterazione delle proprietà "enumerabili", che non includono metodi nativi come Array.prototype.sort ma include proprietà assegnate regolarmente come Array.prototype.foo = whatever. Ma, ed ecco l'occhiello, se sovrascrivi una proprietà non enumerabile, ad esempio Array.prototype.sort = whatever, questa rimane non enumerabile.

Attualmente Array.prototype.flatten = mooToolsFlattenImplementation crea una proprietà flatten enumerabile, quindi viene copiata in Elements. Tuttavia, se i browser forniscono una versione nativa di flatten, questa diventa non enumerabile e non viene copiata in Elements. Qualsiasi codice che si basa sul codice Elements.prototype.flatten di MooTools non funziona.

Anche se sembra che la modifica del valore nativo Array.prototype.flatten in modo che sia enumerabile potrebbe risolvere il problema, probabilmente causerebbe ancora più problemi di compatibilità. Ogni sito web che fa affidamento su for-in per l'iterazione su un array (che è una cattiva pratica, ma accade) otterrà improvvisamente un'ulteriore iterazione di loop per la proprietà flatten.

Il problema principale qui è la modifica degli oggetti integrati. Al giorno d'oggi l'estensione di prototipi nativi è generalmente accettata come una prassi scorretta, poiché non si integra bene con altre librerie e codice di terze parti. Non modificare gli oggetti che non sono di tua proprietà.

Perché non ci limitiamo a mantenere il nome esistente e a rovinare il Web?

Nel 1996, prima che CSS si diffusero e molto prima che "HTML5" diventasse una cosa, il sito web di Space Jam è stato pubblicato. Il sito web funziona ancora come 22 anni fa.

Come è successo? Qualcuno ha gestito quel sito web per tutti questi anni, aggiornandolo ogni volta che i fornitori di browser hanno introdotto una nuova funzionalità?

Come si è scoperto, "non rompere il web" è il principio di progettazione numero uno per HTML, CSS, JavaScript e qualsiasi altro standard ampiamente usato sul web. Se la pubblicazione di una nuova funzionalità del browser causa l'interruzione del funzionamento dei siti web esistenti, questo rappresenta un danno per tutti:

  • i visitatori dei siti web interessati subiscono improvvisamente un'esperienza utente non funzionante;
  • I proprietari di siti web sono passati da un sito web che funziona perfettamente a uno non funzionale,
  • i fornitori di browser che pubblicano la nuova funzionalità perdono quota di mercato, a causa del passaggio da un browser all'altro dopo aver notato che "funziona nel browser X".
  • una volta che il problema di compatibilità è noto, altri fornitori di browser si rifiutano di distribuirlo. La specifica della funzionalità non corrisponde alla realtà ("nient'altro che un'opera di finzione"), il che è negativo per il processo di standardizzazione.

Certo, a posteriori MooTools ha fatto la cosa sbagliata, ma spezzare il web non li punisce, ma punisce gli utenti. Questi utenti non sanno che cos'è uno strumento moo. In alternativa, possiamo trovare un'altra soluzione e gli utenti possono continuare a utilizzare il web. La scelta è facile.

Questo significa che le API dannose non possono mai essere rimosse dalla piattaforma web?

Dipende. In rari casi, le funzionalità non conformi possono essere rimosse dal web. Anche solo capire se è possibile rimuovere una funzionalità è un'attività molto complicata, che richiede un'ampia telemetria per quantificare il numero di pagine web che potrebbero cambiare il loro comportamento. Tuttavia, è possibile farlo quando la funzionalità è sufficientemente non sicura, dannosa per gli utenti o viene usata molto raramente.

<applet>, <keygen> e showModalDialog() sono tutti esempi di API non valide che sono state rimosse correttamente dalla piattaforma web.

Perché non semplicemente correggiamo MooTools?

È una buona idea applicare patch a MooTools in modo che non estenda più gli oggetti integrati. Tuttavia, non risolve il problema in questione. Anche se MooTools rilasciasse una versione con patch, tutti i siti web esistenti che la utilizzano dovrebbero essere aggiornati affinché il problema di compatibilità si risolva.

Le persone non possono semplicemente aggiornare la propria copia di MooTools?

In un mondo perfetto, MooTools rilasciava una patch e ogni singolo sito web che utilizzava MooTools verrebbe aggiornato magicamente il giorno successivo. Problema risolto, vero?!

Purtroppo questo non è realistico. Anche se qualcuno riuscisse in qualche modo a identificare l'intero insieme di siti web interessati, a trovare i dati di contatto per ognuno di loro, a contattare con successo tutti i proprietari dei siti web e a convincerli tutti a eseguire l'aggiornamento (il che potrebbe significare il refactoring dell'intero codebase), l'intero processo avrebbe richiesto anni.

Tieni presente che molti di questi siti web sono datati e probabilmente non sono stati mantenuti. Anche se il gestore non è ancora disponibile, è possibile che non sia uno sviluppatore web altamente qualificato come te. Non possiamo aspettarci che tutti passino a cambiare il sito web di 8 anni per problemi di compatibilità web.

Come funziona la procedura TC39?

Il TC39 è il comitato incaricato di sviluppare il linguaggio JavaScript tramite lo standard ECMAScript.

#SmooshGate ha fatto credere ad alcuni che "TC39 vuole rinominare flatten in smoosh", ma si trattava di una battuta che non è stata comunicata bene all'esterno. Le decisioni importanti, come la ridenominazione di una proposta, non vengono prese alla leggera, non vengono prese da una sola persona e non vengono affatto prese da un giorno all'altro sulla base di un singolo commento di GitHub.

Il TC39 adotta un chiaro processo di gestione temporanea per le proposte di funzionalità. Le proposte ECMAScript e le eventuali modifiche importanti apportate (compresa la ridenominazione del metodo) vengono discusse durante le riunioni del TC39 e devono essere approvate dall'intero comitato prima di diventare ufficiali. Nel caso di Array.prototype.flatten, la proposta ha già superato diverse fasi di accordo, fino alla fase 3, a indicare che la funzionalità è pronta per essere implementata nei browser web. È comune che si verifichino ulteriori problemi relativi alle specifiche durante l'implementazione. In questo caso, il feedback più importante è stato dopo aver tentato di distribuirlo: la funzionalità, nel suo stato attuale, interrompe il web. Problemi difficili da prevedere come questi sono parte del motivo per cui il processo TC39 non termina solo una volta che i browser distribuiscono una funzionalità.

Il TC39 opera sul consenso, il che significa che il comitato deve accordarsi su eventuali nuove modifiche. Anche se smoosh fosse stato un suggerimento serio, sembra probabile che un membro del comitato si opponga a favore di un nome più comune come compact o chain.

La ridenominazione da flatten a smoosh (anche se non era uno scherzo) non è mai stata discussa in una riunione del TC39. Di conseguenza, la posizione ufficiale del TC39 su questo argomento non è nota. Nessun singolo individuo può parlare per conto di tutti i TC39 finché non viene raggiunto il consenso alla prossima riunione.

Alle riunioni del TC39 partecipano in genere persone con background molto diversificati: alcune hanno anni di esperienza nella progettazione dei linguaggi di programmazione, altre lavorano su un browser o un motore JavaScript e un numero crescente di operatori è presente per rappresentare la community di sviluppatori JavaScript.

Come si è risolto SmooshGate alla fine?

Durante la riunione del TC39 di maggio 2018, #SmooshGate è stato ufficialmente risolto rinominando flatten in flat.

Array.prototype.flat e Array.prototype.flatMap spediti in V8 v6.9 e Chrome 69.