Co się stało z smoosh?
Proponowana funkcja języka JavaScript o nazwie Array.prototype.flatten
okazuje się niezgodna z internetem. Wprowadzenie tej funkcji w Firefox Nightly spowodowało usterkę co najmniej jednej popularnej witryny. Ponieważ problematyczny kod jest częścią popularnej biblioteki MooTools, prawdopodobnie dotyczy to wielu innych witryn. (chociaż w 2018 r. MooTools nie jest często używany do tworzenia nowych witryn, był bardzo popularny i nadal jest obecny w wielu witrynach produkcyjnych).
Autor propozycji zażartował, że aby uniknąć problemów ze zgodnością, można zmienić nazwę flatten
na smoosh
. Żart nie był jasny dla wszystkich, więc niektórzy użytkownicy zaczęli błędnie sądzić, że nowa nazwa została już wybrana, i sytuacja szybko się nasiliła.
Co robi Array.prototype.flatten
?
Funkcja Array.prototype.flat
, pierwotnie zaproponowana jako Array.prototype.flatten
, spłaszcza tablice rekurencyjnie aż do określonej wartości depth
, która domyślnie wynosi 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]
Ta sama propozycja zawiera funkcję Array.prototype.flatMap
, która jest podobna do funkcji Array.prototype.map
, ale spłaszcza wynik w nowej tablicy.
[2, 3, 4].flatMap((x) => [x, x * 2]);
// → [2, 4, 3, 6, 4, 8]
Co powoduje ten problem?
MooTools definiuje własną niestandardową wersję Array.prototype.flatten
:
Array.prototype.flatten = /* non-standard implementation */;
Implementacja flatten
w MooTools różni się od proponowanego standardu.
To jednak nie jest problem. Gdy przeglądarki udostępniają Array.prototype.flatten
natywnie, MooTools zastępuje natywną implementację. Dzięki temu kod korzystający z zachowania MooTools działa zgodnie z oczekiwaniami niezależnie od tego, czy natywna funkcja flatten
jest dostępny.
Póki co idzie dobrze.
Niestety, dzieje się coś innego. MooTools kopiuje wszystkie niestandardowe metody tablic do Elements.prototype
(gdzie Elements
jest interfejsem API specyficznym dla MooTools):
for (var key in Array.prototype) {
Elements.prototype[key] = Array.prototype[key];
}
for
-in
iteruje właściwościami „enumerowanymi”, które nie obejmują metod natywnych, takich jak Array.prototype.sort
, ale obejmują właściwości przypisane regularnie, takie jak Array.prototype.foo = whatever
. Ale – i tutaj jest haczyk – jeśli zastąpisz właściwość niewyliczalną, np. Array.prototype.sort = whatever
, pozostanie ona niewyliczalną.
Obecnie funkcja Array.prototype.flatten = mooToolsFlattenImplementation
tworzy wyliczalną właściwość flatten
, która jest później kopiowana do Elements
. Jeśli jednak przeglądarki udostępniają natywną wersję elementu flatten
, staje się on niewyliczalny i nie jest kopiowany do elementu Elements
. Każdy kod korzystający z biblioteki MooToolsElements.prototype.flatten
jest teraz uszkodzony.
Chociaż wydaje się, że zmiana natywnej wartości Array.prototype.flatten
na enumerable rozwiąże problem, prawdopodobnie spowoduje jeszcze więcej problemów ze zgodnością. Każda witryna, która używa pętli for
-in
do iteracji w tablicy (co jest złym rozwiązaniem, ale czasami się zdarza), nagle uzyskałaby dodatkową iterację pętli dla właściwości flatten
.
Większym problemem jest modyfikowanie wbudowanych obiektów. Rozszerzanie prototypów natywnych jest obecnie powszechnie uznawane za złą praktykę, ponieważ nie komponuje się dobrze z innymi bibliotekami i kodem innych firm. Nie modyfikuj obiektów, które do Ciebie nie należą.
Dlaczego nie pozostawimy dotychczasowej nazwy i nie zerwiemy internetu?
W 1996 r., zanim stało się to powszechne, a zanim „HTML5” stało się czymś ważnym, uruchomiliśmy witrynę Space Jam. Obecnie strona działa tak samo jak 22 lata temu.
Jak to się stało? Czy przez te wszystkie lata ktoś zajmował się tą witryną, aktualizując ją za każdym razem, gdy dostawcy przeglądarek wprowadzali nową funkcję?
Okazuje się, że „nie psuj internetu” to główna zasada projektowania kodu HTML, CSS, JavaScriptu i innych standardów powszechnie używanych w internecie. Jeśli wdrożenie nowej funkcji przeglądarki powoduje, że istniejące witryny przestają działać, jest to niekorzystne dla wszystkich:
- użytkownicy dotkniętych witryn nagle odczuwają pogorszenie jakości usług;
- właściciele witryny przeszli od witryny, która działała bez zarzutu, do niedziałającej, bez wprowadzania jakichkolwiek zmian;
- dostawcy przeglądarek udostępniający nową funkcję tracą udział w rynku, ponieważ użytkownicy przełączają się na przeglądarki, które „działają”;
- Gdy problem ze zgodnością stanie się znany, inni dostawcy przeglądarek odmówią jego udostępnienia. Specyfikacja funkcji nie odpowiada rzeczywistości („to tylko fikcja”), co nie sprzyja procesowi standaryzacji.
Z pewnością MooTools popełniło błąd, ale zepsucie internetu nie jest karą dla MooTools, tylko dla użytkowników. Ci użytkownicy nie wiedzą, czym jest narzędzie moo. Możemy też znaleźć inne rozwiązanie, a użytkownicy będą mogli nadal korzystać z Internetu. Wybór jest prosty.
Czy to oznacza, że złe interfejsy API nigdy nie mogą zostać usunięte z platformy internetowej?
To zależy. W rzadkich przypadkach nieprawidłowe funkcje mogą zostać usunięte z Internetu. Nawet ustalenie, czy możliwe jest usunięcie danej funkcji, jest bardzo trudne i wymaga rozbudowanej telemetrii, aby określić, ile stron internetowych zmieniłoby swoje działanie. Może się to jednak zdarzyć, gdy funkcja jest niewystarczająco bezpieczna, szkodliwa dla użytkowników lub używana bardzo rzadko.
<applet>
, <keygen>
i showModalDialog()
to przykłady nieprawidłowych interfejsów API, które zostały usunięte z platformy Web Platform.
Dlaczego nie naprawimy MooTools?
Dobrym pomysłem jest wdrożenie poprawki w MooTools, aby nie rozszerzała już wbudowanych obiektów. Nie rozwiązuje jednak problemu. Nawet gdyby MooTools opublikowało zaktualizowaną wersję, wszystkie istniejące witryny, które z niej korzystają, musiałyby zostać zaktualizowane, aby problem ze zgodnością zniknął.
Czy użytkownicy nie mogą po prostu zaktualizować swojej kopii MooTools?
W idealnym świecie MooTools udostępniałaby łatkę, a następnego dnia każda witryna korzystająca z MooTools zostałaby magicznie zaktualizowana. Problem rozwiązany, prawda?
Niestety, jest to nierealne. Nawet jeśli udałoby się zidentyfikować wszystkie witryny, które są dotknięte problemem, znaleźć informacje kontaktowe do każdej z nich, skontaktować się z właścicielami i przekonać ich do wprowadzenia aktualizacji (co może wymagać przeprojektowania całej bazy kodu), cały proces w najlepszym razie zajęłby lata.
Pamiętaj, że wiele z tych witryn jest starych i prawdopodobnie nie jest już aktualizowanych. Nawet jeśli osoba, która zajmuje się witryną, nadal pracuje w Twojej firmie, może nie być tak doświadczonym programistą stron internetowych jak Ty. Nie możemy wymagać od wszystkich użytkowników, aby zmienili swoją 8-letnią stronę internetową z powodu problemów ze zgodnością.
Jak wygląda proces TC39?
TC39 to komitet odpowiedzialny za rozwój języka JavaScript w ramach standardu ECMAScript.
#SmooshGate sprawił, że niektórzy użytkownicy uwierzyli, że „TC39 chce zmienić nazwę flatten
na smoosh
”. Była to jednak wewnętrzna żartobliwa nazwa, która nie została dobrze zakomunikowana na zewnątrz.
Ważne decyzje, takie jak zmiana nazwy propozycji, nie są podejmowane lekkomyślnie, nie są podejmowane przez jedną osobę i zdecydowanie nie są podejmowane z dnia na dzień na podstawie jednego komentarza na GitHubie.
TC39 stosuje jasny proces wdrażania propozycji funkcji.
Propozycje ECMAScript i wszelkie istotne zmiany w nich (w tym zmiana nazwy metody) są omawiane podczas spotkań TC39 i muszą zostać zatwierdzone przez cały komitet, zanim staną się oficjalne. W przypadku Array.prototype.flatten
propozycja przeszła już kilka etapów uzgodnień, aż do etapu 3, co oznacza, że funkcja jest gotowa do wdrożenia w przeglądarkach internetowych. Podczas wdrażania często pojawiają się dodatkowe problemy ze specyfikacją. W tym przypadku najważniejsze opinie otrzymaliśmy po wdrożenie tej funkcji: w jej obecnej formie funkcja ta powoduje błędy w sieci. Trudne do przewidzenia problemy, takie jak te, są jednym z powodów, dla których proces TC39 nie kończy się wraz z wdrożeniem funkcji przez przeglądarki.
TC39 działa na zasadzie konsensusu, co oznacza, że komitet musi wyrazić zgodę na wszelkie nowe zmiany. Nawet jeśli smoosh
to poważna propozycja, wydaje się prawdopodobne, że członek komitetu sprzeciwi się jej na rzecz bardziej powszechnej nazwy, takiej jak compact
lub chain
.
Zmiana nazwy z flatten
na smoosh
(nawet jeśli nie była to żart) nigdy nie była omawiana na spotkaniu TC39. Dlatego oficjalne stanowisko TC39 w tej sprawie jest obecnie nieznane. Dopóki nie osiągniemy konsensusu na kolejnym spotkaniu, nikt nie może wypowiadać się w imieniu całego komitetu TC39.
W spotkaniach TC39 zazwyczaj uczestniczą osoby o bardzo zróżnicowanym doświadczeniu: niektóre mają wieloletnie doświadczenie w projektowaniu języków programowania, inne pracują nad przeglądarką lub silnikiem JavaScript, a coraz więcej osób reprezentuje społeczność programistów JavaScript.
Jak rozwiązano problem SmooshGate?
Podczas spotkania TC39 w maju 2018 r. problem #SmooshGate został oficjalnie rozwiązany przez zmianę nazwy flatten
na flat
.
Array.prototype.flat
i Array.prototype.flatMap
zostały udostępnione w V8 6.9 i Chrome 69.