SmooshGate に関するよくある質問

どうしたの?

Array.prototype.flatten という JavaScript 言語機能の提案が、ウェブ互換性がないことがわかりました。Firefox Nightly にこの機能を配布したことで、少なくとも 1 つの人気ウェブサイトが動作しなくなりました。問題のあるコードは広範な MooTools ライブラリの一部であるため、より多くのウェブサイトが影響を受ける可能性があります。(MooTools は 2018 年、新しいウェブサイトであまり使用されませんが、以前は非常に人気があり、現在でも多くの本番環境ウェブサイトで使用されています)。

提案者は、互換性の問題を回避するために、flatten の名前を smoosh に変更することを冗談めかして提案しました。このジョークは誰にとっても明確ではありませんでした。新しい名前はすでに決まっていると誤認する人もいて、事態は急速にエスカレートしました。

Array.prototype.flatten の機能

元々 Array.prototype.flatten として提案された Array.prototype.flat は、指定された depth(デフォルトは 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]

同じ提案には Array.prototype.flatMap が含まれています。これは結果を新しい配列にフラット化するという点を除き、Array.prototype.map と似ています。

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

この問題を引き起こす MooTools の挙動

MooTools では、独自の非標準バージョンの Array.prototype.flatten を定義しています。

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

MooTools の flatten 実装は、提案されている標準とは異なります。ただし、これは問題ではありません。ブラウザが Array.prototype.flatten をネイティブで出荷する場合、MooTools はネイティブ実装をオーバーライドします。これにより、ネイティブの flatten が使用可能かどうかにかかわらず、MooTools の動作に依存するコードが意図したとおりに機能します。ここまでは順調です。

残念なことに、その後別の問題が発生します。MooTools は、すべてのカスタム配列メソッドを Elements.prototype にコピーします(ここで、Elements は MooTools 固有の API です)。

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

for-in は、「enumerable」プロパティを反復処理します。これには Array.prototype.sort などのネイティブ メソッドは含まれませんが、Array.prototype.foo = whatever などの通常割り当てのプロパティは含まれます。しかし、ここで重要なのは、列挙不可能なプロパティ(Array.prototype.sort = whatever など)を上書きした場合、そのプロパティは列挙不可能なままになります。

現在、Array.prototype.flatten = mooToolsFlattenImplementation は列挙型の flatten プロパティを作成するため、後で Elements にコピーされます。ただし、ブラウザがネイティブ バージョンの flatten を提供する場合、その数は列挙不可能になり、Elements にコピーされませんMooTools の Elements.prototype.flatten に依存するコードはすべて破損しています。

ネイティブ Array.prototype.flatten を列挙可能に変更すると問題が解決するように見えますが、より多くの互換性の問題が発生する可能性があります。for-in を使用して配列の反復処理を行っているすべてのウェブサイト(これはおすすめしませんが、実際には発生します)で、flatten プロパティで追加のループ反復処理が突然発生します。

ここでの大きな根本的な問題は、組み込みオブジェクトの変更です。ネイティブ プロトタイプを拡張することは、他のライブラリやサードパーティのコードとうまく構成できないため、現在は一般的に推奨されていません。所有していないオブジェクトは変更しないでください。

既存の名称を変えずに、ウェブを壊してはどうでしょうか?

CSS が普及する前の 1996 年、「HTML5」が普及するずっと前、Space Jam ウェブサイトが公開されました。現在でもウェブサイトは 22 年前と同じように機能しています

なぜそのようなことが起きたのでしょうか?ブラウザベンダーが新機能をリリースするたびに そのウェブサイトをアップデートしている人がいるでしょうか

結局のところ、「ウェブを破壊しない」ことが、HTML、CSS、JavaScript、その他ウェブで広く使用されている標準に関する第一の設計原則です。新しいブラウザ機能の提供によって既存のウェブサイトが機能しなくなることは、すべての人にとって良いことです。

  • 影響を受けたウェブサイトの訪問者は、突然ユーザー エクスペリエンスに悪影響を及ぼします。
  • ウェブサイトの所有者は何も変更することなく 正常に機能していたウェブサイトから機能しないウェブサイトに 変更しました
  • 新機能をリリースしているブラウザ ベンダーがマーケット シェアを失っている。これは、ユーザーが「ブラウザ X で動作する」ことに気付いた後にブラウザを切り替えたことが原因です。
  • 互換性の問題が判明すると、他のブラウザ ベンダーはその製品の提供を拒否します。機能の仕様が現実に合っていないため(「単なるフィクション作品ではなく」)、標準化プロセスには適していません。

もちろん、振り返ってみると、MooTools が誤った行動を起こしたのは確かです。しかし、ウェブを壊しても罰はされず、ユーザーに罰則が課されます。これらのユーザーは Moo ツールとは どのようなものかわかりませんが、別の解決策を見つけることもできます。ユーザーは引き続きウェブを使用します。選択は簡単です。

ウェブ プラットフォームから不正な API を削除できないということでしょうか?

場合によって変わります。まれに、問題のある機能をウェブから削除できます。ある機能を削除可能かどうかを知るだけでも、非常に厄介な作業です。動作が変更されたウェブページの数を定量化するには、広範なテレメトリーが必要です。ただし、その機能の安全性が十分でない、ユーザーにとって有害である場合、またはほとんど使用されない場合には、このような対応が可能です。

<applet><keygen>showModalDialog() はすべて、ウェブ プラットフォームから削除された不正な API の例です。

MooTools を修正してはどうでしょうか?

MooTools にパッチを適用して組み込みオブジェクトが拡張されないようにすることをおすすめします。しかし、それで目の前の問題を解決できるわけではありません。MooTools がパッチ適用済みバージョンをリリースしたとしても、互換性の問題をなくすには、MooTools を使用する既存のウェブサイトをすべて更新する必要があります。

MooTools のコピーを更新できないのでしょうか?

理想としては、MooTools がパッチをリリースし、MooTools を使用するすべてのウェブサイトが翌日、魔法のように更新されます。問題は解決しましたね

残念ながら、これは現実的ではありません。誰かがなんらかの方法で影響を受けるウェブサイトをすべて特定し、それぞれの連絡先情報を見つけて、すべてのウェブサイト所有者に連絡をとり、更新の実行を説得(コードベース全体をリファクタリングすることになるかもしれません)したとしても、プロセス全体はせいぜい何年もかかるでしょう。

これらのウェブサイトの多くは古く、メンテナンスが行われていない可能性が高いことにご注意ください。メンテナンス担当者が近くにいても、ご自身のような高度なスキルを持つウェブ デベロッパーでない可能性があります。ウェブの互換性の問題で、誰もが使い始めて 8 年間だったウェブサイトを変更することは期待できません。

TC39 のプロセスの仕組み

TC39 は、ECMAScript 標準による JavaScript 言語の進化を担当する委員会です。

#SmooshGate により、「TC39 が flatten の名前を smoosh に変更したい」という誤解が生まれましたが、これは面白いジョークであり、外部への周知は十分に行われていません。 提案の名前の変更などの重要な決定は、慎重に行われたものではなく、1 人の人間が行うものでもなく、GitHub の 1 つのコメントから一夜にして行われるわけでもありません。

TC39 は、機能の提案の明確なステージング プロセスに基づいて運用されます。ECMAScript の提案とそれに対する大きな変更(メソッド名の変更など)は、TC39 の会議で議論されます。正式に承認される前に、委員会全体で承認する必要があります。Array.prototype.flatten の場合、提案は複数の合意ステージを経てステージ 3 まで進んでおり、ウェブブラウザでこの機能を実装する準備が整っていることを示しています。実装中に仕様の問題が追加されることは珍しくありません。この場合、最も重要なフィードバックはリリースを試みた後に届きました。つまり、現在の状態では機能がウェブに支障をきたします。TC39 のプロセスは、ブラウザから機能がリリースされただけでは終了しない理由の一つとして、このような予測が困難な問題があります。

TC39 はコンセンサスに基づいて活動します。つまり、委員会は新しい変更について合意する必要があります。smoosh が真剣な提案であったとしても、委員会のメンバーは compactchain のようなより一般的な名前に異議を唱える可能性が高いと思われます。

flatten から smoosh への名称変更は(冗談でなかった場合でも)TC39 の会議では一度も議論されていません。そのため、このトピックに関する TC39 の正式なスタンスは不明です。次の会議で合意に達するまで、TC39 全員を代表して発言することはできません。

TC39 の会議には、一般的に多様なバックグラウンドを持つ人々が参加します。プログラミング言語の設計に長年携わっている人、ブラウザや JavaScript エンジンを担当している人、JavaScript のデベロッパー コミュニティを代表する人がどんどん参加しています。

SmooshGate は最終的にどのように解決されましたか?

2018 年 5 月の TC39 会議中に、flatten の名前が flat に変更され、#SmooshGate が正式に解決されました。

Array.prototype.flatArray.prototype.flatMap は、V8 v6.9 と Chrome 69 で提供されています。