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.