520만 명의 언어와 하나의 경고: 소프트웨어의 경계는 누가 지키는가

min dulle

Hatched by min dulle

Aug 27, 2026

7 min read

86%

0

가장 큰 생태계는 왜 가장 작은 파일에서 흔들리는가

개발자 520만 명이 사용하는 언어가 있다고 하자. 그중 33퍼센트가 한 국가에 몰려 있다. 이 정도 규모라면 우리는 그 언어가 매우 안정적이고, 예측 가능하며, 웬만한 변화에도 끄떡없을 것이라고 생각하기 쉽다. 하지만 실제 소프트웨어의 취약한 지점은 거대한 생태계의 중심이 아니라, 컴파일러가 모르는 작은 파일 하나일 때가 많다.

예를 들어 애플리케이션 코드가 CSS 파일을 불러온다고 해 보자. 번들러는 CSS를 이해한다. 실행 환경도 CSS를 처리한다. 그러나 TypeScript 컴파일러는 기본적으로 이 import를 오류로 판단할 수 있다. 시스템 전체에서는 아무 문제도 없는데, 하나의 도구가 다른 도구의 세계를 인정하지 않는 순간 개발 흐름이 멈춘다.

여기에는 오늘날 소프트웨어 개발의 중요한 긴장이 드러난다. 규모가 커질수록 더 많은 것을 표준화해야 하지만, 실제 시스템은 표준 밖의 수많은 현실과 연결되어야 한다. Java와 같은 거대한 생태계의 힘은 안정된 규칙, 오랜 경험, 폭넓은 인력에서 나온다. 반면 현대 프런트엔드 도구의 힘은 파일 형식과 실행 방식을 유연하게 조합하는 능력에서 나온다.

이 둘은 서로 반대처럼 보인다. 하나는 질서와 예측 가능성을 대표하고, 다른 하나는 확장성과 조합 가능성을 대표한다. 그러나 더 깊이 보면 둘은 같은 문제를 다룬다. 서로 다른 도구와 사람들이 공유하는 경계를 어떻게 설계할 것인가라는 문제다.

좋은 개발 도구는 모든 현실을 직접 이해하려 하지 않는다. 대신 현실을 안전하게 연결할 수 있는 경계를 제공한다.

컴파일러의 오류와 조직의 마찰은 같은 구조를 가진다

allowArbitraryExtensions 같은 설정은 단순히 오류 메시지를 숨기는 기능이 아니다. 그것은 컴파일러가 자신의 지식 바깥에 있는 대상을 만났을 때 어떤 태도를 취할지 결정하는 정책이다. CSS 로더가 해당 파일을 책임지고 있다면, TypeScript가 그 파일의 모든 의미를 직접 검증할 필요는 없다. 대신 필요한 선언 파일을 통해 최소한의 계약을 확인할 수 있다.

이 구조를 다른 영역에 옮겨 보자. 대규모 기업에서 백엔드 팀은 Java로 서비스를 만들고, 프런트엔드 팀은 TypeScript를 사용하며, 배포 팀은 별도의 구성 파일과 자동화 도구를 운영한다. 각 도구는 자신의 영역에서는 정확해야 한다. 그러나 서비스 하나가 완성되려면 이 영역들이 서로의 산출물을 받아들여야 한다.

문제는 흔히 도구의 부족이 아니라 경계에 대한 잘못된 기대에서 발생한다. Java 컴파일러가 데이터베이스의 모든 운영 상황을 알 수는 없다. TypeScript 컴파일러가 번들러의 모든 변환 규칙을 알 수도 없다. 배포 시스템이 애플리케이션 내부의 모든 비즈니스 의미를 이해할 수도 없다. 그럼에도 우리는 각 도구가 전체 시스템의 진실을 알고 있어야 한다고 기대한다.

그 결과 두 가지 실패가 나타난다.

첫째, 도구가 너무 엄격해진다. 자신의 영역 밖에 있는 대상을 오류로 거부한다. 실제 런타임에서는 정상적으로 처리되는 CSS import가 컴파일 단계에서 막히는 것이 그 사례다. 조직에서도 비슷한 일이 생긴다. 한 팀의 승인 절차가 다른 팀의 작업을 차단하고, 규칙을 지키는 것이 제품을 만드는 것보다 중요해진다.

둘째, 도구가 너무 느슨해진다. 모든 것을 허용하지만 아무런 계약도 요구하지 않는다. 그러면 오류는 사라지는 대신 더 늦게 발견된다. 빌드가 성공했는데 배포 후 파일을 찾지 못하거나, 팀 간 데이터 형식이 달라 운영 장애가 발생한다.

따라서 핵심은 엄격함과 자유 중 하나를 선택하는 데 있지 않다. 무엇을 직접 검증하고, 무엇을 외부 계약에 위임할지 구분하는 것이 핵심이다.

규모는 표준의 문제가 아니라 계약의 문제다

520만 명의 개발자가 같은 언어를 사용한다는 사실은 단순한 인기 지표가 아니다. 그것은 거대한 계약 네트워크가 존재한다는 뜻이다. 수많은 교육 과정, 채용 기준, 라이브러리, 운영 경험, 디버깅 방법이 서로 연결되어 있다는 의미다. 미국 개발자의 33퍼센트가 그 생태계에 포함되어 있다는 사실도 이 네트워크가 특정 지역의 기업과 시장에 깊이 뿌리내렸음을 보여 준다.

하지만 규모가 커진다고 자동으로 일관성이 생기는 것은 아니다. 오히려 규모는 경계의 수를 늘린다. 한 사람이 모든 맥락을 이해할 수 없기 때문이다. 작은 프로젝트에서는 개발자가 코드, 빌드 설정, 배포 환경을 모두 기억할 수 있다. 큰 조직에서는 한 팀이 만든 결과물이 다른 팀의 시스템에 들어가고, 다시 세 번째 팀의 자동화 파이프라인을 통과한다.

이때 필요한 것은 모든 팀이 같은 도구를 쓰는 일이 아니다. 더 중요한 것은 각 팀이 서로의 내부를 몰라도 사용할 수 있는 계약을 만드는 일이다.

계약은 다양한 형태를 가질 수 있다.

  • TypeScript에서는 선언 파일이 코드와 외부 파일 사이의 계약이 될 수 있다.
  • Java에서는 공개 인터페이스와 타입 체계가 구현 세부 사항을 감춘다.
  • 서비스 간 통신에서는 스키마와 버전 정책이 계약이 된다.
  • 조직에서는 책임 범위, 승인 기준, 장애 대응 규칙이 계약이 된다.
  • 제품에서는 사용자가 기대하는 동작과 오류 처리 방식이 계약이 된다.

여기서 중요한 것은 계약이 모든 것을 설명해야 한다는 생각을 버리는 것이다. 좋은 계약은 현실 전체의 복사본이 아니다. 상대방이 안전하게 의존하기 위해 필요한 정보만 담은 압축된 약속이다.

CSS 파일의 색상과 간격을 TypeScript가 모두 알아야 하는 것은 아니다. TypeScript가 알아야 하는 것은 해당 import가 허용되는지, 어떤 형태의 값으로 취급되는지 정도일 수 있다. 마찬가지로 서비스 소비자는 내부 클래스의 구조가 아니라 요청 형식, 응답 형식, 실패 조건을 알면 된다.

이 관점은 표준화에 대한 생각도 바꾼다. 표준화란 모든 차이를 제거하는 일이 아니다. 차이가 존재하는 상태에서도 예측 가능한 연결을 가능하게 하는 최소 규칙을 정하는 일이다.

유연성은 허가가 아니라 책임의 이동이다

임의 확장자를 허용하는 설정은 편리하다. 하지만 allowArbitraryExtensions를 켠다고 해서 시스템이 갑자기 더 안전해지는 것은 아니다. 컴파일러의 책임 일부가 런타임과 번들러, 그리고 개발자에게 이동할 뿐이다.

이 사실을 놓치면 설정은 해결책이 아니라 부채가 된다. 다음과 같은 상황을 생각해 보자. 팀이 CSS import 오류를 없애기 위해 임의 확장자를 허용했다. 처음에는 개발 경험이 좋아진다. 그러나 선언 파일을 생성하지 않거나, 실제 번들러 설정과 타입 선언이 다르게 유지되면 문제가 누적된다. 컴파일러는 통과했지만 실행 환경에서 파일이 처리되지 않을 수 있다.

따라서 모든 유연한 설정에는 세 가지 질문이 따라와야 한다.

1. 누가 최종적으로 진실을 알고 있는가

TypeScript가 모르는 파일을 번들러가 안다면, 번들러 설정이 실제 실행의 기준이다. 데이터베이스의 상태가 최종 기준이라면 애플리케이션 타입만 믿어서는 안 된다. 시스템에서 어떤 도구가 실제 동작을 결정하는지 먼저 밝혀야 한다.

2. 그 진실을 어떻게 검증할 것인가

위임은 방치와 다르다. 선언 파일 생성, 통합 테스트, 빌드 검증, 스키마 검사처럼 위임된 책임을 확인하는 절차가 필요하다. 컴파일러가 모든 것을 검사하지 않는다면, 다른 검사 장치를 의도적으로 배치해야 한다.

3. 계약이 깨졌을 때 얼마나 빨리 알 수 있는가

실패를 제거할 수 없다면 실패의 위치를 앞당겨야 한다. 개발 중에 발견되는 오류는 배포 후 장애보다 싸다. 로컬 빌드에서 발견되는 불일치는 운영 로그에서 발견되는 불일치보다 싸다. 유연한 시스템의 품질은 오류가 없는 상태가 아니라, 오류가 빠르고 명확하게 드러나는 상태에 가깝다.

이것은 대규모 언어 생태계에도 적용된다. 많은 사람이 사용하는 언어는 모든 사용자의 요구를 한 번에 만족시킬 수 없다. 대신 확장 지점, 인터페이스, 라이브러리 규칙, 도구 간 연결 방식을 제공해야 한다. 생태계의 성숙도는 중심 규칙의 수보다 안전한 위임의 품질로 측정된다.

경계를 설계하는 실전 모델: 인식, 위임, 검증

서로 다른 기술을 연결할 때 사용할 수 있는 간단한 모델이 있다. 모든 경계를 다음 세 단계로 살펴보는 것이다.

인식

현재 도구가 직접 이해하는 것은 무엇인가? 이해하지 못하는 것은 무엇인가? 이 질문을 명시적으로 적어 보는 것만으로도 많은 혼란이 줄어든다. 예를 들어 TypeScript는 .ts.tsx의 타입을 검사하지만, CSS의 실제 변환은 담당하지 않는다.

조직에서도 같은 목록을 만들 수 있다. 프런트엔드 팀은 화면 동작을 알고, 플랫폼 팀은 배포 환경을 알며, 보안 팀은 접근 정책을 안다. 어느 팀도 전체 시스템을 독점적으로 이해하지 않는다.

위임

직접 이해하지 못하는 영역의 책임을 누구에게 넘길 것인가? 이때 중요한 것은 책임자를 지정하는 일이다. “번들러가 알아서 처리한다”는 문장은 충분하지 않다. 어떤 번들러 설정이 기준인지, 누가 관리하는지, 변경 시 누가 검토하는지가 필요하다.

위임은 이름을 붙이는 행위다. 파일 형식마다 처리 주체를 정하고, 서비스마다 소유 팀을 정하고, 계약마다 변경 권한을 정해야 한다. 책임자가 없는 경계는 결국 모든 사람이 가끔씩 책임지는 경계가 되고, 그런 경계는 아무도 제대로 관리하지 않는다.

검증

위임한 책임이 실제로 지켜지는지 어떻게 확인할 것인가? 선언 파일이 실제 파일과 일치하는지, 번들 결과에 필요한 자원이 포함되는지, 서비스 스키마가 소비자의 기대와 맞는지 자동화해야 한다.

이 세 단계는 개발 도구뿐 아니라 조직 설계에도 사용할 수 있다. 인식은 범위의 명확화이고, 위임은 소유권의 명확화이며, 검증은 피드백 속도의 명확화다. 이 셋 중 하나라도 빠지면 경계는 흔들린다.

확장 가능한 시스템은 모든 것을 아는 시스템이 아니다. 모르는 것을 정확히 표시하고, 그 책임을 안전하게 넘기며, 결과를 다시 확인하는 시스템이다.

핵심 정리

  • 도구의 오류를 무조건 제거하지 말고, 오류의 책임자를 먼저 확인하라. 컴파일러의 경고를 끄기 전에 실제 실행을 책임지는 도구가 무엇인지 정한다.
  • 모든 외부 자원에 최소 계약을 부여하라. CSS, 이미지, API, 구성 파일처럼 코드 바깥의 대상도 타입, 선언, 스키마, 테스트 중 하나 이상의 형태로 경계를 만든다.
  • 유연한 설정을 켤 때 책임 이전을 기록하라. 무엇이 허용되었고, 그 결과 누가 검증을 담당하는지 설정 문서와 저장소 규칙에 남긴다.
  • 경계마다 인식, 위임, 검증을 점검하라. 현재 도구가 아는 것과 모르는 것, 책임자, 자동 검증 방법을 한 장의 문서로 정리한다.
  • 표준화의 목표를 동일성에서 예측 가능성으로 바꾸라. 모든 팀과 파일 형식을 똑같이 만들기보다, 달라도 안전하게 연결되도록 계약을 설계한다.

마지막으로, 소프트웨어의 진짜 규모를 다시 생각하기

우리는 종종 언어의 규모를 사용자 수로 측정한다. 개발자 520만 명이라는 숫자는 분명 강력한 신호다. 거대한 인력 풀과 축적된 지식, 풍부한 도구가 있다는 뜻이기 때문이다. 그러나 사용자 수가 많다는 것만으로 시스템이 확장 가능한 것은 아니다.

진짜 규모는 서로 다른 세계가 얼마나 적은 마찰로 연결되는지에서 드러난다. 오래된 엔터프라이즈 언어와 새로운 프런트엔드 도구가 공존할 수 있는가. 컴파일러가 모르는 자원을 런타임이 안전하게 처리할 수 있는가. 한 팀의 변경이 다른 팀의 내부 지식을 요구하지 않는가. 이런 질문에 답할 수 있을 때 비로소 생태계는 커진다.

결국 소프트웨어에서 가장 중요한 선은 파일 확장자나 모듈 경계가 아니다. 지식의 경계와 책임의 경계다. 모든 것을 직접 검증하려는 시스템은 작을 때는 안전해 보이지만, 커질수록 병목이 된다. 반대로 아무것도 검증하지 않는 시스템은 자유로워 보이지만, 커질수록 불안정해진다.

성숙한 시스템은 그 사이에서 작동한다. 각 도구가 자신의 한계를 인정하고, 다른 도구와 계약을 맺고, 위임된 책임을 빠르게 검증한다. 어쩌면 좋은 아키텍처란 모든 것을 통제하는 설계가 아니라, 통제하지 않아도 신뢰할 수 있도록 경계를 만드는 설계일 것이다.

Sources

← Back to Library

Hatch New Ideas with Glasp AI 🐣

Glasp AI allows you to hatch new ideas based on your curated content. Let's curate and create with Glasp AI :)

Start Hatching 🐣