Perguntas frequentes sobre o SmooshGate

O que aconteceu de smoosh?!

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

O autor da proposta, de forma divertida, sugeriu renomear flatten como smoosh para evitar o problema de compatibilidade. A piada não ficava clara para todos, algumas pessoas começaram a acreditar incorretamente que o novo nome já havia sido decidido, e as coisas foram escaladas rapidamente.

O que o Array.prototype.flatten faz?

Array.prototype.flat, originalmente proposto como Array.prototype.flatten, nivela matrizes recursivamente até o depth especificado, que tem como padrão 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, mas nivela 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?

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

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

A implementação de flatten da MooTools é diferente do padrão proposto. No entanto, esse não é o problema. Quando os navegadores enviam Array.prototype.flatten nativamente, 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 flatten nativa estar disponível. Até aqui, tudo bem!

Infelizmente, outra coisa acontece. O MooTools copia todos os métodos de matriz personalizada 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 em propriedades "enumerais", que não inclui métodos nativos como Array.prototype.sort, mas inclui propriedades atribuídas regularmente, como Array.prototype.foo = whatever. No entanto, e este é o destaque, se você substituir uma propriedade não enumerada, por exemplo, Array.prototype.sort = whatever, ela vai permanecer não enumerada.

Atualmente, o Array.prototype.flatten = mooToolsFlattenImplementation cria uma propriedade flatten enumerável, para que ela seja copiada para Elements. No entanto, se os navegadores tiverem uma versão nativa de flatten, ela se tornará não numerada e não será copiada para Elements. Todos os códigos que dependem do Elements.prototype.flatten da MooTools agora estão corrompidos.

Embora pareça que mudar o Array.prototype.flatten nativo para um número enumerado 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 não recomendada, mas acontece) receberiam uma iteração de loop extra para a propriedade flatten de repente.

O maior problema subjacente é a modificação de objetos integrados. Atualmente, a extensão de protótipos nativos é aceita como uma prática não recomendada, porque não funciona bem com outras bibliotecas e códigos de terceiros. Não modifique objetos que não sejam de sua propriedade.

Por que não podemos simplesmente manter o nome que já existe e quebrar a web?

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

Como isso aconteceu? Alguém manteve o site por todos esses anos, atualizando-o toda vez que os fornecedores de navegador lançavam um novo recurso?

Como foi constatado, "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 sites existentes parem de funcionar, isso será ruim para todos:

  • os visitantes dos sites afetados repentinamente têm uma experiência do usuário corrompida;
  • os proprietários passaram de ter um site que funcionava perfeitamente para um não funcional, sem alterar nada;
  • os fornecedores de navegadores que lançam o novo recurso perdem participação de mercado porque os usuários trocam de navegador depois de perceber que "ele funciona no navegador X";
  • quando o problema de compatibilidade for conhecido, outros fornecedores de navegador se recusarão a enviá-lo. A especificação de recursos não corresponde à realidade ("nada além de uma obra 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 puni os usuários, mas sim 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 de fazer.

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

Depende. Em casos raros, os recursos maliciosos podem ser removidos da Web. Mesmo 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 for suficientemente inseguro, prejudicar os usuários ou for usado muito raramente.

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

Por que só não corrigimos o MooTools?

Uma boa ideia é aplicar um patch no MooTools para que ele não estenda mais objetos integrados. No entanto, isso não resolve o problema em questão. Mesmo que a MooTools lance uma versão com patch, todos os sites que a usam precisarão ser atualizados para que o problema de compatibilidade desapareça.

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

Em um mundo perfeito, a MooTools lançaria um patch e todos os sites que usam o MooTools seriam atualizados em um passe de mágica no dia seguinte. Problema resolvido, certo?!

Infelizmente, isso não é realista. Mesmo que alguém precisasse identificar o conjunto completo de sites afetados, conseguir encontrar os dados de contato de cada um deles, entrar em contato com todos os proprietários do site e convencer todos a realizar a atualização (o que pode significar refatorar toda a base de código), todo o processo levaria anos, na melhor das hipóteses.

Lembre-se de que muitos desses sites são antigos e provavelmente não têm manutenção. 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 oito anos por causa de um problema de compatibilidade com a Web.

Como funciona o processo do TC39?

O TC39 é o comitê encarregado de aprimorar a linguagem JavaScript por meio do padrão ECMAScript.

#SmooshGate fez alguns acreditarem que “TC39 quer renomear flatten como smoosh”, mas era uma piada que não foi bem divulgada externamente. Grandes decisões, como renomear uma proposta, são levadas a sério, não são tomadas por uma única pessoa e definitivamente não são tomadas da noite para o dia, com base em um único comentário do GitHub.

O TC39 opera com um processo de preparo claro para propostas de recursos. As propostas da 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 Fase 3, indicando que o recurso está pronto para ser implementado em navegadores da Web. É comum que surjam outros problemas de especificações durante a implementação. Nesse caso, o feedback mais importante veio após a tentativa de envio: o recurso, no estado atual, interrompe a Web. Problemas difíceis de prever como esses são parte da razão pela qual o processo do TC39 não termina apenas quando os navegadores enviam um recurso.

O TC39 funciona com base em consenso, ou seja, o comitê precisa concordar com quaisquer novas mudanças. Mesmo que smoosh fosse uma sugestão séria, parece que um membro do comitê se oporia a ela em favor de um nome mais comum, como compact ou chain.

A renomeação de flatten para smoosh (mesmo que não tenha sido uma brincadeira) nunca foi discutida em uma reunião do TC39. Por isso, a posição oficial do TC39 em relação a esse tema é desconhecida. Nenhum indivíduo pode falar em nome de todo o TC39 até chegar a um consenso na próxima reunião.

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

Como o SmooshGate foi resolvido?

Durante a reunião do TC39 de maio de 2018 (em inglês), o #SmooshGate foi oficialmente resolvido renomeando flatten como flat.

Array.prototype.flat e Array.prototype.flatMap foram lançados no V8 v6.9 e no Chrome 69.