O que aconteceu com o smoosh?
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
amplamente utilizada, é provável que muitos outros 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 de 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, independentemente de o flatten
nativo estar disponível.
Até aqui, tudo bem!
Infelizmente, algo mais acontece. O MooTools copia todos os
métodos de matriz personalizados para Elements.prototype
(onde 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á quebrado.
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. A extensão de protótipos nativos é geralmente aceita como uma prática ruim atualmente, porque não combina 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 lançamento de um novo recurso do navegador fizer com que os sites atuais 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 de sites passaram de ter 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 pune eles, 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 de fazer.
Isso significa que as APIs ruins nunca podem ser removidas da Plataforma Web?
Depende. Em casos raros, recursos incorretos podem ser removidos da Web. Mesmo descobrir se é possível remover um recurso é um esforço muito complicado, que exige uma telemetria extensa para quantificar quantas páginas da Web teriam o comportamento alterado. No entanto, quando o recurso é suficientemente inseguro, é prejudicial para os usuários ou é usado muito raramente, isso pode ser feito.
<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 seus sites de oito anos por causa de um problema de compatibilidade da Web.
Como funciona o processo 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, são parte do motivo pelo qual
o processo do TC39 não termina assim que os navegadores lançam 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. Portanto, a posição oficial do TC39 sobre
esse assunto ainda é 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?
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.