Perguntas frequentes sobre o SmooshGate

O que o smoosh aconteceu?!

Uma proposta para um recurso de linguagem JavaScript chamado Array.prototype.flatten acaba sendo incompatível com a Web. O envio do recurso no Firefox Nightly causou o travamento de pelo menos um site popular. Como o código problemático faz parte da biblioteca MooTools, é provável que muito mais sites sejam afetados. Embora o MooTools não seja comumente usado para novos sites em 2018, ele era muito popular e ainda está presente em muitos sites de produção.

O autor da proposta sugeriu, em tom de brincadeira, renomear flatten para smoosh para evitar o problema de compatibilidade. A piada não ficou clara para todos. Algumas pessoas começaram a acreditar incorretamente que o novo nome já tinha sido decidido, e as coisas escalaram rapidamente.

O que Array.prototype.flatten faz?

Array.prototype.flat, originalmente proposto como Array.prototype.flatten, aplana matrizes de forma recursiva até o depth especificado, que é o padrão para 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]

A mesma proposta inclui Array.prototype.flatMap, que é semelhante a Array.prototype.map, exceto por achatar o resultado em uma nova matriz.

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

O que o MooTools está fazendo para causar esse problema?

O MooTools define a própria versão não padrão de Array.prototype.flatten:

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

A implementação do flatten do MooTools é diferente do padrão proposto. No entanto, esse não é o problema. Quando os navegadores enviam Array.prototype.flatten de forma nativa, o MooTools substitui a implementação nativa. Isso garante que o código que depende do comportamento do MooTools funcione conforme o esperado, independente da disponibilidade do flatten nativo. Até aqui, tudo bem!

Infelizmente, algo mais acontece. O MooTools copia todos os métodos de matriz personalizados para Elements.prototype (em que Elements é uma API específica do MooTools):

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

for-in itera sobre propriedades "enumeráveis", que não incluem métodos nativos como Array.prototype.sort, mas incluem propriedades atribuídas regularmente, como Array.prototype.foo = whatever. No entanto, e aqui está o problema: se você substituir uma propriedade não enumerável, por exemplo, Array.prototype.sort = whatever, ela continuará não enumerável.

No momento, Array.prototype.flatten = mooToolsFlattenImplementation cria uma propriedade flatten enumerável, que é copiada mais tarde para Elements. No entanto, se os navegadores enviarem uma versão nativa de flatten, ela se tornará não enumerável e não será copiada para Elements. Qualquer código que dependa do Elements.prototype.flatten do MooTools agora está corrompido.

Embora pareça que mudar o Array.prototype.flatten nativo para ser enumerável corrigiria o problema, isso provavelmente causaria ainda mais problemas de compatibilidade. Todos os sites que dependem de for-in para iterar em uma matriz (o que é uma prática inadequada, mas acontece) receberiam de repente uma iteração de loop adicional para a propriedade flatten.

O maior problema aqui é modificar objetos integrados. Estender protótipos nativos geralmente é aceito como uma prática não recomendada atualmente, porque não se compõe bem com outras bibliotecas e códigos de terceiros. Não modifique objetos que não são seus.

Por que não manter o nome atual e quebrar a Web?

Em 1996, antes que o CSS se tornasse difundido e muito antes de o "HTML5" se tornar uma coisa, o site do Space Jam foi lançado. Hoje, o site ainda funciona da mesma forma que há 22 anos.

Como isso aconteceu? Alguém manteve esse site por todos esses anos, atualizado sempre que os fornecedores de navegadores lançavam um novo recurso?

A regra "não quebre a Web" é o princípio de design número um para HTML, CSS, JavaScript e qualquer outro padrão amplamente usado na Web. Se o envio de um novo recurso do navegador fizer com que os sites parem de funcionar, isso será ruim para todos:

  • os visitantes dos sites afetados têm uma experiência do usuário ruim de repente;
  • os proprietários do site passaram de um site que funcionava perfeitamente para um não funcional sem mudar nada;
  • os fornecedores de navegadores que enviam o novo recurso perdem participação de mercado porque os usuários mudam de navegador depois de perceberem que "ele funciona no navegador X";
  • Quando o problema de compatibilidade é conhecido, outros fornecedores de navegadores se recusam a enviar o produto. A especificação do recurso não corresponde à realidade (“nada além de um trabalho de ficção”), o que é ruim para o processo de padronização.

Claro, em retrospecto, o MooTools fez a coisa errada, mas quebrar a Web não os pune, pune os usuários. Esses usuários não sabem o que é uma ferramenta moo. Como alternativa, podemos encontrar outra solução, e os usuários podem continuar usando a Web. A escolha é fácil.

Isso significa que APIs ruins nunca podem ser removidas da plataforma Web?

Depende. Em casos raros, recursos incorretos podem ser removidos da Web. Mesmo apenas descobrir se é possível remover um recurso é um esforço muito complicado, exigindo telemetria extensiva para quantificar quantas páginas da Web teriam o comportamento alterado. No entanto, isso pode ser feito quando o recurso não é seguro o suficiente, é prejudicial aos usuários ou é usado muito raramente.

<applet>, <keygen> e showModalDialog() são exemplos de APIs inválidas que foram removidas da Plataforma Web.

Por que não corrigimos o MooTools?

Aplicar um patch no MooTools para que ele não estenda mais objetos integrados é uma boa ideia. No entanto, isso não resolve o problema em questão. Mesmo que o MooTools lancasse uma versão corrigida, todos os sites que o usam teriam que ser atualizados para que o problema de compatibilidade fosse resolvido.

As pessoas não podem simplesmente atualizar a cópia do MooTools?

Em um mundo perfeito, o MooTools lançaria um patch, e todos os sites que usam o MooTools seriam magicamente atualizados no dia seguinte. Problema resolvido, certo?!

Infelizmente, isso não é realista. Mesmo que alguém identificasse o conjunto completo de sites afetados, conseguisse encontrar as informações de contato de cada um deles, conseguisse entrar em contato com todos os proprietários dos sites e os convencesse a fazer a atualização (o que pode significar refatorar toda a base de código), o processo todo levaria anos, na melhor das hipóteses.

Muitos desses sites são antigos e provavelmente não são mantidos. Mesmo que o mantenedor ainda esteja por perto, é possível que ele não seja um desenvolvedor da Web altamente qualificado como você. Não podemos esperar que todos mudem o site de 8 anos por causa de um problema de compatibilidade da Web.

Como funciona o processo do TC39?

O TC39 é o comitê responsável por evoluir a linguagem JavaScript pelo padrão ECMAScript.

O #SmooshGate fez com que algumas pessoas acreditassem que o "TC39 quer renomear flatten para smoosh", mas era uma brincadeira interna que não foi bem comunicada externamente. Decisões importantes, como renomear uma proposta, não são tomadas de ânimo leve, não são tomadas por uma única pessoa e definitivamente não são tomadas de um dia para o outro com base em um único comentário do GitHub.

O TC39 opera em um processo de preparo claro para propostas de recursos. As propostas do ECMAScript e todas as mudanças importantes nelas (incluindo a renomeação de métodos) são discutidas durante as reuniões do TC39 e precisam ser aprovadas por todo o comitê antes de se tornarem oficiais. No caso de Array.prototype.flatten, a proposta já passou por várias etapas de acordo, até a Etapa 3, indicando que o recurso está pronto para ser implementado em navegadores da Web. É comum que outros problemas de especificação surjam durante a implementação. Nesse caso, o feedback mais importante veio depois de tentar enviar: o recurso, no estado atual, quebra a Web. Problemas difíceis de prever como esses fazem parte da razão pela qual o processo TC39 não termina apenas quando os navegadores oferecem um recurso.

O TC39 opera por consenso, o que significa que o comitê precisa concordar com todas as novas mudanças. Mesmo que smoosh fosse uma sugestão séria, é provável que um membro do comitê se opusesse a ela em favor de um nome mais comum, como compact ou chain.

A mudança de nome de flatten para smoosh (mesmo que não fosse uma piada) nunca foi discutida em uma reunião do TC39. Dessa forma, a postura oficial do TC39 sobre esse assunto é desconhecida. Nenhum indivíduo pode falar em nome de toda a TC39 até que um consenso seja alcançado na próxima reunião.

As reuniões do TC39 geralmente são realizadas por pessoas com origens muito diversas: algumas têm anos de experiência em design de linguagem de programação, outras trabalham em um navegador ou mecanismo JavaScript, e um número cada vez maior de participantes está presente para representar a comunidade de desenvolvedores JavaScript.

Como o SmooshGate foi resolvido, no fim das contas?

Durante a reunião do TC39 de maio de 2018, o #SmooshGate foi oficialmente resolvido com a renomeação de flatten para flat.

Array.prototype.flat e Array.prototype.flatMap enviados na V8 v6.9 e no Chrome 69.