Preguntas frecuentes sobre SmooshGate

¿Qué sucedió el smoosh?

Una propuesta para una función del lenguaje JavaScript llamada Array.prototype.flatten resulta incompatible con la Web. El envío de la función en Firefox Nightly causó la falla de al menos un sitio web popular. Dado que el código problemático forma parte de la amplia biblioteca MooTools, es probable que se vean afectados muchos más sitios web. Si bien MooTools no se usa comúnmente para sitios web nuevos en 2018, solía ser muy popular y sigue estando presente en muchos sitios web de producción.

El autor de la propuesta sugirió en broma cambiar el nombre de flatten a smoosh para evitar el problema de compatibilidad. La broma no estaba clara para todos, algunas personas comenzaron a creer erróneamente que el nombre nuevo ya se había decidido y las cosas se elevaron rápidamente.

¿Qué hace Array.prototype.flatten?

Array.prototype.flat, que en un principio se propuso como Array.prototype.flatten, compacta los arrays de manera recursiva en el depth especificado, cuyo valor predeterminado es 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 misma propuesta incluye Array.prototype.flatMap, que es como Array.prototype.map, excepto que compacta el resultado en un array nuevo.

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

¿Qué hace MooTools para provocar este problema?

MooTools define su propia versión no estándar de Array.prototype.flatten:

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

La implementación de flatten de MooTools difiere del estándar propuesto. Sin embargo, este no es el problema. Cuando los navegadores envían Array.prototype.flatten de forma nativa, MooTools anula la implementación nativa. De esta manera, se garantiza que el código que se basa en el comportamiento de MooTools funcione según lo previsto, independientemente de si el flatten nativo está disponible o no. Todo bien por ahora.

Desafortunadamente, sucede algo más. MooTools copia todos sus métodos de array personalizados en Elements.prototype (donde Elements es una API específica de MooTools):

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

for-in itera en las propiedades "enumerables", que no incluyen métodos nativos como Array.prototype.sort, pero sí propiedades asignadas con regularidad, como Array.prototype.foo = whatever. Sin embargo, y este es el punto de partida, si reemplazas una propiedad no enumerable, p.ej., Array.prototype.sort = whatever, esta sigue siendo no enumerable.

Actualmente, Array.prototype.flatten = mooToolsFlattenImplementation crea una propiedad flatten enumerable, por lo que luego se copia en Elements. Sin embargo, si los navegadores envían una versión nativa de flatten, esta se vuelve no enumerable y no se copia en Elements. Cualquier código que dependa de Elements.prototype.flatten de MooTools ahora está dañado.

Si bien parece que cambiar el Array.prototype.flatten nativo para que sea enumerable solucionaría el problema, es probable que causara aún más problemas de compatibilidad. Cada sitio web que depende de for-in para iterar sobre un array (lo cual no es una práctica recomendada, pero sucede) obtendría de repente una iteración de bucle adicional para la propiedad flatten.

El mayor problema subyacente aquí es la modificación de objetos integrados. En la actualidad, la extensión de los prototipos nativos se acepta como una práctica no recomendada, ya que no se compone bien con otras bibliotecas y código de terceros. ¡No modifiques objetos que no te pertenecen!

¿Por qué no conservar el nombre existente y romper la Web?

En 1996, antes de que se expandiera el CSS y mucho antes de que “HTML5” se convirtiera en un producto, se lanzó el sitio web de Space Jam. Hoy en día, el sitio web sigue funcionando de la misma manera que hace 22 años.

¿Cómo sucedió eso? ¿Alguien mantuvo ese sitio web durante todos estos años y lo actualizó cada vez que los proveedores de navegadores enviaban una función nueva?

Al parecer, "no rompas la Web" es el principio de diseño número uno para HTML, CSS, JavaScript y cualquier otro estándar que se use ampliamente en la Web. Si el envío de una función nueva del navegador hace que los sitios web existentes dejen de funcionar, eso perjudica a todos:

  • los visitantes de los sitios web afectados de repente tienen una experiencia del usuario dañada;
  • los propietarios del sitio web pasaron de tener un sitio web que funcionaba perfectamente a uno no funcional sin que cambiaran nada;
  • los proveedores de navegadores que envían la nueva función pierden participación de mercado debido a que los usuarios cambian de navegador después de notar que “funciona en el navegador X”.
  • Una vez que se conoce el problema de compatibilidad, otros proveedores de navegadores se niegan a enviarlo. La especificación de la función no coincide con la realidad ("solo una obra de ficción"), lo que es malo para el proceso de estandarización.

Por supuesto, en retrospectiva, MooTools hizo algo mal, pero romper la Web no los castiga, sino a los usuarios. Estos usuarios no saben qué es una herramienta muu. Como alternativa, podemos encontrar otra solución y los usuarios pueden seguir usando la Web. La elección es fácil de elegir.

¿Esto significa que las APIs dañadas nunca se pueden quitar de la plataforma web?

Depende. En casos excepcionales, es posible que se quiten las funciones dañinas de la Web. Incluso averiguar si es posible quitar un atributo es un esfuerzo muy complicado, ya que requiere una telemetría extensa para cuantificar cuántas páginas web cambiarían su comportamiento. Sin embargo, cuando la función es lo suficientemente insegura, es perjudicial para los usuarios o se usa con muy poca frecuencia, esto se puede hacer.

<applet>, <keygen> y showModalDialog() son ejemplos de APIs incorrectas que se quitaron correctamente de la plataforma web.

¿Por qué no simplemente reparamos MooTools?

Aplicar parches a MooTools para que ya no extienda los objetos integrados es una buena idea. Sin embargo, no resuelve el problema en cuestión. Incluso si MooTools lanzara una versión con parche, todos los sitios web existentes que la usaran tendrían que actualizarse para que el problema de compatibilidad desaparezca.

¿Las personas no pueden simplemente actualizar su copia de MooTools?

En un mundo ideal, MooTools lanzaría un parche y todos los sitios web que usaban MooTools se actualizarían mágicamente al día siguiente. Problema resuelto, ¿no?

Lamentablemente, esto no es realista. Incluso si alguien identificara de alguna manera el conjunto completo de sitios web afectados, lograra encontrar la información de contacto de cada uno de ellos, comunicarse con éxito con todos los propietarios del sitio web y convencerlos a todos para realizar la actualización (lo que podría significar refactorizar toda su base de código), el proceso completo tardaría años, en el mejor de los casos.

Ten en cuenta que muchos de estos sitios web son antiguos y es probable que no tengan mantenimiento. Incluso si el encargado de mantenimiento aún está presente, es posible que no sea un desarrollador web altamente capacitado como tú. No podemos esperar que todos cambien su sitio web de 8 años debido a un problema de compatibilidad web.

¿Cómo funciona el proceso de TC39?

TC39 es el comité a cargo de desarrollar el lenguaje JavaScript con el estándar ECMAScript.

#SmooshGate hizo creer a algunos que "TC39 quiere cambiar el nombre de flatten a smoosh", pero fue una broma interna que no se comunicó bien a nivel externo. Las decisiones importantes, como cambiar el nombre de una propuesta, no se toman a la ligera, no las toma una sola persona y, definitivamente, no se toman de la noche a la mañana en función de un solo comentario de GitHub.

TC39 opera en un proceso de etapa de pruebas claro para las propuestas de funciones. Las propuestas de ECMAScript y cualquier cambio importante que se realicen (incluido el cambio de nombre del método) se analizan durante las reuniones de TC39 y deben ser aprobadas por todo el comité antes de que se conviertan en oficiales. En el caso de Array.prototype.flatten, la propuesta ya pasó por varias etapas de aceptación, hasta la etapa 3, lo que indica que la función está lista para implementarse en navegadores web. Es común que surjan otros problemas de especificaciones durante la implementación. En este caso, el feedback más importante surgió después de intentar enviarlo: la función, en su estado actual, rompe la Web. Estos problemas difíciles de predecir son parte del motivo por el que el proceso de TC39 no termina una vez que los navegadores envían una función.

TC39 funciona según un consenso, lo que significa que el comité debe acordar cualquier cambio nuevo. Incluso si smoosh hubiera sido una sugerencia seria, es probable que un miembro del comité se oponga a ella en favor de un nombre más común, como compact o chain.

El cambio de nombre de flatten a smoosh (incluso si no fue una broma) nunca se analizó en una reunión de TC39. Por lo tanto, se desconoce la postura oficial de TC39 sobre este tema. Ninguna persona puede hablar en nombre de todo el TC39 hasta que se llegue a un consenso en la próxima reunión.

Por lo general, asisten a las reuniones de TC39 personas con antecedentes muy diversos: algunas tienen años de experiencia en el diseño de lenguajes de programación, otras trabajan en un navegador o un motor de JavaScript, y una cantidad cada vez mayor de asistentes están allí para representar a la comunidad de desarrolladores de JavaScript.

¿Cómo se resolvió SmooshGate finalmente?

Durante la reunión de TC39 de mayo de 2018, #SmooshGate se resolvió oficialmente cuando se cambió el nombre de flatten a flat.

Array.prototype.flat y Array.prototype.flatMap se enviaron en V8 v6.9 y Chrome 69.