diff --git a/contributions/65395.md b/contributions/65395.md new file mode 100644 index 0000000..2bf21ec --- /dev/null +++ b/contributions/65395.md @@ -0,0 +1,360 @@ +--- +pr-url: https://github.com/nodejs/node/pull/65395 +--- + +## 문제 내용 + +Node.js Issue #57367에서는 `net.Socket`의 실제 동작과 문서의 설명 사이에서 혼동이 발생할 수 있다는 문제가 제기되어 있었습니다. + +기존 `socket.destroyed` 문서에는 connection이 destroyed되면 더 이상 데이터를 전송할 수 없다는 설명이 있었고, `socket.destroy()` 역시 다음과 같이 설명되어 있었습니다. + +```text +Ensures that no more I/O activity happens on this socket. +``` + +이 설명만 보면 `socket.destroy()`를 호출한 이후에는 해당 `Socket` 객체 자체가 영구적으로 사용할 수 없는 상태가 된다고 이해할 수 있습니다. + +하지만 실제 `net.Socket`의 동작은 달랐습니다. + +Socket을 생성한 뒤 다음과 같이 다시 연결을 시도할 수 있었습니다. + +```text +connect() +↓ +destroy() +↓ +connect() +``` + +즉 `destroy()` 이후에도 동일한 `Socket` 객체에서 새로운 connection을 생성할 수 있었습니다. + +따라서 기존 문서는 `Socket` 객체 자체의 lifecycle과 현재 connection의 lifecycle을 명확하게 구분하지 않아, `destroy()` 이후 해당 Socket 객체를 다시 사용할 수 없는 것으로 오해할 가능성이 있었습니다. + +이번 작업에서는 문장을 바로 수정하는 대신 실제 Node.js 동작을 직접 재현하여 문서와 runtime behavior가 어떤 차이를 보이는지 먼저 확인했습니다. + +## 해결 과정과 검증 + +### 실제 Socket 동작 재현 + +Issue에서 설명한 현상이 실제 Node.js에서도 동일하게 발생하는지 확인하기 위해 `net.Socket`을 생성하고 직접 연결 과정을 확인했습니다. + +실행 흐름은 다음과 같았습니다. + +```text +Socket 생성 +↓ +첫 번째 connect() +↓ +연결 성공 +↓ +destroy() +↓ +현재 connection 종료 +↓ +다시 connect() +↓ +새로운 connection 연결 성공 +``` + +이를 통해 `destroy()`가 호출되었다고 해서 `Socket` 객체 자체가 영구적으로 재사용 불가능해지는 것은 아니라는 점을 확인했습니다. + +이번 문제를 이해할 때 가장 중요했던 부분은 다음 두 lifecycle을 구분하는 것이었습니다. + +```text +Socket object lifecycle +≠ +connection lifecycle +``` + +하나의 `Socket` 객체에서 현재 connection은 destroy될 수 있지만, 이후 다시 `connect()`를 호출하여 새로운 connection을 생성할 수 있었습니다. + +따라서 API 문서 역시 객체 자체와 현재 연결의 의미를 구분해서 설명할 필요가 있다고 판단했습니다. + +### 초기 문서 수정 + +처음에는 `socket.destroyed`의 설명을 수정했습니다. + +기존 문서는 다음과 같았습니다. + +```diff +-* Type: {boolean} Indicates if the connection is destroyed or not. Once a +- connection is destroyed no further data can be transferred using it. +``` + +이를 다음과 같이 변경했습니다. + +```diff ++* Type: {boolean} Indicates if the connection is destroyed or not. No further ++ data can be transferred using a destroyed connection. +``` + +기존의 + +```text +Once a connection is destroyed +``` + +라는 표현은 이후에도 영구적으로 사용할 수 없는 상태처럼 읽힐 가능성이 있었습니다. + +이를 + +```text +No further data can be transferred using a destroyed connection. +``` + +으로 변경하여 현재 destroyed된 connection에서는 데이터를 전송할 수 없다는 의미를 보다 명확하게 표현했습니다. + +### 문서 검증 + +문서 수정 이후 Node.js Markdown 문서 검증을 수행했습니다. + +```bash +make lint-md +``` + +Markdown lint를 포함한 문서 검사가 정상적으로 완료되는 것을 확인한 후 Pull Request를 생성했습니다. + +Commit message는 다음과 같이 작성했습니다. + +```text +doc: clarify socket destroyed behavior +``` + +또한 관련 Issue가 PR merge와 함께 종료될 수 있도록 PR 본문에 다음 내용을 작성했습니다. + +```text +Fixes: https://github.com/nodejs/node/issues/57367 + +Tests: `make lint-md` +``` + +## 리뷰 및 수정 과정 + +PR을 생성한 이후 Node.js collaborator인 `jasnell`에게 첫 승인을 받았습니다. + +이후 리뷰 과정에서 `socket.destroyed`뿐만 아니라 바로 위에 있는 `socket.destroy()`의 설명 역시 같은 오해를 만들 수 있다는 피드백을 받았습니다. + +기존 `socket.destroy()` 문서는 다음과 같이 작성되어 있었습니다. + +```text +Ensures that no more I/O activity happens on this socket. +``` + +여기서 + +```text +this socket +``` + +이라는 표현은 `Socket` 객체 자체가 더 이상 사용할 수 없어진다는 의미로 해석될 가능성이 있었습니다. + +리뷰에서는 `socket.destroyed`를 명확하게 수정하는 것과 같은 이유로 `socket.destroy()` 설명 역시 함께 명확하게 하는 것이 좋겠다는 의견을 받았습니다. + +이에 리뷰 내용을 반영하여 다음과 같이 수정했습니다. + +```diff +-Ensures that no more I/O activity happens on this socket. ++Ensures that no more I/O activity happens on the current connection. +``` + +즉, + +```text +this socket +``` + +을 + +```text +the current connection +``` + +으로 변경했습니다. + +이를 통해 `destroy()`의 대상이 `Socket` 객체 자체의 영구적인 lifecycle이 아니라 현재 connection이라는 점이 더욱 분명해졌습니다. + +최종적으로 PR에서 변경된 핵심 내용은 다음과 같습니다. + +```diff +-Ensures that no more I/O activity happens on this socket. ++Ensures that no more I/O activity happens on the current connection. + +-* Type: {boolean} Indicates if the connection is destroyed or not. Once a +- connection is destroyed no further data can be transferred using it. ++* Type: {boolean} Indicates if the connection is destroyed or not. No further ++ data can be transferred using a destroyed connection. +``` + +처음에는 `socket.destroyed` 한 부분의 문서 문제를 수정하는 것으로 시작했지만, 리뷰를 통해 동일한 의미상의 문제가 `socket.destroy()`에도 존재한다는 것을 확인하여 수정 범위를 함께 확장했습니다. + +리뷰 내용을 반영한 이후 다시 승인을 받았고 PR이 merge 가능한 상태가 되었습니다. + +## Merge 결과 + +최종적으로 PR #65395는 Node.js 공식 저장소의 `main` 브랜치에 merge되었습니다. + +```text +PR #65395 +doc: clarify socket destroyed behavior +↓ +Merged +``` + +이번 PR은 관련 Issue #57367을 해결하는 PR이었기 때문에 merge와 함께 해당 Issue도 해결된 상태로 종료되었습니다. + +이번 기여의 전체 과정은 다음과 같습니다. + +```text +Issue #57367 확인 +↓ +문서의 의미 분석 +↓ +Socket 실제 동작 재현 +↓ +connect() +→ destroy() +→ connect() +동작 확인 +↓ +Socket object와 connection lifecycle 구분 +↓ +socket.destroyed 문서 수정 +↓ +make lint-md +↓ +PR #65395 생성 +↓ +첫 리뷰 승인 +↓ +추가 리뷰 피드백 +↓ +socket.destroy() 설명까지 수정 +↓ +재승인 +↓ +Merge +``` + +## 배운 점 + +### 1. 문서 기여에서도 실제 동작을 직접 검증하는 것이 중요하다 + +이번 작업은 Node.js 내부 구현 코드를 변경하는 작업이 아니라 API 문서를 수정하는 작업이었습니다. + +처음에는 문장 표현만 수정하면 되는 간단한 문제처럼 보였지만, 문서가 실제 동작과 맞지 않는다고 판단하기 위해서는 먼저 Node.js가 실제로 어떻게 동작하는지를 확인해야 했습니다. + +따라서 직접 + +```text +connect() +→ destroy() +→ connect() +``` + +과정을 실행해 보면서 Socket이 destroy된 이후에도 다시 연결될 수 있다는 점을 확인했습니다. + +이를 통해 문서 기여 역시 단순한 표현 수정이 아니라 실제 runtime behavior를 근거로 해야 한다는 것을 배웠습니다. + +### 2. API의 lifecycle semantics를 구분해서 이해해야 한다 + +이번 기여에서 가장 중요하게 이해한 부분은 `Socket` 객체의 lifecycle과 현재 connection의 lifecycle이 서로 다른 개념이라는 점이었습니다. + +처음에는 `destroy()`라는 이름 때문에 다음과 같이 생각하기 쉬웠습니다. + +```text +socket.destroy() +↓ +Socket 객체 파괴 +↓ +다시 사용 불가능 +``` + +하지만 실제 동작은 다음과 같았습니다. + +```text +Socket 객체 +│ +├─ connection 1 +│ ↓ +│ destroy() +│ +└─ connection 2 + ↑ + connect()로 다시 생성 가능 +``` + +따라서 `destroy()`가 의미하는 대상이 무엇인지 정확하게 이해하는 것이 중요했습니다. + +API 문서에서는 단순히 기능을 설명하는 것뿐만 아니라 객체, connection, 상태 등이 각각 어떤 lifecycle을 가지는지 명확하게 표현해야 한다는 점을 배웠습니다. + +### 3. 리뷰를 통해 문제의 범위를 더 정확하게 볼 수 있었다 + +처음 PR을 작성했을 때는 `socket.destroyed` 문서만 수정했습니다. + +하지만 리뷰 과정에서 바로 위의 `socket.destroy()` 문서 역시 같은 오해를 만들 수 있다는 의견을 받았습니다. + +따라서 수정 범위가 + +```text +socket.destroyed +``` + +에서 + +```text +socket.destroy() ++ +socket.destroyed +``` + +로 확장되었습니다. + +이를 통해 코드 리뷰는 단순히 작성한 변경이 맞는지 승인받는 과정이 아니라, 내가 발견한 문제를 더 넓은 관점에서 다시 살펴보고 변경의 완성도를 높이는 과정이라는 것을 경험했습니다. + +### 4. 이전 기여보다 한 단계 더 깊은 문제를 다뤄볼 수 있었다 + +이전 PR #65124에서는 잘못된 문서 링크를 수정하면서 Node.js 기여 절차와 리뷰, CI, Commit Queue 등의 흐름을 처음 경험했습니다. + +이번 PR에서는 단순한 링크나 오타 수정에서 한 단계 더 나아가 실제 API의 동작을 직접 재현하고 그 결과를 바탕으로 문서의 의미를 수정했습니다. + +```text +문서 확인 +↓ +실제 runtime behavior 확인 +↓ +API semantics 분석 +↓ +문서 수정 +``` + +이라는 과정을 경험하면서 문서를 수정할 때도 Node.js 내부 API가 어떤 의미로 동작하는지 이해하는 것이 중요하다는 것을 알게 되었습니다. + +### 5. 실제 Node.js Core에 내 변경이 반영되는 전체 과정을 경험했다 + +이전 PR에서는 Pull Request 작성, 리뷰, 수정, CI, Commit Queue까지 경험했지만 최종적으로 제 PR 자체가 merge되지는 않았습니다. + +이번 PR #65395에서는 + +```text +Issue 분석 +↓ +실제 동작 재현 +↓ +수정 +↓ +검증 +↓ +Pull Request +↓ +리뷰 +↓ +피드백 반영 +↓ +승인 +↓ +Merge +``` + +까지 오픈소스 기여의 전체 흐름을 경험할 수 있었습니다. + +특히 직접 분석하고 수정한 내용이 실제 Node.js 공식 저장소의 `main` 브랜치에 반영되었다는 점에서 이전 기여보다 한 단계 더 나아간 경험이었습니다.