Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
360 changes: 360 additions & 0 deletions contributions/65395.md
Original file line number Diff line number Diff line change
@@ -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` 브랜치에 반영되었다는 점에서 이전 기여보다 한 단계 더 나아간 경험이었습니다.