SmooshGate に関するよくある質問

スムージングが何ですか?

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

提案の作成者は、互換性の問題を回避するために flatten の名前を smoosh に変更することを冗談めかして提案しました。ジョークが誰にでも明らかだったわけではなく、新しい名前がすでに決まっていると誤って信じ始めた人もおり、事態は急速にエスカレーションしました。

Array.prototype.flatten の機能は次の通りです。

Array.prototype.flat(元々は Array.prototype.flatten として提案)は、指定された 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];
}

forin は「列挙可能」なプロパティを反復処理します。これには 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 を列挙可能に変更すると問題が解決するように思えますが、互換性の問題がさらに発生する可能性があります。forin を使用して配列を反復処理するすべてのウェブサイト(これは好ましくない方法ですが、実際に行われています)で、flatten プロパティのループが突然追加されます。

根本的な問題は、組み込みオブジェクトの変更です。ネイティブ プロトタイプの拡張は、他のライブラリやサードパーティ コードとうまくコンポーズされないため、現在では一般的に悪い方法と見なされています。自分が所有していないオブジェクトは変更しないでください。

既存の名前をそのままにして、ウェブを壊さないのはなぜですか?

1996 年、CSS が普及する前、そして「HTML5」が登場するずっと前に、スペース ジャムのウェブサイトが公開されました。現在、このウェブサイトは 22 年前とまったく同じ方法で動作しています。

なぜそのような事態になったのでしょうか?誰かがそのウェブサイトを長年にわたって維持し、ブラウザ ベンダーが新しい機能をリリースするたびに更新していたのでしょうか?

実際のところ、「ウェブを壊さない」ことは、HTML、CSS、JavaScript、およびウェブで広く使用されている他の標準の 1 番の設計原則です。新しいブラウザ機能をリリースした結果、既存のウェブサイトが動作しなくなると、すべての人にとって不利な結果になります。

  • 影響を受けるウェブサイトの訪問者が突然、ユーザー エクスペリエンスの不具合に遭遇する。
  • ウェブサイト所有者が何も変更していないのに、ウェブサイトが正常に動作していた状態から機能しなくなった状態に変わっている。
  • 新機能をリリースしたブラウザ ベンダーが市場シェアを失う。ユーザーが「ブラウザ X では動作する」ことに気づき、ブラウザを切り替えるため。
  • 互換性の問題が判明すると、他のブラウザ ベンダーはリリースを拒否します。機能仕様が現実と一致していない(「フィクションにすぎない」)。これは標準化プロセスにとって好ましくありません。

確かに、MooTools は後から考えれば間違ったことをしたが、ウェブを破壊しても彼らを罰することはできない。罰せられるのはユーザーである。このようなユーザーは、moo ツールが何であるかを知りません。また、別の解決策を見つけて、ユーザーがウェブを引き続き使用できるようにすることもできます。選択は簡単です。

つまり、不適切な API をウェブ プラットフォームから削除することはできないということですか?

場合によって変わります。まれに、不適切な機能がウェブから削除されることがあります。機能を削除できるかどうかを判断するだけでも非常に難しい作業です。ウェブページの動作が変更されるページの数を定量化するには、広範なテレメトリーが必要です。ただし、機能が十分に安全でない場合、ユーザーに有害な場合、または非常にまれにしか使用されない場合は、この操作を行うことができます。

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

MooTools を修正しないのはなぜですか?

MooTools にパッチを適用して、組み込みオブジェクトを拡張しないようにすることをおすすめします。ただし、これでは当面の問題は解決しません。MooTools がパッチ適用版をリリースしたとしても、互換性の問題を解消するには、それを使用している既存のすべてのウェブサイトを更新する必要があります。

MooTools のコピーを更新するだけでよいのでは?

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

残念ながら、これは現実的ではありません。影響を受けるウェブサイトをすべて特定し、それぞれの連絡先情報を入手し、すべてのウェブサイト所有者に連絡して、更新(コードベース全体のリファクタリングを意味する場合があります)を実行するよう説得できたとしても、このプロセス全体にかかる時間は最長で数年かかります。

これらのウェブサイトの多くは古く、メンテナンスされていない可能性があります。メンテナンス担当者がまだ存在する場合でも、その担当者があなたのような高度なスキルを持つウェブ デベロッパーではない可能性があります。ウェブの互換性の問題があるからといって、8 年前のウェブサイトを変更するよう求めることはできません。

TC39 のプロセスの仕組み

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

#SmooshGate により、「TC39 は flatten の名前を smoosh に変更したい」と考える人がいましたが、これは社内向けの冗談で、社外に十分に伝えられていませんでした。提案の名前変更などの重要な決定は、軽率に行われるものではなく、1 人の担当者が行うものではありません。また、GitHub の 1 つのコメントに基づいて、1 晩で行われるものでもありません。

TC39 は、機能提案に対して明確なステージング プロセスを運用しています。ECMAScript の提案とその主な変更(メソッドの名前変更など)は TC39 のミーティングで議論され、正式になる前に委員会全体の承認を得る必要があります。Array.prototype.flatten の場合、このプロポーザルはすでにステージ 3 まで、複数の合意段階を経ており、この機能はウェブブラウザに実装する準備が整っていることを示しています。実装中に追加の仕様の問題が発生することはよくあります。この場合、最も重要なフィードバックは、リリースに寄せられました。この機能は、現在の状態ではウェブを破壊します。このような予測しにくい問題が、TC39 プロセスがブラウザが機能をリリースした時点で終了しない理由の一部です。

TC39 はコンセンサスに基づいて運営されています。つまり、新しい変更については委員会が合意する必要があります。smoosh が真剣な提案であったとしても、委員会のメンバーは compactchain などの一般的な名前を好み、smoosh に反対する可能性が高いと思われます。

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 でリリースされました。