TestForge | Aidevops | 📊 Plogger ✍️ Blog 📚 Docs
plogger

AI DevOps Korea

AI 서비스 개발, 운영, 성능개선을 하나의 루프로 연결합니다

aidevops.kr에서 LLMOps, RAG, AI Agent, 관측성, 평가, 비용-성능 최적화를 실전 운영 관점으로 정리합니다.

Modern JavaScript ES2024 문법 실전 해설

· 수정 4월 21일
Modern JavaScript ES2024 문법 실전 해설 다이어그램
이 글에서 다루는 핵심 흐름, 아키텍처 구조, 주요 판단 포인트를 한눈에 이해할 수 있도록 정리한 그림입니다.
최신 JavaScript는 변하는 속도가 빨라서, 많은 팀이 새 문법을 일종의 체크리스트처럼 소비합니다. 그러면 보통 얕은 도입으로 끝납니다. 연산자 몇 개는 추가됐는데 스타일은 오히려 더 흔들리고, 어떤 기능이 실제로 코드 품질을 높였는지는 아무도 명확히 설명하지 못하게 됩니다.

그래서 ES2024 전후의 JavaScript를 읽는 더 좋은 방법은 “더 짧게 쓸 수 있다”가 아니라, 모호함을 줄이고, 반복 보일러플레이트를 안전하게 덜고, 비동기 의도를 더 분명히 만들 수 있는가를 기준으로 보는 것입니다.

핵심은 지원 여부보다 설계 효과다

대부분 팀은 새 문법이 런타임이나 번들러에서 지원되는지만 먼저 봅니다. 물론 필요하지만 그게 전부는 아닙니다.

더 중요한 질문은 아래입니다.

  • 이 문법이 읽는 사람의 모호함을 줄이는가
  • 반복되는 boilerplate를 안전하게 대체하는가
  • 실패 동작을 더 분명히 드러내는가
  • 팀이 일관되게 쓸 수 있어서 리뷰가 쉬워지는가

새 문법의 가치는 결국 코드베이스의 기본 규칙을 얼마나 더 선명하게 만들 수 있느냐에 달려 있습니다.

optional chaining과 nullish coalescing은 이미 기준을 바꿨다

이 두 기능은 이제 익숙하지만, 여전히 중요합니다. 방어적 코드를 쓰는 기본 방식을 바꿨기 때문입니다.

잘 맞는 경우:

  • 외부 입력 경계에서 nullability가 실제로 존재할 때
  • fallback이 falsy와 missing을 구분해야 할 때
  • 중첩 객체 접근 boilerplate를 줄여야 할 때

위험한 경우:

  • 원래 더 앞에서 강제해야 할 invariant를 뒤로 미룰 때
  • 데이터 구조 문제를 optional chaining으로 덮을 때

즉 이 연산자들은 경계 처리에는 탁월하지만, 도메인 모델링 부실을 감추는 수단이 되어서는 안 됩니다.

grouping 계열 기능은 intent를 코드로 드러낸다

배열과 객체를 그룹핑하는 기능은 단순히 줄 수를 줄여서 좋은 것이 아닙니다. “이 데이터를 어떤 기준으로 묶는다”는 의도를 코드에 직접 드러내기 때문에 좋습니다.

매번 임시 reducer를 손으로 쓰는 대신 아래 같은 질문이 코드에서 바로 읽힙니다.

  • 카테고리별로 묶기
  • 상태별 버킷으로 나누기
  • 키 기준으로 테이블 만들기

리포팅, 대시보드, UI 집계 로직이 많은 코드베이스일수록 이런 intent 노출은 꽤 큰 차이를 만듭니다.

Promise 유틸리티는 문법이 아니라 실패 정책이다

최신 Promise helper는 편의 기능처럼 보이지만, 실제로는 실패 정책을 드러내는 도구입니다.

  • Promise.all() 은 fail-fast 병렬 작업을 뜻하고
  • Promise.allSettled() 는 부분 성공을 허용하는 모델을 뜻하며
  • Promise.any() 는 first-success 전략을 표현합니다

이 차이를 의식하지 않고 쓰면 비동기 코드는 금방 읽기 어려워집니다. 현대 JavaScript의 좋은 사용법은 대체로 “무엇이 더 짧은가”가 아니라, 비동기 의미가 더 정직하게 드러나는가를 보는 쪽입니다.

편의 문법은 게으름을 숨기기도 한다

최신 문법의 위험은 편리함이 곧 모델링 게으름으로 이어질 수 있다는 점입니다.

대표적인 예시는:

  • 유효성 검증 대신 optional chaining만 늘어나는 경우
  • 너무 늦은 시점에 fallback default를 붙이는 경우
  • spread 문법이 많아져 객체 소유권이 흐려지는 경우
  • 보기엔 세련됐지만 실제로는 비용이 큰 helper 체인이 쌓이는 경우

그래서 새 문법은 correctness뿐 아니라, 경계를 더 강하게 만들었는지 아니면 더 얇게 보이게만 만들었는지까지 같이 봐야 합니다.

예시: 경계 처리가 분명한 최신 JavaScript

function normalizeUser(input) {
  const email = input?.email?.trim()?.toLowerCase();
  const locale = input?.preferences?.locale ?? "en-US";

  if (!email) {
    throw new Error("email is required");
  }

  return {
    id: input.id,
    email,
    locale,
    marketingOptIn: input.preferences?.marketingOptIn ?? false,
  };
}

이 예시가 괜찮은 이유는 새 문법을 썼기 때문이 아니라, 아래가 모두 보이기 때문입니다.

  • optional access는 외부 입력 경계에만 머무른다
  • 필수 invariant는 여전히 강제한다
  • fallback default가 의미 있게 선언된다

짧아졌지만, 더 중요한 것은 의도가 더 깨끗해졌다는 점입니다.

팀 규칙이 문법 자체보다 더 중요하다

최신 JavaScript가 비싸지는 순간은 개발자마다 다른 식으로 도입할 때입니다.

좋은 팀은 보통 이런 기준을 정합니다.

  • optional chaining을 어디까지 허용할지
  • ??|| 를 언제 구분할지
  • Promise helper별 실패 정책을 어떻게 읽을지
  • hand-written reducer를 언제 built-in 패턴으로 바꿀지

이 기준이 없으면 최신 문법은 업그레이드가 아니라 파편화를 만듭니다.

자주 보는 안티패턴

  • invariant 검증 대신 optional chaining만 쓰는 경우
  • 새 문법이면 무조건 더 읽기 좋다고 가정하는 경우
  • Promise coordination 스타일이 팀 내에서 제각각인 경우
  • spread와 destructuring이 지나쳐 데이터 흐름이 흐려지는 경우
  • 팀 규칙보다 문법 도입 속도가 더 빠른 경우

문제는 최신 JavaScript가 너무 고급이라서가 아니라, 아키텍처 의도 없이 도입되기 때문입니다.

리뷰 체크리스트

  • 이 기능이 짧게 만드는가, 아니면 의도를 더 분명히 만드는가
  • boilerplate를 줄이는가, 아니면 모델링 문제를 숨기는가
  • 비동기 실패 동작을 코드만 보고도 이해할 수 있는가
  • default와 null handling이 여전히 분명한가
  • 유사한 코드에서 팀이 같은 규칙으로 쓰고 있는가

마무리 판단

최신 JavaScript는 nullability, fallback, 비동기 의도를 더 정직하게 드러낼 때 가장 유용합니다. 반대로 새 문법으로 모호함을 압축만 하면 곧 유지보수 비용으로 돌아옵니다.

Continue Reading

다음으로 읽기 좋은 글

다음 탐색

이 주제를 시스템 관점으로 더 이어서 보기