사전 패키지
용어함정

패키지

gabury1고친 사람 github-actions[bot]

패키지는 여러 파일을 한 이름 아래 묶어서 한 덩어리로 다루게 해 줍니다. 그런데 무엇을 위해 묶느냐에 따라 뜻이 둘로 갈립니다. 하나는 소스 코드 안에서 이름이 겹치지 않게 나누는 묶음입니다. 다른 하나는 만든 소프트웨어를 남에게 건네 설치하게 하는 묶음입니다.

쉽고 빠른 이해

무슨 일을 하는 물건인가 — 파일 여러 개에 이름 하나를 붙여 묶습니다. 자바 코드 맨 위의 package 한 줄도 패키지입니다. 명령 한 번으로 내려받아 설치하는 라이브러리도 패키지입니다. 두 물건은 이름만 같습니다.

왜 이렇게 하나 — 코드 쪽에서는 두 팀이 똑같이 Order 라는 클래스를 만들어도 섞이지 않게 하려고 묶습니다. 배포 쪽에서는 남이 만든 코드를 버전까지 맞춰 한 번에 받아 오게 하려고 묶습니다.

어떻게 도나

  1. 코드 패키지는 클래스 이름 앞에 묶음 이름을 붙여 서로를 가릅니다
  2. 배포 패키지는 결과물에 이름과 버전과 필요한 라이브러리 목록을 붙입니다
  3. 설치 도구(패키지 관리자)가 그 목록을 읽고 필요한 것을 줄줄이 받아 옵니다

대가 — 코드 패키지는 이름이 길어집니다. 폴더 구조에도 매입니다. 배포 패키지는 서로 다른 버전을 요구하는 라이브러리가 만나면 충돌합니다. 그리고 대화에서 둘을 섞어 부르면 서로 다른 이야기를 하게 됩니다.

상세

이 절은 「패키지」가 가리키는 두 물건을 나란히 놓고 봅니다. 먼저 두 뜻을 표 하나로 가른 뒤, 코드를 나누는 패키지와 배포하는 패키지를 차례로 따라갑니다.

끝에서는 두 뜻이 한 라이브러리 안에서 동시에 나오는 경우를 보고, 대화에서 어느 뜻인지 알아채는 단서를 모읍니다.

두 뜻

두 뜻은 묶는 대상과 묶는 까닭이 다릅니다. 한쪽은 개발자가 코드를 짜는 동안 씁니다. 다른 쪽은 코드를 다 만든 뒤 내보낼 때 씁니다.

맥락 무엇을 묶나 왜 묶나 예
코드 구성 클래스 · 함수 · 소스 파일 이름을 나누고 보이는 범위를 정한다 자바의 com.shop.order · 파이썬에서 import 하는 폴더
배포 빌드한 결과물 + 이름 · 버전 · 의존성 정보 남이 받아서 설치하게 한다 npm 패키지 · 데비안의 .deb 파일 · 메이븐으로 받는 JAR(Java ARchive, 자바 아카이브) 파일

표의 두 줄은 서로를 대신하지 못합니다. 코드 패키지는 파일 하나로 떼어 건넬 수 있는 물건이 아닙니다. 배포 패키지는 코드 안의 이름을 나눠 주지 않습니다.

코드를 나누는 패키지

큰 프로그램에는 클래스가 수천 개 들어갑니다. 주문 팀과 배송 팀이 둘 다 Order 라는 클래스를 만들면 컴파일러는 어느 쪽을 말하는지 모릅니다.

그래서 클래스 이름 앞에 묶음 이름을 붙입니다. 이 묶음 이름이 코드 패키지입니다. 이름이 겹치지 않게 나눈 구역을 네임스페이스라고 합니다. 코드 패키지는 언어가 주는 네임스페이스의 한 형태입니다.

자바에서는 파일 맨 위에 패키지를 적습니다.

Java
package com.shop.order;

class Order { }  // com.shop.order.Order

클래스의 온전한 이름은 패키지 이름과 클래스 이름을 이은 것입니다. 배송 팀의 클래스는 com.shop.delivery.Order 가 되니 둘이 섞이지 않습니다.

패키지 이름은 폴더 경로와도 이어집니다. 자바 컴파일러는 소스 파일 Order.java 를 실행할 수 있는 형태로 바꿔 Order.class 를 냅니다. 이 결과 파일이 클래스 파일입니다. 자바는 실행할 때 패키지 이름의 점을 폴더 구분으로 바꿔 com/shop/order/Order.class 경로에서 이 파일을 찾습니다.

그 경로를 어느 폴더에서부터 따라갈지는 따로 정해 줘야 합니다. 클래스 파일을 찾아볼 폴더와 JAR 파일의 목록을 클래스패스라고 합니다.

코드 패키지가 하는 일이 하나 더 있습니다. 보이는 범위를 정합니다. 자바에서 접근 제어자를 안 붙인 클래스와 메서드는 같은 패키지 안에서만 보입니다. 바깥에 내놓을 것과 안에서만 쓸 것을 패키지 경계로 가르는 것입니다.

언어마다 패키지와 폴더를 잇는 방식이 조금씩 다릅니다.

언어 패키지와 폴더 밖에서 보이는 것
자바 패키지 이름의 점이 폴더 경로가 된다 주로 public 을 붙인 것
파이썬 파이썬 파일 하나가 모듈이고, 모듈을 담은 폴더가 패키지다 기본으로 전부. 밑줄로 시작하는 이름은 안에서 쓰라는 관례
Go 폴더 하나에 든 소스 파일이 한 패키지다 대문자로 시작하는 이름

대가는 이름과 폴더가 묶인다는 것입니다. 클래스를 다른 패키지로 옮기면 그 클래스를 부르는 코드도 전부 고쳐야 합니다. 패키지 이름이 깊어질수록 이름도 길어집니다.

배포하는 패키지

남이 만든 라이브러리를 쓰려면 코드 파일만으로는 모자랍니다. 그 라이브러리의 이름과 버전을 알아야 합니다. 그 라이브러리가 기대는 다른 라이브러리도 함께 받아야 합니다. 이렇게 기대는 다른 패키지를 의존성이라고 합니다.

배포 패키지는 결과물과 이런 정보를 한 덩어리로 묶은 것입니다. 결과물에 붙는 이 정보를 메타데이터라고 합니다. 메타데이터에는 대개 이름과 버전과 의존성 목록이 들어갑니다.

이 묶음을 읽고 설치해 주는 도구가 패키지 관리자입니다. 앞에서 「설치 도구」라고 부른 것이 이것입니다. 패키지 관리자는 메타데이터의 의존성 목록을 보고 필요한 패키지를 차례로 내려받습니다. 개발자는 이름 하나만 적으면 됩니다.

패키지를 받아 오는 곳은 저장소입니다. 여기서 저장소는 git 같은 코드 저장소가 아니라, 패키지를 모아 두고 내려받게 해 주는 서버를 말합니다.

형식은 생태계마다 다릅니다. 메타데이터를 패키지 파일 안에 넣는 곳도 있고, 파일 곁에 따로 두는 곳도 있습니다. 아래 표에서 JAR 는 pom.xml 을 저장소의 같은 자리에 별도 파일로 두고, .deb 는 control 파일을 패키지 안에 넣습니다.

생태계 패키지 파일 메타데이터가 담기는 곳
자바스크립트 npm 패키지 package.json
자바 JAR 파일 곁에 따로 두는 pom.xml
데비안 계열 리눅스 .deb 파일 안에 든 control 파일

릴리스 엔지니어링은 만든 코드를 사용자에게 내보내기까지의 과정을 다루는 일입니다. 거기서 말하는 패키지도 이쪽 뜻입니다. 빌드한 결과를 패키지로 묶고 버전을 붙인 뒤 배포 단계로 넘깁니다. 이때 「배포」는 묶음이 아니라 그 묶음을 실제로 내보내는 단계를 가리킵니다.

이름과 버전이 같으면 사람들은 같은 내용이라고 믿고 씁니다. 그래서 한 번 내보낸 버전의 내용은 바꾸지 않는 것이 원칙입니다. 고칠 것이 생기면 버전을 새로 올려 내보냅니다.

대가는 버전 충돌입니다. 라이브러리 A 는 어떤 패키지의 버전 1을, 라이브러리 B 는 같은 패키지의 버전 2를 요구하면 둘을 한 프로그램에 같이 넣기 어렵습니다. 이런 얽힘이 쌓인 상태를 의존성 지옥이라고 부릅니다.

두 뜻이 한 라이브러리에서 만날 때

두 뜻은 따로 노는 것 같습니다. 하지만 한 라이브러리 안에서 동시에 나옵니다. 배포 패키지 하나 안에 코드 패키지가 여러 개 들어 있기 때문입니다.

주문 기능을 담은 라이브러리를 order-lib 이라는 이름으로 내보낸다고 해 봅시다. 그 안에는 주문 코드와 결제 코드가 서로 다른 코드 패키지로 나뉘어 있습니다.

flowchart TD
    subgraph D["배포 패키지 · order-lib 1.2.0"]
        M["메타데이터 · 이름 · 버전 · 의존성 목록"]
        subgraph C["안에 든 코드 패키지"]
            P1["com.shop.order"]
            P2["com.shop.payment"]
        end
    end
    D --> R["패키지 관리자가 받아서 설치한다"]
    C --> I["코드가 import 로 불러 쓴다"]

그림에서 바깥 상자를 다루는 쪽은 패키지 관리자입니다. 안쪽 상자를 다루는 쪽은 개발자의 코드입니다. 그래서 설치할 때 쓰는 이름과 코드에서 부르는 이름이 다를 수 있습니다.

파이썬에서 흔히 만나는 예가 있습니다. 설치할 때는 배포 패키지 이름을 씁니다. 코드에서는 그 안에 든 코드 패키지 이름을 씁니다.

pip install beautifulsoup4  # 배포 이름
import bs4                  # 코드 이름

두 줄은 같은 라이브러리를 가리킵니다. 그런데 이름이 다릅니다. 「패키지 이름이 뭐냐」는 물음에 답이 둘인 까닭이 이것입니다.

어느 뜻인지 가르는 단서

대화나 문서에서 「패키지」가 나오면 함께 붙은 동사와 낱말을 봅니다. 대개 그것만으로 어느 뜻인지 갈립니다.

함께 나오는 말 뜻
설치한다 · 올린다 · 내려받는다 · 버전을 올린다 배포
패키지 관리자 · 저장소 · 의존성 배포
import 한다 · 패키지 경로 · 같은 패키지 안에서만 보인다 코드 구성
패키지를 나눈다 · 패키지 구조 코드 구성

단서가 없으면 한 번 되묻는 편이 낫습니다. 「패키지를 옮기자」는 코드 폴더를 재배치하자는 말일 수 있습니다. 라이브러리를 다른 저장소로 옮기자는 말일 수도 있습니다.

관련 항목

코드 패키지와 함께 이름을 나누는 언어 요소

네임스페이스 · 모듈 · 클래스 · 접근 제어자 · import · 클래스패스 · 클래스 파일

배포 패키지를 받아서 설치하는 도구

패키지 관리자 · npm · pip · Maven · Gradle · apt

배포 패키지를 담는 파일 형식

JAR · WAR · wheel · deb · 컨테이너 이미지

배포 패키지에 붙는 버전과 의존성 정보

메타데이터 · 버전 번호 · 시맨틱 버저닝 · 의존성 · package.json · pom.xml · 락 파일

배포 패키지가 거치는 릴리스 단계

빌드 · 빌드 아티팩트 · 릴리스 엔지니어링 · 배포 · 아티팩트 저장소 · 패키지 서명

배포 패키지에서 자주 나는 장애

의존성 지옥 · 버전 충돌 · 타이포스쿼팅 · 소프트웨어 공급망 보안

다른 이름: package