언어의 환상: 지시어(Directives)의 진실

I
Inkyu Oh

Front-End2025.11.14

DEV Community 블로그 포스트 번역
2025년 11월 9일



서문 및 소개 — 이 글이 존재하는 이유

이 글은 반박이 아닙니다. 이는 Tanner Linsley의 훌륭한 글 "Directives and the Platform Boundary"에서 영감을 받은 반성입니다. 저는 이 글을 진심으로 즐겼고, 특히 소유권, 출처, 명시적 API의 가치에 대한 많은 점에 동의합니다. 제가 추가하고 싶었던 것은 디렉티브 기반 도구를 구축하고 JavaScript에 'use client'나 'use server'가 생기기 훨씬 전의 프로그래밍 역사에서 매우 유사한 장을 경험한 사람으로서의 약간 다른 관점입니다.
지난 1년 동안, 수많은 개발자들이 JavaScript의 디렉티브를 마치 실제 언어 기능인 것처럼 다루는 것을 보았습니다. 이는 JavaScript 사양이나 런타임 환경에 내장된 것처럼 보입니다. 파일 상단의 문자열이 코드의 동작을 마법처럼 바꾸는 것은 권위적으로 보입니다.
React Server Components와 Next.js와 같은 프레임워크의 진화를 따라오지 않았다면: 현대 React 앱은 이제 와 와 같은 파일 수준의 디렉티브를 사용하여 코드가 실행되는 위치를 제어합니다. 이들은 파일 상단의 단순한 문자열 리터럴처럼 보이지만, 컴포넌트가 서버나 클라이언트에서 실행되는지를 결정하여 번들링, 렌더링 및 데이터 흐름을 형성합니다. 여기서 혼란이 시작됩니다.
하지만 여기에는 긴장이 있습니다:
디렉티브는 언어 기능처럼 보입니다. 디렉티브는 언어 기능처럼 느껴집니다. 그러나 디렉티브는 언어 기능이 아닙니다.
디렉티브는 번들러, 컴파일러 및 빌드 파이프라인에서 소비되는 도구 수준의 신호입니다.
이 오해는 새로운 현상이 아닙니다. 우리는 이미 이곳에 있었습니다.

개인적인 회상

젊은 개발자로서 C++ 코드베이스에서 처음 를 보았을 때, 저는 이렇게 생각했습니다: “와, 언어에 이걸 위한 키워드가 있구나! 왜 JavaScript에는 없지?”
하지만... 그것은 언어 키워드가 아니었습니다. 그것은 컴파일러 지시였습니다. 언어 자체가 아닌 전처리기에 대한 힌트였습니다.
'use strict'가 처음에는 "JavaScript 문법"이 아니었던 것처럼, 'use client'도 오늘날 "JavaScript 문법"이 아닙니다.
이 글은 그 평행선을 탐구합니다. C/C++ 전처리기 시대를 이해하는 것이 현대 JS 디렉티브를 이해하는 데 놀랍도록 강력한 방법이기 때문입니다. 왜 사람들이 혼란스러워하는지, 그리고 과거로부터 무엇을 배워 더 잘 가르칠 수 있는지를 이해하는 데 도움이 됩니다.

왜 디렉티브가 언어 기능처럼 느껴질까요?

다음 코드를 초보자에게 보여주고:
'use client';

export function Button() {
return <button>Click</button>;
}
그리고 그들에게 'use client'가 무엇인지 물어보면, 대부분은 자신 있게 대답할 것입니다:
“JavaScript의 일부입니다.”
이는 무지가 아닙니다. 이는 패턴 인식입니다.
프로그래밍 생애 전반에 걸쳐, 파일 수준의 "마법 문장"은 거의 항상 언어 의미론이었지, 도구 의미론이 아니었습니다:
  • "use strict"
  • "use asm"
이들은 구문처럼 보입니다. 파일 상단에 위치합니다. 행동을 바꿉니다.
그래서 뇌는 당연히 그것들을 언어로 분류합니다.
TanStack 글은 다음과 같이 말할 때 이 부분을 잘 포착합니다:
“파일 상단의 디렉티브는 권위적으로 보입니다. 이는 언어 수준의 진실처럼 보이며, 프레임워크 힌트가 아닙니다.”
이것이 혼란의 핵심입니다.

숨겨진 메커니즘이 상황을 악화시킵니다

디렉티브는 경계를 흐리게 합니다. 왜냐하면 그에 반응하는 코드는:
  • 보이지 않습니다
  • 비지역적입니다
  • 임포트를 통해 추적할 수 없습니다
다음과 같이 작성하면:
import { client } from 'somewhere';
→ 임포트를 따라갈 수 있습니다. 누가 소유하고 있는지 알 수 있습니다. 버전을 지정할 수 있습니다. 검색할 문서를 알 수 있습니다.
하지만 디렉티브는:
  • 임포트가 없습니다
  • 네임스페이스가 없습니다
  • 소유권 참조가 없습니다
  • 조사할 호출 사이트가 없습니다
행동은 "어디서도 오지 않습니다".
이것이 바로 그들이 언어처럼 느껴지는 이유입니다.

빌드 도구를 추가하면 환상이 굳어집니다

JavaScript 키워드와 달리, 디렉티브는 스스로 아무것도 하지 않습니다.
런타임 엔진은 를 잘못 입력해도 오류를 발생시키지 않습니다. 번들러나 변환 플러그인이 그것을 어떻게 처리할지 결정합니다. 일부는 무시하고, 일부는 오류를 발생시키고, 일부는 문자열 리터럴로 처리합니다.
이로 인해 두 번째 주요 혼란이 발생합니다:
“번들러가 작동하려면 플랫폼의 일부가 아니라 언어의 일부가 아닌가요?”
개발자의 관점에서, 명시적 임포트 없이 코드가 동작을 변경하면, 마음은 기본적으로:
✅ 언어 기능 ❌ 라이브러리 기능
그리고 그것이 함정입니다.
오늘날 우리가 "플랫폼"이라고 부르는 것은 실제로 도구의 스택입니다 — 일관된 언어 표면이 아닙니다. C/C++ 시대와 정확히 같습니다.

C/C++ 매크로와 전처리기: 과거를 돌아보다

현대 JavaScript 빌드 파이프라인이 있기 훨씬 전, C와 C++ 세계는 매우 유사한 혼란을 겪었습니다. 그리고 그것은 컴파일 이전에 위치한 레이어, 즉 전처리기에서 시작되었습니다.
오늘날의 디렉티브를 이해하려면 그 시대의 세 가지 기둥을 간단히 되짚어볼 필요가 있습니다 — 왜냐하면 그것들은 오늘날 우리가 보는 것과 놀랍도록 잘 맞아떨어지기 때문입니다.

C 전처리기는 언어가 아니었지만 언어처럼 느껴졌습니다

다음과 같은 코드를 고려해보세요:
#define PI 3.14
처음 이 코드를 접한 많은 초보자들은 이렇게 가정합니다: “오, C에는 상수를 정의하기 위한 특별한 언어 키워드가 있구나.”
하지만... 은 C 언어 문법의 일부가 아닙니다. 이는 컴파일러 이전에 실행되는 별도의 도구에 대한 지시입니다.
이는 텍스트 대체를 수행합니다 — 타입 검사, 구문 분석, 의미 검증이 아닙니다.
하지만, 파일 내에 존재하고 "코드"처럼 보였기 때문에, 여러 세대의 개발자들은 이를 언어로 인식했습니다.
익숙하게 들리나요?
JS의 디렉티브도 같은 방식으로 작동합니다:
'use server';
JavaScript 엔진은 그것이 무엇을 의미하는지 모릅니다. 번들러가 실행 전에 무엇을 재작성할지 결정합니다.
둘 다 언어 이전 단계로, 언어처럼 가장합니다.

프래그마: 원래의 "프레임워크 디렉티브"

매크로가 오늘날의 코드 생성 유틸리티와 같다면, 는 현대 디렉티브의 가장 가까운 조상입니다:
#pragma once
이 줄은 C++ 언어 사양의 일부가 아닙니다. 이는 컴파일러 특정 "힌트" — 빌드 시스템이 이 파일을 처리하는 방식을 변경하는 지시입니다.
  • 임포트 없음
  • 네임스페이스나 출처 없음
  • 소유권 표시 없음
다른 컴파일러는 다른 프래그마를 지원했습니다. 일부는 무시했고, 일부는 경고를 발생시켰으며, 일부는 다르게 동작했습니다.
"컴파일러"를 "번들러"로 바꾸면 2025년이 됩니다.
예를 들어:
  • Next.js는 에 반응합니다
  • Vite는 이를 무시할 수 있습니다
  • 커스텀 RSC 번들러는 다르게 해석할 수 있습니다
이는 30년 전의 동일한 분열 패턴입니다.

인클루드 가드: 최초의 "보이지 않는 빌드 타임 동작"

#pragma once가 일반화되기 전에는 C/C++에서 이중 포함을 방지하기 위해 인클루드 가드를 사용했습니다.
#ifndef MY_HEADER_H
#define MY_HEADER_H

// header contents

#endif
이 패턴은:
  • 프로그램 동작을 변경했습니다
  • 도구에만 존재했습니다
  • 런타임 의미가 없었습니다
  • 빌드 모델에 대한 지식이 필요했습니다, 단순히 언어만이 아닙니다
이것은 중요합니다:
C/C++는 개발자들에게 "파일에 작성한 코드"와 "언어 자체"가 동일하지 않다는 것을 배우도록 강요했습니다.
이는 고통스럽지만 변혁적인 교훈이었습니다.
우리는 이제 JavaScript에서 동일한 교육적 순간에 있습니다.

다단계 컴파일: 익숙한 파이프라인

C/C++는 뚜렷한 레이어를 가지고 있었습니다:
Preprocessor → Compiler → Linker → Executable
현대 JS 도구는 동일한 분리를 가지고 있습니다, 단지 더 멋진 이름을 가지고 있을 뿐입니다:
Directive Scanner / Loader → AST Transforms → Bundler → Output Chunks
그리고 초보자들이 "C++ 언어"를 전처리기 특이성 때문에 비난했던 것처럼, 오늘날 개발자들은 다음을 비난합니다:
  • "JavaScript"
  • "React"
  • "플랫폼"
...사실은 빌드 도구에서 기인한 동작에 대해.
역사는 거의 줄 단위로 반복되고 있습니다.

전처리기 시대의 렌즈를 통해 본 현대 디렉티브

C/C++의 유사점을 한 번 보면, 현대 JavaScript 디렉티브가 갑자기 훨씬 더 이해가 됩니다. 이들은 JavaScript 구문의 진화가 아니라 — 컴파일러 힌트의 진화입니다.
명시적으로 매핑을 해봅시다:
전처리기 시대 개념
현대 JS 등가물
#pragma,
'use client', 'use server'
#define 매크로
코드 변환 / 자동 생성 래퍼
#include 가드
모듈 경계 / 하이드레이션 경계
컴파일러 특정 동작
번들러 특정 동작
다단계 빌드
로더 → 변환 → 번들 파이프라인
90년대와 마찬가지로, 표면은 기만적으로 단순해 보입니다 — 하지만 실제 작업은 아래에서 일어납니다.

디렉티브는 실행되지 않습니다 — 도구에 지시합니다

디렉티브의 주요 속성은 다음과 같습니다:
그들은 스스로 아무것도 하지 않습니다 — 그들은 단지 다른 것이 어떻게 동작하는지를 변경합니다.
디렉티브 기반 파이프라인에서 일반적으로 발생하는 일을 간단히 설명하겠습니다 (단순화되었지만 충분히 정확합니다):
파일 읽기 → 디렉티브 확인 → 환경 / 경계 결정 →
변환 실행 → 클라이언트/서버 번들 생성 → 출력
이를 C 파이프라인과 비교해 봅시다:
파일 읽기 → 전처리기가 매크로 확장 + 프래그마 처리 →
컴파일 → 링크 → 출력
이들은 구조적으로 동일한 개념입니다, 단지 다른 언어와 시대에 적용된 것입니다.

언어 기능의 환상이 지속되는 이유

세 가지 심리적 요인이 혼란에 기여합니다:
  1. 구문처럼 보입니다 와 는 예약어처럼 느껴집니다.
  1. 파일 상단에 위치합니다 전체 파일을 형성하는 것은 종종 언어로 가정됩니다.
  1. 전역적이고 암시적으로 작동합니다 인스턴스화나 임포트가 필요하지 않습니다.
즉, 디렉티브는 언어적 환상을 성공적으로 이용합니다. 그들은 프로그래밍 언어처럼 행동합니다 — 하지만 그렇지 않습니다.

하지만 현대 디렉티브는 C 프래그마보다 더 나아갑니다

여기서 더 흥미로운 점이 있습니다:
C 프래그마는 컴파일 동작에만 영향을 미쳤습니다. 현대 디렉티브는 종종 실행 모델, 코드 배치, 번들링, 런타임 경계에 영향을 미칩니다.
예를 들어, 는 다음을 수행할 수 있습니다:
  • 코드를 서버 전용 청크로 이동
  • 호출을 RPC 스텁으로 대체
  • 직렬화 래퍼 추가
  • 데이터 흐름 제약 조건 적용
이는 이미 C 전처리기가 했던 것 이상입니다.
이는 매크로 시스템 + 컴파일러 패스에 더 가깝습니다.
이것이 구분을 이해하는 것이 중요한 이유입니다:
무언가가 런타임 실행과 코드 배치에 영향을 미친다면, 우리는 그것을 "파일 상단의 단순한 문자열"로 취급해서는 안 됩니다.
그리고 아이러니하게도, 대부분의 오해는 그것이 정확히 그렇게 보이기 때문에 발생합니다.

빌드 도구는 디렉티브의 실제 해석자입니다

다른 C 컴파일러가 프래그마를 다르게 처리했던 것처럼, 현대 JS 도구도 다양합니다:
  • Next.js는 를 한 가지 방식으로 해석합니다
  • Vite + RSC 구현은 또 다른 방식으로
  • 서드파티 번들러는 세 번째 방식으로
만약 내일 또 다른 프레임워크가 다음을 도입한다면:
'use streaming-server';
JavaScript 엔진은 신경 쓰지 않을 것입니다. 도구가 그것이 무엇을 의미하는지 결정할 것입니다.
그리고 그것이 개발자들이 해야 할 정신적 전환입니다:
디렉티브 ≠ 언어 디렉티브 = 빌드 지시
그들은 사용자 영역에 존재합니다 — 사양에 있지 않습니다.
잠시 멈추고 생각해볼 가치가 있습니다. C와 C++의 유사점은 디렉티브의 형태를 이해하는 데 유용하지만, 실제로 본 적이 없다면 여전히 추상적으로 느껴질 수 있습니다. 이 이론을 더 명확하게 하기 위해, 오늘날의 생태계에서 구체적인 예를 살펴보겠습니다 — 이론을 조금 더 구체적으로 만들고, 이러한 컴파일러 힌트가 실제 현대 코드에서 어떻게 나타나는지를 보여줍니다.
📦 인라인 서버 함수가 디렉티브의 필요성을 드러낼 때
저는 한 번 서버 동작을 런타임에 맡길 수 없는 이유를 완벽하게 드러낸 사례를 만난 적이 있습니다.
로컬 스코프에서 변수를 캡처하는 Server Component 내부에 정의된 인라인 서버 함수를 고려해보세요:
export default function Dashboard() {
const rate = 0.27;

async function save(value) {
'use server';
return value * rate; // ← 컴포넌트 스코프에서 "rate"를 캡처합니다
}

return <button onClick={() => save(10)}>Save</button>;
}
처음에는 이것이 일반적인 함수 호출처럼 느껴집니다. 하지만 이것이 작동하려면, 번들러는 미묘하고 비협상적인 작업을 수행해야 합니다:
  • save가 서버 함수임을 감지하고,
  • 서버 전용 모듈로 끌어올리고,
  • AST 수준의 클로저 분석을 수행하여 rate를 캡처하고,
  • 클라이언트에 안정적이고 직접 호출 가능한 참조를 생성해야 합니다 — 런타임에 구성된 래퍼가 아닙니다.
런타임 헬퍼는 이를 해결할 수 없습니다. 코드가 실행될 때쯤이면 클로저는 사라지고 의도는 이미 잃어버렸습니다. 함수는 프로그램이 존재하기 전에 변환되어야 하며, 클라이언트가 이를 직접 함수로 호출할 수 있도록 해야 합니다, 우리가 너무 늦게 조합한 프록시가 아니라.
이것이 디렉티브가 이 공간에 잘 맞는 이유입니다: 그들은 정의 순간에 이 함수가 진정으로 무엇인지 빌드 도구에 알려주어, 그에 따라 형성할 시간을 줍니다.
일부 결정은 코드가 아직 짜여질 때 일어나야 합니다 — 이미 살아있는 후가 아니라.

교육적 격차 — 그리고 역사로부터 배울 수 있는 것

오늘날 디렉티브에 대한 혼란을 한 발 물러서서 보면, 놀라운 점을 발견할 수 있습니다:
문제는 더 이상 기술적이지 않습니다 — 교육적입니다.
우리는 역사적 패턴을 반복했습니다:
  • 도구 수준의 구조가 언어처럼 보입니다
  • 개발자들은 그것이 언어라고 가정합니다
  • 정신 모델이 잘못됩니다
  • 혼란이 문서가 수정할 수 있는 것보다 빠르게 퍼집니다
이것은 C 전처리기에서 발생했습니다. JavaScript 디렉티브에서도 다시 발생하고 있습니다.

레이어링을 가르쳐야 합니다 — 단순히 기능만이 아닙니다

우리가 'use server'을 가르친다면:
“이것은 당신의 함수를 서버에서 실행하게 만듭니다.”
...우리는 이미 졌습니다.
왜냐하면 그 문장은 4개의 별도 레이어를 숨기고 있기 때문입니다:
레이어
책임
구문
문자열 리터럴 작성
로더
디렉티브 감지
빌드 도구
코드 변환 / 분할
런타임
경계 강제
개발자들이 어떤 레이어가 무엇을 책임지는지 이해하지 못하면, 그들은 번들러 문제에 대해 "JavaScript"를 비난할 것입니다 — 마치 C 개발자들이 전처리기 버그에 대해 "언어"를 비난했던 것처럼.

C/C++ 커뮤니티가 결국 배운 것

시간이 지나면서, C/C++ 교육은 진화했습니다:
초기 교육: “과 를 사용하는 방법입니다.”
성숙한 교육: “전처리기가 무엇인지, 그리고 왜 언어와 분리되어 있는지입니다.”
그 변화 이후, 혼란은 극적으로 줄어들었습니다. 오늘날 진지한 C++ 과정은 매크로를 가르치기 전에 컴파일 단계의 정신 모델을 먼저 가르치지 않습니다.
우리는 JS 디렉티브에 대해 동일한 변화를 필요로 합니다.

디렉티브는 나쁘지 않습니다 — 이해하면 강력합니다

이 글은 디렉티브에 반대하는 주장이 아닙니다. 그들은 목적을 제공합니다:
  • 의도를 선언적으로 전달
  • 보일러플레이트 감소
  • 도구가 코드를 최적화하고 분리하도록 도움
  • 복잡한 동작에 대한 간단한 스위치를 개발자에게 제공
사실, 가장 인체공학적인 서버/서버리스 기능 중 일부는 그들 없이는 훨씬 더 번거로울 것입니다.
하지만 인체공학의 대가는 명확성 부채입니다.
마법이 어디서 오는지 가르치지 않으면, 개발자들은 진실의 출처를 잘못 속이고 — 디버깅이 무너집니다.

내일부터 가르칠 수 있는 간단한 정신 모델

저는 디렉티브를 다음 한 문장으로 설명하는 것을 좋아합니다:
“디렉티브는 JavaScript가 아닌 빌드 도구를 위한 메모입니다.”
그 한 줄만으로도 오해의 70%가 해결됩니다.
하나의 비유를 추가하세요:
`#pragma once`가 C++ 구문이 아니었다면, “use client”도 JavaScript 구문이 아닙니다.”
그리고 갑자기, 사람들은 이해합니다.
이것은 더 많은 문서가 필요하지 않습니다 — 더 나은 프레이밍이 필요합니다.

명확성을 향한 실질적인 단계: 디렉티브를 위한 TypeScript 플러그인

마무리하기 전에, 실제 코드베이스에서 이 혼란을 줄이기 위해 제가 취한 또 다른 구체적인 단계를 공유하고 싶습니다. 문제의 일부가 디렉티브가 언어처럼 보이지만 공식적인 구조가 부족하기 때문이라면, 그들에게 타입 수준의 의미를 부여하는 것이 격차를 줄이는 한 방법입니다.
저는 디렉티브에 타입 안전성과 IntelliSense 인식을 제공하는 작은 TypeScript 플러그인인 를 만들었습니다. 이를 통해 팀은:
  • 자신만의 디렉티브 어휘를 정의하고,
  • 컴파일 타임에 이를 검증하고,
  • 에디터 힌트와 자동 완성을 받고,
  • 알아차리기 힘든 'use clinet' 같은 오타를 방지합니다.
목표는 디렉티브를 "표준화"하는 것이 아니라, 그들의 의도를 명시적이고 개발자와 도구 모두에게 명확하게 만드는 것입니다 — 번들러가 먼저 해석할 필요 없이.
여기에서 시도해볼 수 있습니다:
이는 의도적으로 가볍습니다 — 정신 모델이 더 빨리 클릭하도록 돕고, TypeScript 프로젝트 내에서 디렉티브에 더 공식적인 형태를 제공하기 위한 작은 레이어입니다.
TypeScript 플러그인이 디렉티브를 "강제"할 수 있다는 일반적인 가정이 있습니다 — 플러그인이 이를 알고 있다면, 시스템이 기본적으로 안전해진다는 것입니다. 하지만 TS 플러그인은 언어 서비스에 존재합니다. 이는 인식, 경고, 지침을 제공할 수 있지만 — 여전히 코드가 실제로 변환되는 곳에서 실행되지 않습니다. 이는 컴파일이나 번들링에 참여하지 않습니다.
플러그인은 디렉티브 사용을 식별하는 데 도움을 줄 수 있지만 그들의 의미를 강제할 수는 없습니다. 이를 위해서는 컴파일러가 의도의 신호를 필요로 합니다 — 타입 시스템이 이해할 수 있는 것.
이를 가능하게 하기 위해, 저는 플러그인에서 전역 타입을 노출합니다. 작성자는 를 사용하여 에디터가 아닌 TypeScript 컴파일러에 주어진 문자열이 디렉티브로 의도되었음을 알릴 수 있습니다:
'use server' satisfies Directive;
이는 동작을 변경하거나 변환을 트리거하지 않습니다. 그것이 하는 일은 훨씬 더 간단하고 근본적입니다:
타입 시스템에 말합니다: “이것을 디렉티브로 취급하고, 그렇게 검증하세요.”
이는 의도를 컴파일러와 일치시킵니다, 런타임과는 아니고, IDE와도 아닙니다.
세계의 실제 분리는 — 컴포넌트에서 인라인 서버 함수를 끌어올리고, 캡처된 스코프를 분석하고, 직접 호출 가능한 경계를 생성하는 것은 — 여전히 전적으로 빌드에 속합니다. 타입 시스템은 의도를 인정할 수 있지만, 번들러가 그것에 대해 행동해야 합니다.
하나의 실질적인 주의 사항: 오늘날 일부 도구 — Next.js를 포함하여 — 디렉티브가 단순 문자열 리터럴로 나타나기를 기대합니다. 로 작성되면, 디렉티브는 더 이상 프레임워크가 스캔하는 정확한 형태로 존재하지 않기 때문에 감지되지 않을 수 있습니다. 이것이 변경될 때까지, 이 패턴은 Next.js에 의해 인식되지 않을 것입니다.
언급할 가치가 있는 또 다른 미묘함이 있습니다. 이 타입 수준의 의도는 타입 체커가 실제로 실행되는 경우에만 중요합니다. 많은 현대 툴체인 — esbuild, SWC, Oxc, Bun, 심지어 대부분의 Deno 및 Vite 설정 —은 전혀 타입 검사를 하지 않습니다. 그들은 단순히 타입을 제거하고 계속 진행합니다. 이러한 환경에서는 + 표현이 컴파일러가 들을 기회를 갖지 못한 조용한 메모가 됩니다.

마무리 반성

Tanner의 글은 가치 있는 대화를 제기합니다 — 나쁜 습관이 굳어지기 전에 일찍 할 가치가 있는 대화입니다. 저는 디렉티브를 제거하는 것이 목표가 되어야 한다고 믿지 않습니다; 그들은 분명히 실제 문제를 해결합니다. 하지만 우리는 역사를 배울 수 있고, C/C++ 개발자 세대가 배워야 했던 혼란을 피할 수 있습니다.
우리는 이미 이곳에 있었습니다. 우리는 이 이야기가 어떻게 진행되는지 알고 있습니다. 이번에는 중간의 혼란의 10년을 건너뛸 수 있습니다.
레이어를 가르치세요. 출처를 가르치세요. 정신 모델을 가르치세요.
그리고 디렉티브는 "비밀 언어 기능"처럼 느껴지지 않을 것입니다 — 그들이 실제로 의도된 강력한 컴파일러 힌트처럼 느껴질 것입니다.
0
98

댓글

?

아직 댓글이 없습니다.

첫 번째 댓글을 작성해보세요!