semantic Version과 Version Range Syntax

맛없는콩두유·2023년 2월 20일
0
post-thumbnail

1. Semantic Version이란?

이전 노트에서 본 express 패키지의 package.json 파일의 dependencies 필드를 살펴봅시다.

여기서 각 패키지의 이름 옆에 적힌 버전에 대한 이야기를 해보겠습니다.
dependencies 필드에 있는 각 패키지 이름 옆의 버전은 Semantic Version이라고 하는데요. Semantic Version을 우리말로 해석하면 '의미론적 버전' 정도로 해석할 수 있습니다.

Semantic Version은 위 그림에서 보이는 것처럼 1.3.7, 6.7.0 등과 같이 총 세 개의 숫자로 이루어진 버전인데요. 이때 이것을

이 이미지처럼 쪼개봤을 때,

X를 메이저 버전(major version)
Y를 마이너 버전(minor version)
Z를 패치 버전(patch version)

이라고 합니다. Semantic Version에서 중요한 것은 패키지의 버전을 업데이트할 때 일정한 규칙이 있다는 점인데요.

이 규칙을 배우기 전에 먼저 API라는 것이 뭔지 간단히 알아야합니다. API란 Application Programming Interface의 약자로 '외부에서 사용할 수 있도록 공개된 함수'를 의미합니다. 우리가 코드 내에서 require 함수를 써서 어떤 패키지를 로드하는 이유는 뭔가요? 그 패키지가 공개하는 함수 등을 사용하기 위해서잖아요? 이렇게 외부에서 사용할 수 있도록 공개된 함수 등을 모두 API라고 하는 겁니다. Semantic Version에서는 이 API의 변화를 기준으로 버전을 업데이트해야 합니다. 하나씩 설명해볼게요.

첫 번째로 가장 오른쪽의 패치 버전은, API에 변화를 주지 않는 범위 내에서의 변화가 이루어진 경우에 업데이트합니다. 이런 경우는 어떤 것들이 있을까요? 겉으로 공개된 API는 바뀌지 않았지만, 코드에 존재하던 버그를 해결하거나, 알고리즘을 바꿔서 그 효율성을 향상시킨 경우 등이 해당하겠죠? 이럴 때는 예를 들어, 버전을 2.3.1에서 2.3.2로 올릴 수 있는 겁니다. 2.3.1에서 바로 2.4.0이나 3.0.0으로 업데이트하면 안 되는 것이고요.

두 번째로 가운데에 있는 마이너 버전은, 이전 버전의 API와 호환되는(backward-compatible) API 상의 변화가 발생했을 때 업데이트합니다. 예를 들어, 새로운 API를 추가한 경우를 생각해봅시다. 그러니까 2.3.1 버전에서 새로운 API를 추가하면 2.4.0으로 버전을 올리면 됩니다. 그럼 기존의 2.3.1 버전의 패키지를 믿고 사용했던 다른 곳에서 이 패키지의 2.4.0 버전을 사용해도 괜찮은 걸까요? 네, 괜찮습니다. 왜냐하면 API 상의 변화가 생기긴 했지만 이미 존재했던 API들은 건드리지 않는 범위의 변화(단순 API 추가)가 발생한 것이기 때문입니다.

마지막으로 가장 왼쪽의 메이저 버전은, 이전 버전의 API와 호환되지 않는(not backward-compatible) API 상의 변화가 발생했을 때 업데이트합니다. 기존의 API를 아예 삭제했거나 그 이름을 바꾸는 등의 변화가 이것에 해당하는데요. 이럴 때는 원래 2.3.1 버전이었다면 3.0.0으로 버전을 올려줘야 합니다. 만약 자신이 사용하던 패키지의 메이저 버전이 업데이트되었다면 그리 좋은 소식은 아닐 수도 있습니다. 왜냐하면 그 패키지의 최신 버전을 사용하고 싶다면, 원래 사용하던 이전 버전 패키지의 API에서 어떤 부분들이 바뀐 건지를 체크하고, 코드를 재수정해야 할 가능성이 높기 때문입니다.

그리고 메이저 버전 업데이트는 패키지를 만드는 사람 입장에서도 너무 자주 해서는 안 되는 작업이기도 합니다. 특히, 인기가 많은 패키지일수록 해당 패키지에 의존해서 만들어진 것들이 많을 텐데 만약 메이저 버전 업데이트가 자주 발생하면 이것에 대해 많은 사람의 수고가 필요하기 때문이죠. 하지만 그렇다고 메이저 버전 업데이트를 안 할 수는 없는 일이겠죠? 만약 메이저 버전 업데이트가 발생했다면 해당 업데이트를 한 사람은 그 패키지를 가져다 쓴 사람들이 잘 알 수 있도록 홈페이지에 잘 공지해두고, 어떤 점이 크게 바뀐 건지를 잘 정리해두는 게 좋습니다.

Semantic Version이 뭔지 이해가 되시나요? 생각보다 엄격한 규칙이 포함된 버전 표기법이죠? 이런 체계적인 버전 관리 규칙이 있기 때문에 Node.js의 패키지 생태계가 잘 유지될 수 있는 겁니다.

2. Version Range Syntax 배우기

이번에는 방금 배운 Semantic Version을 기반으로 패키지가 다른 패키지의 어느 버전들을 요구하는지를 나타낼 때 사용되는 Version Range Syntax(버전 범위에 관한 표기법)에 대해 배워보겠습니다.

지금 이 이미지를 다시 보면 Semantic Version만 쓰여 있는 경우도 있지만 Semantic Version 왼쪽에 물결 모양 기호가 붙어있는 것도 보입니다. 물결 모양 기호의 정식 명칭은 틸드(Tilde)인데요. 이것도 Version Range Syntax 중의 하나입니다.

자, 이제

codeit이라는 패키지가 존재하고,
express 패키지가 codeit 패키지를 필요로 한다고 가정한 후,

Version Range Syntax를 본격적으로 배워봅시다.

(1) Basic Syntax

"codeit" : "2.3.1"

이렇게 쓰여 있으면 정확히 2.3.1 버전의 codeit 패키지가 필요하다는 뜻입니다.

"codeit" : ">2.3.1"

2.3.1보다 높은 버전의 codeit 패키지가 필요하다는 뜻입니다.

"codeit" : "2.3.1 || ≥2.5.0 <3.1.2"

2.3.1 버전의 codeit 패키지 또는 2.5.0 버전 이상이면서 3.1.2 버전 미만의 codeit 패키지가 필요하다는 뜻입니다. ||(or)는 왼쪽 조건과 오른쪽 조건 중 하나를 만족해야 한다는 뜻이고, ≥2.5.0 <3.1.2 사이의 공백 하나는 왼쪽과 오른쪽 조건 둘 다(&, and)를 만족해야 한다는 뜻입니다.

여기까지는 별로 어렵지 않죠? 이제 좀더 응용된 형태의 Syntax들도 보겠습니다.

(2) Advanced Syntax

1) Hyphen Range

"codeit" : "2.3.1 - 3.1.2"

2.3.1 버전 이상 3.1.2 버전 이하의 codeit 패키지가 필요하다는 뜻입니다. 이것은 ≥2.3.1 ≤3.1.2 을 줄여서 표시한 것이라고 생각하면 됩니다. 이때 패치 버전이나 마이너 버전을 표시하지 않는 경우도 있을 수 있는데요.

예를 들어, 2.3 - 3.1.2이면 자동으로 ≥2.3.0 ≤3.1.2 으로 빈자리에 0이 붙어서 해석됩니다.
하지만 만약 그런 버전이 오른쪽에 있다면,

그러니까 예를 들어 2.3.1 - 3.1 이면 ≥2.3.1 <3.2.0 이렇게 다르게 해석됩니다.
같은 원리로 2.3.1 - 3 이면 ≥2.3.1 <4.0.0 이렇게 해석됩니다.

2) X-range

"codeit" : "*"

어느 버전의 codeit 패키지도 상관없다는 뜻입니다.

"codeit" : "3.x"

x에는 어떤 버전이 들어가도 상관없다는 뜻입니다. 즉, ≥3.0.0 <4.0.0 과 같은 뜻입니다.
참고로 그냥 3이라고만 써있어도 3.x로 해석이 되어서 ≥3.0.0 <4.0.0 라는 뜻입니다.

"codeit" : "3.1.x"

같은 원리로 ≥3.1.0 <3.2.0 라는 뜻입니다.
참고로 그냥 3.1이라고만 써있어도 3.1.x로 해석이 되어서 ≥3.1.0 <3.2.0 라는 뜻입니다.

3) Tilde Range

위에서 봤던 물결 모양 기호(~, Tilde, 틸드)를 사용한 표기법인데요. 이 경우에는 마이너 버전이 표시된 경우는 패치 버전 업데이트까지만 허용하고, 마이너 버전이 없으면 마이너 버전의 업데이트까지 허락하는 겁니다.

"codeit" : "~3.1.2"

이런 경우는 ≥3.1.2 <3.2.0 이렇게 해석이 됩니다. 지금 3.1.2에 마이너 버전이 존재하므로 패치 버전이 업데이트된 것들만 허용합니다.

"codeit" : "~3.1"

만약 이렇게 패치 버전이 적혀있지 않다면 ≥3.1.0 <3.2.0 이렇게 해석됩니다. 지금 3.1에 마이너 버전이 존재하므로 패치 버전이 업데이트된 것들만 허용되는 겁니다. 생략된 패치 버전은 0부터 시작합니다.

"codeit" : "~3"

만약 마이너 버전도 적혀있지 않다면 ≥3.0.0 <4.0.0 이렇게 해석됩니다. 즉, 마이너 버전이나 패치 버전이 업데이트된 버전들만 허용합니다.

4) Caret Range

메이저 버전, 마이너 버전, 패치 버전 중에서 현재 보이는 가장 왼쪽의 0이 아닌 버전이 바뀌지 않는 선에서의 버전 업데이트만을 허용합니다.

"codeit" : "^1.2.3"

가장 왼쪽의 0이 아닌 버전, 즉, 1이 바뀌지 않는 선에서의 버전 업데이트만 허용됩니다. 여기서는 ≥1.2.3 <2.0.0 이라는 뜻입니다.

"codeit" : "^0.2.3"

가장 왼쪽의 0이 아닌 버전, 2가 바뀌지 않는 선에서의 버전 업데이트만 허용됩니다. ≥0.2.3 <0.3.0 이라는 뜻입니다.

"codeit" : "^0.0.3"

가장 왼쪽의 0이 아닌 버전, 3이 바뀌지 않는 선에서의 버전 업데이트만 허용됩니다. ≥0.0.3 <0.0.4 이라는 뜻입니다.

Version Range Syntax에 대해 배워봤는데요. 별로 어렵지는 않죠? 마지막의 Tilde Range와 Caret Range만 잘 구별할 수 있다면 큰 어려움은 없을 겁니다.

자, 이때까지

한 패키지의 package.json 파일에 있는 
dependencies 필드에 적힌 
각각의 패키지 이름 옆에 붙은 Semantic Version과 Version Range Syntax에 대해 배웠습니다.

이 두 가지를 잘 이해하면 앞으로 패키지 간의 의존 관계를 쉽게 해석할 수 있게 될 겁니다.

profile
하루하루 기록하기!

0개의 댓글