Skip to content

Commit d04bd2e

Browse files
feat: 20260426 포스팅 - 보이스카웃 규칙
1 parent e709658 commit d04bd2e

2 files changed

Lines changed: 182 additions & 0 deletions

File tree

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
---
2+
title: "보이스카웃 규칙, 책에서 어디선가 본 적은 있긴 한데,,"
3+
categories: [협업]
4+
tags: [협업, 컨벤션, 장인정신]
5+
image:
6+
path: ../assets/img/posting-images/20260426/20260426_thumbnail.png
7+
alt: 보이스카웃 해본 적은 없는데..(?) 뭐 하튼 그런 규칙이 있다고 합니다~ 👮‍♂️🏕️
8+
width: 2048
9+
height: 2048
10+
---
11+
12+
며칠 전, 회사에서 팀장님과 PR 리뷰를 진행하다가, 팀장님께서 내게 물으셨다.
13+
14+
*"추천해드린 Clean Code 책에 보면 '보이스카웃 규칙'이라고 나오는데, 살펴본 적 있어요?"*
15+
16+
책에서 본 것 같긴 했다. 분명 어딘가 페이지를 넘기다 마주친 단어였다. 그런데 그게 정확히 어떤 내용이었는지, 그 자리에서 답을 내놓을 수가 없었다. 더듬더듬 비슷한 말을 꺼내보긴 했는데, 정확한 정의도 아니었고 내 것도 아니었다.
17+
18+
당황스러우면서 솔직히 부끄러웠다. 열심히 하는 모습만 보여드리고 싶었는데, 그러지 못한 게 그날 내내 마음에 걸렸다. 그런데 신기하게도 그 부끄러움은 며칠이 지나도 사라지지 않고, 오히려 그 키워드를 머릿속에 못박아두는 역할을 했다. 이 글은 그 키워드가 왜 내게 그렇게 들러붙었는지, 그리고 그게 어떤 깨달음으로 이어졌는지에 대한 기록이다.
19+
20+
## **보이스카웃 규칙이 뭔지**
21+
22+
원래 보이스카웃에는 이런 격언이 있다고 한다. *"캠프장은 처음 왔을 때보다 깨끗하게 하고 떠나라."* Robert C. Martin은 이걸 코드에 적용했다. 내가 작성하지 않은 코드라도, 내가 손댄 김에 조금이라도 더 낫게 만들고 떠나라는 것. 변수명 하나라도 더 명확하게, 죽은 코드 한 줄이라도 지우고, 흐름이 꼬인 부분이 있으면 살짝이라도 펴주고.
23+
24+
말로 들으면 당연한 얘기다. 그래서 책에서 봤을 때도 "그렇지" 하고 넘겼던 것 같다. 진짜로 이 규칙이 살아 움직이기 시작한 건, 며칠 뒤 내가 짠 코드를 다시 마주한 순간부터였다.
25+
26+
## **2달 전 내 코드를 살펴보니... 심각하다**
27+
28+
그날 나는 2달 전쯤 작성해둔 코드를 다시 열어봐야 했다. 기능을 조금 손봐야 하는 상황이었다.
29+
30+
코드를 읽기 시작하자마자 거부감이 올라왔다. 내가 짠 코드인데, 내가 거부감이 들었다.
31+
32+
뭐가 거슬렸는지 하나하나 떠올려보면 이렇다.
33+
34+
변수명과 함수명이 의미 불명이었다. `data`, `result`, `tmp` 같은 이름들이 곳곳에 흩어져 있어서, 이 변수가 뭘 담고 있는 건지 위로 올라가서 다시 읽어야 했다. 함수 하나가 너무 길어서 흐름을 한 번에 따라가기 힘들었다. 무슨 의도로 짠 건지 주석이라도 있으면 좋았을 텐데, 정작 필요한 곳엔 주석이 없었고 엉뚱한 곳에 옛날 주석이 남아있었다. 팀에서 정한 컨벤션에서 벗어난 부분도 곳곳에 섞여 있었다. 어디는 따르고 어디는 안 따르고. 거기에 더해 쓰이지 않는 함수와 주석 처리된 코드 블록이 그대로 방치되어 있었다.
35+
36+
그게 누가 짠 코드도 아니고 2달 전의 나였다. 책에서 보이스카웃 규칙이 "남이 더럽혀놓은 캠프장을 청소하는 이야기"인 줄 알았는데, 정작 마주한 건 **내가 더럽혀놓은 캠프장**이었다.
37+
38+
이 장면 위에 팀장님이 던지셨던 키워드가 겹쳐졌다. 그제야 그 개념이 머릿속에서 살아 움직이기 시작했다. 책으로 봤을 때는 "당연한 말"이었던 게, 내 코드를 보고 나니 "절실한 말"이 되어 있었다.
39+
40+
## **왜 그렇게 짰냐 기철아,,👊**
41+
42+
거부감보다 더 마음에 걸렸던 건, 왜 내가 그렇게 짰는지를 돌아봤을 때 나오는 답이었다.
43+
44+
이유는 솔직히 명확했다.
45+
46+
첫째, Django에 대한 기초적인 이해가 부족했다. ORM이 제공하는 도구를 충분히 알지 못한 채로 짜다 보니, 우회하는 코드가 많이 나왔다.
47+
48+
둘째, 일정이 급했다. "일단 돌아가게" 만드는 게 급선무였고, 다듬는 건 나중 일이었다. 그리고 그 "나중"은 오지 않았다.
49+
50+
셋째, 이게 가장 마음에 걸리는 부분인데, Claude Code의 플랜 모드만으로 거의 블랙박스처럼 구현을 맡겨버렸다. 빠르게 결과물이 나오니까 검토 없이 흘려보냈다. 그런데 Claude Code가 참고한 건 팀 컨벤션을 따르지 않은 채 남아있던 레거시 코드였다. 결과적으로 컨벤션이 더 흐트러진 코드가 생성됐고, 그게 그대로 머지됐다.
51+
52+
빠르게 짜준 도구를 탓하려는 게 아니다. 도구는 도구일 뿐이고, 결국 캠프장을 떠날 때 한 번 더 둘러보지 않은 건 나였다. 다만 이 경험에서 한 가지는 분명해졌다.
53+
54+
**속도와 청소는 별개의 문제다.** AI 도구는 짜는 속도를 줄여준다. 그런데 청소까지 자동으로 해주진 않는다. 오히려 빠르게 짜는 만큼 캠프장이 더러워지는 속도도 빨라진다. 게다가 AI가 참고하는 게 이미 더러운 캠프장이라면, 결과물은 그 더러움을 학습해서 한 번 더 더럽힌다.
55+
56+
생각해보면 AI 시대에는 보이스카웃 규칙이 더 중요해진 게 아닐까. 더러워지는 속도가 빨라진 만큼, 의식적으로 청소하지 않으면 캠프장은 손쓸 수 없게 망가진다.
57+
58+
### 코드로 보면 이런 거다 (Python/Django)
59+
60+
가상의 예로 사용자 목록을 가져오는 코드를 보자. 2달 전의 나라면 이렇게 짰을 법한 모습이다.
61+
62+
```python
63+
def get_data(req):
64+
# 활성 유저 가져오기
65+
tmp = User.objects.all()
66+
result = []
67+
for u in tmp:
68+
if u.is_active == True:
69+
result.append(u)
70+
# data = User.objects.filter(is_active=True) # 옛날 방식
71+
72+
final = []
73+
for r in result:
74+
final.append({
75+
'id': r.id,
76+
'name': r.name,
77+
})
78+
return JsonResponse({'data': final})
79+
```
80+
81+
`tmp`, `result`, `final`, `data` — 다 무슨 뜻인지 모르겠는 이름들이다. `is_active == True` 같은 불필요한 비교, 주석 처리된 죽은 코드, Django ORM이 제공하는 `filter``values`를 두고 Python에서 직접 도는 비효율까지. 짧은 함수인데도 다 거슬린다.
82+
83+
캠프장을 청소하고 떠나면 이렇게 된다.
84+
85+
```python
86+
def get_active_users(request):
87+
users = User.objects.filter(is_active=True).values('id', 'name')
88+
return JsonResponse({'data': list(users)})
89+
```
90+
91+
거창한 리팩터링이 아니다. 함수명을 의도가 드러나게 바꾸고, ORM의 도구를 쓰고, 죽은 코드를 지웠을 뿐이다. 그런데 다음에 이 코드를 열어볼 누군가는(아마도 미래의 나는) 거부감 없이 읽을 수 있다.
92+
93+
### 프론트엔드도 마찬가지 (JS/React)
94+
95+
상품 검색 컴포넌트를 가정해보자. 정리되지 않은 버전이다.
96+
97+
```jsx
98+
import React, { useState, useEffect } from 'react';
99+
import axios from 'axios';
100+
import _ from 'lodash'; // 사용 안 함
101+
102+
function Comp({ d, fn }) {
103+
const [data, setData] = useState([]);
104+
const [tmp, setTmp] = useState('');
105+
106+
useEffect(() => {
107+
axios.get('/api/products?q=' + tmp).then(r => {
108+
setData(r.data);
109+
});
110+
}, [tmp]);
111+
112+
// const handleOld = () => { ... }
113+
114+
return (
115+
<div>
116+
<input value={tmp} onChange={e => setTmp(e.target.value)} />
117+
{data.map(x => <div key={x.id} onClick={() => fn(x)}>{x.n}</div>)}
118+
</div>
119+
);
120+
}
121+
```
122+
123+
`Comp`, `d`, `fn`, `tmp`, `x`, `n` — 컴포넌트 이름과 prop 이름부터 의미를 알 수 없다. 안 쓰이는 import, 주석 처리된 핸들러, 검색어가 바뀔 때마다 디바운스 없이 호출되는 API까지. 한 번 보고 흐름을 이해하기가 쉽지 않다.
124+
125+
지나가는 김에 조금만 청소하면 이렇게 된다.
126+
127+
```jsx
128+
import React, { useState, useEffect } from 'react';
129+
import axios from 'axios';
130+
131+
function ProductSearch({ onSelect }) {
132+
const [products, setProducts] = useState([]);
133+
const [keyword, setKeyword] = useState('');
134+
135+
useEffect(() => {
136+
if (!keyword) return;
137+
const timer = setTimeout(() => {
138+
axios.get(`/api/products?q=${keyword}`).then(res => setProducts(res.data));
139+
}, 300);
140+
return () => clearTimeout(timer);
141+
}, [keyword]);
142+
143+
return (
144+
<div>
145+
<input value={keyword} onChange={e => setKeyword(e.target.value)} />
146+
{products.map(product => (
147+
<div key={product.id} onClick={() => onSelect(product)}>
148+
{product.name}
149+
</div>
150+
))}
151+
</div>
152+
);
153+
}
154+
```
155+
156+
언어와 프레임워크가 달라도 캠프장 청소의 원리는 같다. 의미 있는 이름, 죽은 코드 제거, 명백한 버그성 패턴(디바운스 누락) 보완. 작업하러 들어온 김에 눈에 보이는 만큼만 정리하는 것.
157+
158+
### 5S, TPM — 같은 이야기를 다른 분야에서 하고 있더라
159+
160+
이 깨달음을 곱씹다 보니, 비슷한 개념을 다른 분야에서 본 적이 있다는 게 떠올랐다.
161+
162+
제조업에는 **5S**라는 개념이 있다. 정리(필요 없는 것 버리기), 정돈(필요한 걸 찾기 쉽게), 청소, 청결(앞의 세 단계를 표준화하기), 생활화(습관으로 만들기). 그리고 그 위에 **TPM(전사적 생산보전)** 이라는 더 큰 틀이 있다. 핵심은 단순하다. *작업 환경은 만들어지는 게 아니라 유지되는 것이다.*
163+
164+
보이스카웃 규칙은 결국 소프트웨어 버전의 5S였다. 분야가 전혀 다른데 결론이 같다는 건, 이게 직군을 넘는 보편 원리에 가깝다는 뜻 같다. 좋은 환경은 만들어내는 게 아니라, 매일 조금씩 지켜내는 것이라는 원리.
165+
166+
### 다만 과하면 독이 된다
167+
168+
물론 균형 감각도 필요하다.
169+
170+
모든 PR마다 캠프장 전체를 청소하려 들면 PR 범위가 폭발한다. 원래 작업과 무관한 변경이 많아지면 리뷰어가 힘들어지고, 변경 의도가 흐려지고, 코드 리뷰는 본질에서 멀어진다. "이번 PR이 뭘 바꾸려는 거였는지" 자체가 안 보이게 된다.
171+
172+
그래서 보이스카웃 규칙은 *완벽주의*가 아니라 *생활화*에 가까운 개념이라고 생각한다. 지나가는 김에 눈에 들어오는 만큼만 깔끔하게. 한 번에 캠프장 전체를 갈아엎는 게 아니라, 매번 조금씩 더 나은 상태로 떠나는 것. 5S에서 마지막 항목이 "생활화"인 것도 같은 맥락일 거다.
173+
174+
## **이제는 나도 보이스카웃 규칙이 뭔지 몸으로 깨달았다.**
175+
176+
팀장님이 다시 물어봐주신다면, 이제는 답할 수 있을 것 같다.
177+
178+
다만 책에서 본 정의를 외워서가 아니다. 2달 전 내 코드를 마주한 그날의 거부감이 답이 됐기 때문이다. 책의 한 페이지로 머물던 개념이, 내 키보드 앞에서의 감각으로 바뀌었다.
179+
180+
소프트웨어 개발주기의 80%는 유지보수라고들 한다. 그 80%를 좌우하는 건 거창한 아키텍처나 화려한 신기술이 아니라, *지나갈 때마다 조금씩 청소하는 생활화* 일지도 모른다. 코드를 빠르게 짜주는 도구는 점점 늘어나고 있지만, 캠프장을 떠날 때 한 번 더 둘러보는 건 여전히 사람의 몫이다.
181+
182+
부끄러웠던 그날의 질문이, 결국 가장 오래 남는 배움이 됐다.
6.11 MB
Loading

0 commit comments

Comments
 (0)