무슨 일이 있었나요?
Array.prototype.flatten
라는 JavaScript 언어 기능에 관한 제안서가 웹과 호환되지 않는 것으로 확인되었습니다. Firefox Nightly에서 이 기능을 출시한 결과 하나 이상의 인기 웹사이트가 중단되었습니다. 문제가 되는 코드는 널리 사용되는 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
는 'enumarable' 속성을 반복합니다. 여기에는 Array.prototype.sort
와 같은 네이티브 메서드는 포함되지 않지만 Array.prototype.foo = whatever
와 같이 정기적으로 할당된 속성은 포함됩니다. 하지만 중요한 점은 Array.prototype.sort = whatever
와 같이 enumarable이 아닌 속성을 덮어쓰면 enumarable이 아닌 상태로 유지된다는 것입니다.
현재 Array.prototype.flatten = mooToolsFlattenImplementation
는 열거 가능한 flatten
속성을 생성하므로 나중에 Elements
에 복사됩니다. 하지만 브라우저가 네이티브 버전의 flatten
를 제공하는 경우 flatten
는 열거 불가능해지며 Elements
에 복사되지 않습니다. MooTools의 Elements.prototype.flatten
를 사용하는 모든 코드가 이제 손상됩니다.
네이티브 Array.prototype.flatten
를 enumarable로 변경하면 문제가 해결될 것 같지만, 더 많은 호환성 문제가 발생할 수 있습니다. 배열을 반복하기 위해 for
-in
를 사용하는 모든 웹사이트 (잘못된 관행이지만 발생함)는 갑자기 flatten
속성에 대한 루프 반복을 추가로 받게 됩니다.
여기서 더 큰 근본적인 문제는 기본 제공 객체를 수정하는 것입니다. 네이티브 프로토타입을 확장하는 것은 다른 라이브러리 및 서드 파티 코드와 잘 조합되지 않으므로 현재 일반적으로 좋지 않은 사례로 간주됩니다. 소유하지 않은 객체는 수정하지 마세요.
기존 이름을 그대로 두고 웹을 깨는 게 어떨까요?
CSS가 보편화되고 'HTML5'가 등장하기 훨씬 전인 1996년에 스페이스 잼 웹사이트가 출시되었습니다. 오늘날 이 웹사이트는 22년 전과 동일한 방식으로 작동합니다.
어떻게 된 건가요? 그동안 누군가 브라우저 공급업체가 새 기능을 출시할 때마다 웹사이트를 업데이트하며 유지관리했나요?
'웹을 중단하지 마세요'는 HTML, CSS, JavaScript, 웹에서 널리 사용되는 다른 모든 표준의 1차 디자인 원칙입니다. 새 브라우저 기능을 출시하면 기존 웹사이트가 작동하지 않게 되며 이는 모든 사용자에게 좋지 않습니다.
- 영향을 받은 웹사이트의 방문자에게 갑자기 사용자 환경이 손상됩니다.
- 웹사이트 소유자가 아무것도 변경하지 않았는데 웹사이트가 제대로 작동하던 상태에서 작동하지 않는 상태로 바뀌었습니다.
- 새 기능을 제공하는 브라우저 공급업체가 시장 점유율을 잃습니다. 사용자가 '브라우저 X에서 작동'하는 것을 발견한 후 브라우저를 전환하기 때문입니다.
- 호환성 문제가 알려지면 다른 브라우저 공급업체는 이를 제공하지 않습니다. 기능 사양이 현실과 일치하지 않으며 ('허구에 불과') 이는 표준화 프로세스에 좋지 않습니다.
물론 MooTools가 잘못한 것은 맞지만 웹을 중단하면 MooTools가 벌을 받는 것이 아니라 사용자가 벌을 받게 됩니다. 이러한 사용자는 moo 도구가 무엇인지 모릅니다. 또는 다른 솔루션을 찾을 수 있으며 사용자는 계속 웹을 사용할 수 있습니다. 선택하기 쉽습니다.
나쁜 API는 웹 플랫폼에서 삭제할 수 없다는 뜻인가요?
경우에 따라 다릅니다. 드물지만 웹에서 잘못된 기능이 삭제되는 경우도 있습니다. 기능을 삭제할 수 있는지 파악하는 것조차 매우 까다로운 작업이며, 광범위한 원격 분석을 통해 동작이 변경되는 웹페이지 수를 수치화해야 합니다. 하지만 기능이 충분히 안전하지 않거나 사용자에게 유해하거나 매우 드물게 사용되는 경우에는 이렇게 할 수 있습니다.
<applet>
, <keygen>
, showModalDialog()
는 모두 웹 플랫폼에서 삭제된 나쁜 API의 예입니다.
MooTools를 수정하면 안 되나요?
MooTools가 더 이상 기본 제공 객체를 확장하지 않도록 패치하는 것이 좋습니다. 그러나 당면한 문제는 해결되지 않습니다. MooTools에서 패치 버전을 출시하더라도 MooTools를 사용하는 기존 웹사이트는 모두 업데이트해야 호환성 문제가 사라질 수 있습니다.
사람들이 MooTools 사본을 업데이트하면 안 되나요?
이상적인 상황에서는 MooTools가 패치를 출시하면 MooTools를 사용하는 모든 웹사이트가 다음날 마술처럼 업데이트됩니다. 문제가 해결되었나요?
안타깝게도 이는 현실적이지 않습니다. 누군가 영향을 받는 웹사이트를 모두 파악하고, 각각의 웹사이트에 대한 연락처 정보를 찾아내고, 모든 웹사이트 소유자에게 연락하여 업데이트를 실행하도록 설득한다면 (전체 코드베이스를 리팩터링해야 할 수도 있음) 전체 프로세스에 최소 수년이 걸릴 것입니다.
이러한 웹사이트는 대부분 오래되어 관리되지 않을 가능성이 높습니다. 개발자가 아직 곁에 있다고 하더라도 여러분과 같이 숙련된 웹 개발자가 아닐 수도 있습니다. 웹 호환성 문제로 인해 8년 된 웹사이트를 모두 변경할 수는 없습니다.
TC39 절차는 어떻게 진행되나요?
TC39는 ECMAScript 표준을 통해 JavaScript 언어를 발전시키는 위원회입니다.
#SmooshGate로 인해 일부에서는 'TC39에서 flatten
의 이름을 smoosh
로 바꾸려 한다'고 생각했지만, 이는 외부에 잘 전달되지 않은 내부 농담이었습니다.
제안서 이름 변경과 같은 중요한 결정은 가볍게 내리지 않으며, 한 사람이 내리지도 않고, 단일 GitHub 댓글을 근거로 하룻밤 사이에 내리지도 않습니다.
TC39는 기능 제안서에 대해 명확한 스테이징 프로세스를 따릅니다.
ECMAScript 제안서와 이에 대한 주요 변경사항 (메서드 이름 변경 포함)은 TC39 회의에서 논의되며 공식화되기 전에 전체 위원회의 승인을 받아야 합니다. Array.prototype.flatten
의 경우 제안서가 이미 동의 단계를 여러 번 거쳐 3단계까지 진행되었으며, 이는 이 기능이 웹브라우저에 구현될 준비가 되었다는 것을 나타냅니다. 구현 중에 추가 사양 문제가 발생하는 것은 흔한 일입니다. 이 경우 가장 중요한 의견은 출시를 시도한 후에 접수되었습니다. 현재 상태에서 이 기능은 웹을 중단시킵니다. 이와 같이 예측하기 어려운 문제는 브라우저에서 기능이 제공되더라도 TC39 프로세스가 종료되지 않는 이유 중 하나입니다.
TC39는 합의에 따라 운영되므로 새로운 변경사항에 대해 위원회에서 동의해야 합니다. smoosh
가 진지한 제안이었다고 해도 위원회 위원이 compact
또는 chain
와 같은 더 일반적인 이름을 선호하여 반대할 가능성이 큽니다.
flatten
에서 smoosh
로 이름을 바꾸는 것은 농담이 아니더라도 TC39 회의에서 논의된 적이 없습니다. 따라서 이 주제에 대한 TC39의 공식적인 입장은 현재 알려지지 않았습니다. 다음 회의에서 합의에 도달할 때까지는 한 개인이 TC39 전체를 대신하여 발언할 수 없습니다.
TC39 회의에는 일반적으로 매우 다양한 배경을 가진 사람들이 참석합니다. 몇 년 동안 프로그래밍 언어 설계 경험이 있는 사람도 있고, 브라우저나 JavaScript 엔진에서 작업하는 사람도 있으며, JavaScript 개발자 커뮤니티를 대표하는 참석자도 점점 늘어나고 있습니다.
SmooshGate는 결국 어떻게 해결되었나요?
2018년 5월 TC39 회의에서 flatten
의 이름을 flat
로 변경하여 #SmooshGate가 공식적으로 해결되었습니다.
Array.prototype.flat
및 Array.prototype.flatMap
는 V8 v6.9 및 Chrome 69에서 제공되었습니다.