[번역] 자바스크립트 모듈에서 default export는 끔찍합니다

eunbinn·2022년 9월 12일
37

FrontEnd 번역

목록 보기
12/31
post-thumbnail

출처: https://www.lloydatkinson.net/posts/2022/default-exports-in-javascript-modules-are-terrible/

자바스크립트 모듈은 named export와 default export, 두 종류의 export가 있습니다. 이 글에서는 왜 default export가 좋지 않고 더 안좋은 개발자 경험으로 이어질 수 있는지 설명하고자 합니다. 아래와 같은 named export와 default export를 모두 가지고 있는 모듈을 생각해봅시다.

export const add = (a, b) => a + b;

export default subtract = (a, b) => a - b;

이 함수들이 어떻게 import되고 사용될지 고려하기 전에, 개발자 경험에도 영향을 미칠 수 있는 또 다른 문제를 먼저 지적하고 싶습니다. export된 함수는 모듈의 기본값입니다. 이에 따른 영향을 고려하는 것은 필수적입니다. 왜 subtract는 default이지만 add는 named export인가요? 아마 이런 인위적인 예시는 문제를 제대로 부각시키지 못할 것 같네요.

개발자에게 익숙하지 않은 더 복잡한 모듈을 사용한다고 가정해 봅시다. 어떤 export가 default인지 모를 수 있습니다. 어쩌면 default export가 있는지 조차 모를 수도 있죠. 따라서 개발자는 문서를 읽거나(문서가 있다면 다행이죠) 라이브러리 소스를 읽는 데 더 많은 시간을 할애해야 합니다. named export만 있었다면 검색은 간단해집니다.

안타깝게도 문서화가 제대로 되지 않는 것은 업계에서 흔한 일입니다. 특히 자바스크립트 문서는 평균적으로 더 빈약해보이며, 이는 자바스크립트의 진입장벽이 낮아 경험이 부족한 개발자들이 무수히 많은 쓸모없는 패키지를 NPM에 게시하기 때문일 수 있습니다. 저는 자바스크립트가 동적이고 느슨하게 타이핑된 언어라는 사실이 이 문제의 원인이라고 생각하지 않습니다. 파이썬은 이러한 문서화에 대한 문제를 가지고 있지 않기 때문이죠.

IDE를 사용하면 모듈의 export된 멤버를 즉시 확인할 수 있습니다. 이 목록에서 빠진 것은 무엇일까요? 맞습니다. default export입니다. default export는 named export가 아니기 때문에 IDE는 default export를 이 목록에 의미 있게 표시할 수 없어 표시하지 않습니다.

이는 Node에서 모듈 포맷을 위해 등장했지만 아주 형편없는 개발자 경험을 선사하며 실패했던 시도인 CommonJS를 떠오르게합니다. 코드에서 CommonJS를 사용하고 있는지 쉽게 알 수 있는 방법은 requiremodule.exports가 있는지 확인하는 것입니다. default export와 마찬가지로 IDE 지원은 거의 없거나 전혀 없습니다.

IDE 도구와 관련한 문제를 확인했으니 (그리고 자동 완성 측면에서 이름이 누락되는 문제를 발견했으니) 이제 import하는 방법을 파악하고 default export의 사용을 확장해보겠습니다.

  • export한 멤버는 어떤 이름으로든 import 할 수 있습니다. 맞습니다. subtraction 함수는 multiply를 포함한 어떠한 이름으로든 import 할 수 있습니다. 이는 곧 혼란을 야기할 수 있고 코드가 점점 더 확장될수록 더 큰 문제가 될 수 있습니다.
import multiply from "./math.js";
const result = multiply(2, 2); // 결과는 0이 됩니다.
  • default export는 어떤 이름으로든 export 할 수 있으므로 여러 개발자는 default import를 위해 각각 다른 이름과 명명 스키마를 생각할 것입니다. 일관성이 없습니다. 저는 최근에 이 문제에 직접 직면했습니다. 게시물에 사용하는 마크다운 파일을 처리하기 위해 rehype 모듈을 사용했습니다. 두 줄의 코드는 각각의 설명서에서 따왔는데 그 중 하나에만 rehype가 앞에 붙어있는 것을 볼 수 있습니다. 어떤 컨벤션을 따를지 결정하는 것은 저에게 달려있습니다.
import rehypeExternalLinks from "rehype-external-links";
import addClasses from "rehype-add-classes";
  • default export는 리팩토링도 어렵게 만듭니다. 모듈에서 named export한 멤버의 이름을 바꾸면 모든 사용처에서도 이름이 변경됩니다(이 리팩토링을 적용할 수 있는 IDE를 사용 중인 경우에). 하지만 default export를 사용하는 경우에는 불가능합니다.

"만약 다른 모듈에서 명명된 두 named export의 이름이 같은 경우 어떻게 해야하나요?"라고 생각할 수 있습니다. 다행히 이 문제는 import aliasing으로 쉽게 해결할 수 있습니다.

import { Article } from "./types";
import { Article as ArticleComponent } from "my-design-system";

물론 별칭의 이름은 생각해야합니다. 하지만 default export를 위한 완전히 새로운 이름을 생각하는 것보다는 훨씬 더 좋은 상황입니다. 또한 이는 여전히 리팩토링하기 쉽습니다. ArticleComponent는 디자인 시스템 컴포넌트 라이브러리에서 가져온 컴포넌트로 작업할 경우에 중복된 이름입니다. 고전 속담에 "이름을 짓는 것은 어렵다"라는 말이 있습니다. 그러나 import 할 때마다 이름을 고민하는 것 보다 하나의 파일 안의 스코프에서 일회성으로 이름을 고민하는 것이 훨씬 편합니다.

"함수나 컴포넌트를 default export 하기를 요구하는 프레임워크나 도구를 쓰고 있네"라는 생각할 수도 있을 것 같습니다. 이 또한 "index.js 패턴"을 사용해서 해결할 수 있습니다. 이는 디렉토리 최상위에 index.jsindex.ts 파일을 만들고 여기에서 default export를 하는 것입니다. 이 패턴을 다루는 좋은 글은 여기에서 확인하실 수 있습니다.

만약 프로젝트에서 혹은 NPM에 모듈을 작성하고 있다면 제발 default export 사용을 멈춰주세요.

3개의 댓글

comment-user-thumbnail
2022년 9월 19일

잘 읽었습니다.

답글 달기
comment-user-thumbnail
2023년 2월 1일

좋은 글 감사합니다!

답글 달기
comment-user-thumbnail
2023년 7월 28일

Like a rare and exquisite gem hidden within the Earth's crust, your article has emerged to dazzle my senses and ignite a fire of gratitude within me. I am spellbound by the depths Pokemon Fusion Generator of insight you have shared and forever indebted to your literary alchemy.

답글 달기