Skip to content

Split View: 남이 쓴 것을 읽는 능력 — 코드베이스 진입과 문서 없는 시스템 역설계

✨ Learn with Quiz
|

남이 쓴 것을 읽는 능력 — 코드베이스 진입과 문서 없는 시스템 역설계

쓰는 연습은 강제되지만 읽는 연습은 아닙니다

일하면서 코드를 쓰면 결과가 강제로 평가됩니다. 돌아가거나 안 돌아가고, 리뷰를 받고, 배포됩니다. 잘 못 쓰면 티가 납니다.

읽기는 그렇지 않습니다. 대충 읽어도 아무도 모릅니다. 이해한 척하고 옆에 붙여 쓰면 대개 동작하고, 문제가 생겨도 몇 달 뒤이고, 그때는 원인이 읽기 부족이었다는 것이 보이지 않습니다.

그래서 읽기는 모두가 매일 하면서도 아무도 훈련하지 않는 기술이 됐습니다. 그리고 이 비대칭 위로 최근의 변화가 얹혔습니다. 자기 손으로 쓰지 않은 코드가 저장소에 들어오는 양이 늘었습니다. 코드를 만들어 내는 능력의 상대적 값어치가 떨어질수록, 남이 만든 것을 읽고 판정하는 능력의 값어치는 올라갑니다.

코드에 남지 않는 것

읽기가 어려운 근본 이유는 코드가 결정의 결과만 남기고 결정의 과정은 남기지 않기 때문입니다.

코드는 채택된 안 하나만 보여 줍니다. 검토됐다가 버려진 세 개의 대안, 버린 이유, 그때 걸려 있던 제약, 이 구조를 강요한 외부 시스템의 사정은 어디에도 없습니다. 그래서 읽는 사람은 "왜 이렇게 이상하게 되어 있지"에서 자주 멈추고, 대개 그 이상함에는 이유가 있었습니다.

Fred Brooks가 1986년 "No Silver Bullet"에서 나눈 구분이 여기서 유용합니다. 그는 소프트웨어의 복잡성을 우연적 복잡성과 본질적 복잡성으로 나누고, 도구가 개선하는 쪽은 우연적 복잡성이며 본질적 복잡성은 문제 자체에서 나오므로 제거할 수 없다고 봤습니다. 그의 논지는 어떤 단일한 발전도 10년 안에 열 배의 개선을 약속하지 못한다는 것이었습니다.

이 구분을 읽기에 적용하면 이렇게 됩니다. 문법과 관용구는 우연적 복잡성이고, 도구의 도움을 잘 받습니다. 반면 이 도메인이 왜 이 규칙을 갖는지, 왜 이 두 시스템이 이런 순서로만 대화해야 하는지는 본질적 복잡성이고, 텍스트만 봐서는 복원되지 않습니다. 읽기 훈련이 향하는 곳은 후자입니다.

대규모 코드베이스에 진입하는 일곱 단계

낯선 저장소를 받았을 때 순서가 있습니다. 순서를 지키는 것만으로 첫 주가 크게 달라집니다.

  1. 먼저 돌립니다. 빌드하고 기동하고 헬스체크를 통과시킵니다. 못 돌리는 상태에서 읽는 것은 전부 추측입니다. 이 단계에서 막힌 지점들이 그 자체로 시스템의 숨은 의존성 목록이 됩니다.
  2. 진입점을 찾습니다. 라우터 정의, 메시지 컨슈머, 스케줄러 등록부. 여기가 지도의 해안선입니다.
  3. 요청 하나를 끝까지 따라갑니다. 넓게 훑지 말고 하나를 수직으로 관통합니다. 가장 단순한 조회 요청 하나면 충분합니다. 이 한 번으로 계층 구조와 이름 규칙과 오류 처리 관습이 한꺼번에 들어옵니다.
  4. 데이터 모델을 봅니다. 스키마와 마이그레이션 이력은 도메인의 화석입니다. 컬럼이 추가되고 이름이 바뀐 흔적은 업무가 어떻게 변해 왔는지를 코드보다 정직하게 말해 줍니다.
  5. 테스트를 명세로 읽습니다. 테스트는 이 팀이 무엇을 지켜야 한다고 믿는지의 목록입니다. 테스트가 없는 영역은 아무도 계약을 정하지 않은 영역입니다.
  6. 변경 밀도를 봅니다. 자주 바뀌는 파일이 위험한 곳이자 중요한 곳입니다.
  7. 자기 말로 다시 씁니다. 한 장짜리 요약을 만들어 아는 사람에게 보여 주고 틀린 데를 지적받습니다. 이 단계를 건너뛰면 앞의 여섯 단계가 확인되지 않은 채로 남습니다.
# 예시 — 지난 1년간 가장 자주 바뀐 파일 상위 20개
git log --since=1.year --name-only --pretty=format: \
  | grep -v '^$' | sort | uniq -c | sort -rn | head -20

이 목록의 위쪽 파일들을 먼저 읽으면 투자 대비 이해도가 가장 빨리 올라갑니다. 자주 바뀐다는 것은 요구가 자주 닿는다는 뜻이고, 요구가 자주 닿는 곳이 그 시스템의 심장입니다.

문서 없는 시스템은 실행 중인 자신이 문서입니다

문서가 없는 시스템을 만나면 사람들은 코드부터 뒤집니다. 순서가 반대인 경우가 많습니다. 실행 중인 시스템은 자기 자신에 대한 가장 최신 문서입니다. 코드는 배포되지 않았을 수도 있지만, 지금 돌고 있는 프로세스는 거짓말을 하지 않습니다.

관측에서 시작하면 이런 것들이 먼저 나옵니다. 어떤 포트가 열려 있고 누구와 연결을 맺고 있는지, 어떤 환경변수와 설정이 실제로 주입되어 있는지, 어떤 로그가 어떤 빈도로 나오는지, 어떤 스케줄이 몇 시에 도는지. 여기까지만으로도 시스템의 경계와 외부 의존성이 그려집니다.

그다음에 코드로 들어가면 읽는 목적이 생깁니다. 목적 없이 읽으면 파일 목록만 훑다 끝나고, "이 연결은 왜 맺어져 있나"를 들고 들어가면 필요한 곳만 정확히 읽게 됩니다.

한 가지 함정을 미리 적어 둡니다. 저장소에 있다고 살아 있는 것이 아닙니다. 죽은 코드를 읽는 데 며칠을 쓰는 일이 생각보다 흔합니다. 읽기 전에 "지금 여기로 트래픽이 지나가는가"를 먼저 확인하세요. 로그 한 줄, 호출 카운터 하나면 답이 나옵니다.

읽기가 왜 비싼 쪽에 남는가

이 시리즈의 판별식으로 돌아가면, 읽기는 검증 비용이 비싼 쪽에 확실히 속합니다. 이유가 두 가지입니다.

하나는 읽기의 산출물이 이해이고, 이해는 직접 검사할 수 없다는 점입니다. 검사하려면 이해를 밖으로 꺼내야 합니다. 요약을 쓰거나, 설명하거나, 예측을 해서 맞는지 봐야 합니다. 그래서 읽기를 훈련하려면 반드시 출력이 붙어야 하고, 일곱 번째 단계가 선택이 아닌 이유가 여기 있습니다.

다른 하나는 앞에서 말한 본질적 복잡성입니다. 읽어야 할 것의 상당 부분이 코드 밖에 있고, 그것을 가진 사람에게 물어야 합니다. 무엇을 물어야 할지 아는 것 자체가 읽기의 결과이므로, 이 능력은 텍스트 처리 능력이 아니라 조직 안에서 정보를 구하는 능력과 붙어 있습니다.

직접 해보기

이번 주에 남이 쓴 병합된 PR 하나를 고르세요. 그리고 다섯 문장으로 요약합니다. 무엇을 바꿨는가, 왜 바꿨는가, 어떤 대안이 있었을 것 같은가, 무엇이 깨질 수 있는가, 무엇을 아직 모르겠는가. 그다음 작성자에게 보내 틀린 곳을 물어보세요. 마지막 문장이 가장 값어치 있는 질문을 만들어 줍니다.

  • Git 놀이터 — 이력을 뒤지고 되돌리고 좁히는 조작을 실제 저장소를 망칠 걱정 없이 반복할 수 있습니다.
  • 논리법 훈련소 — 남의 논증을 정확히 재구성하는 연습입니다. 남의 코드를 읽는 일과 같은 근육을 씁니다.

안 통하는 경우도 있습니다. 곧 폐기될 시스템이라면 깊게 읽는 것이 낭비입니다. 그때는 이해가 아니라 경계만 파악하면 됩니다. 무엇이 들어오고 무엇이 나가는지만 알면 갈아 끼울 수 있습니다.

이어서 읽기

비싸게 남는 기술 시리즈

참고 자료

  • No Silver Bullet — Wikipedia 요약 — Fred Brooks가 1986년에 제시한 우연적 복잡성과 본질적 복잡성의 구분, 그리고 10년 안에 열 배 개선을 약속하는 단일한 발전은 없다는 주장. 2026-08-15 확인.
  • 일곱 단계 절차와 관측 우선 역설계 순서는 위 자료에 나오는 것이 아니라 이 글에서 정리한 것입니다.

Reading What Others Wrote — Entering a Codebase and Reverse-Engineering an Undocumented System

Writing Gets Practiced Under Compulsion, Reading Does Not

Write code at work and the result is graded whether you like it or not. It runs or it does not, it gets reviewed, it ships. Writing badly shows.

Reading is not like that. Skim carelessly and nobody notices. Pretend to understand, bolt your change on beside it, and it usually works. If something does break it breaks months later, and by then nobody can see that the cause was shallow reading.

So reading became the skill everyone performs daily and nobody trains. Onto that asymmetry the recent shift landed: the volume of code entering repositories that nobody on the team typed by hand went up. As the relative value of producing code falls, the value of reading and judging what someone else produced rises.

What Never Survives Into Code

The root reason reading is hard is that code preserves the result of a decision and discards the process.

Code shows one adopted option. The three alternatives considered and dropped, the reason they were dropped, the constraints in force at the time, the external system whose scheduling forced this shape — none of that is anywhere. So readers stall at "why is this so strange," and usually the strangeness had a reason.

The distinction Fred Brooks drew in 1986 in "No Silver Bullet" is useful here. He split software complexity into accidental and essential, held that tooling improves the accidental kind, and argued the essential kind comes from the problem itself and cannot be removed. His thesis was that no single development promises a tenfold improvement within a decade.

Apply that to reading and it comes out like this. Syntax and idiom are accidental complexity and take help from tooling well. Why this domain carries this rule, why these two systems may only talk in this order, is essential complexity and does not reconstruct from text alone. Reading practice aims at the second kind.

Seven Steps Into a Large Codebase

There is an order for a repository you have never seen. Keeping the order alone changes the first week substantially.

  1. Run it first. Build, boot, get a health check passing. Reading in a state where you cannot run it is all guesswork. The points where you got stuck are themselves a list of the hidden dependencies.
  2. Find the entry points. Route definitions, message consumers, the scheduler registry. This is the coastline of your map.
  3. Follow one request all the way through. Do not sweep broadly; cut one vertical slice. The simplest read-only request will do. That single pass hands you the layering, the naming conventions, and the error-handling habits at once.
  4. Look at the data model. Schema and migration history are the fossil record of the domain. Columns added and renamed tell you how the business changed, more honestly than the code does.
  5. Read the tests as a specification. Tests are the list of what this team believes must hold. Areas without tests are areas where nobody set a contract.
  6. Look at change density. The files that change often are both the dangerous places and the important ones.
  7. Rewrite it in your own words. Produce a one-page summary, show it to someone who knows the system, and let them mark what is wrong. Skip this step and the previous six stay unverified.
# Example — the 20 files changed most often in the last year
git log --since=1.year --name-only --pretty=format: \
  | grep -v '^$' | sort | uniq -c | sort -rn | head -20

Reading the files at the top of this list first buys the most understanding per hour. Frequent change means requirements touch that spot often, and where requirements land often is the heart of the system.

An Undocumented System Documents Itself While Running

Faced with an undocumented system, people dig into the source first. Often that is backwards. A running system is the most current documentation of itself. The code might not even be what got deployed, but the process running right now does not lie.

Start from observation and these surface first: which ports are open and who holds connections to them, which environment variables and config are actually injected, which logs appear at what rate, which schedules fire at what hour. That alone sketches the system boundary and its external dependencies.

Then going into the code gives the reading a purpose. Read without one and you skim a file listing; walk in holding "why does this connection exist" and you read exactly the parts you need.

One trap worth writing down in advance: being in the repository does not mean being alive. Spending days reading dead code happens more often than you would think. Before reading, confirm that traffic currently passes through. One log line or one call counter answers it.

Why Reading Stays on the Expensive Side

Back to this series' test: reading clearly belongs on the expensive-to-verify side, for two reasons.

One is that the output of reading is understanding, and understanding cannot be inspected directly. To inspect it you have to get it outside your head — write a summary, explain it, or make a prediction and check it. So training reading requires an attached output, and that is why step seven is not optional.

The other is the essential complexity above. A large share of what must be read lives outside the code and has to be asked of the person holding it. Knowing what to ask is itself a product of reading, so this capability is bound less to text processing than to the ability to source information inside an organization.

Try It This Week

Pick one merged pull request somebody else wrote. Summarize it in five sentences: what changed, why, what alternatives probably existed, what could break, and what you still do not understand. Then send it to the author and ask what you got wrong. The last sentence generates the most valuable question.

  • Git Playground — repeat history digging, reverting, and bisecting without risking a real repository.
  • Logical Reasoning Trainer — practice reconstructing someone else's argument accurately, which uses the same muscle as reading someone else's code.

Where this does not apply: if the system is about to be retired, deep reading is waste. Then you only need the boundary, not the understanding. Knowing what goes in and what comes out is enough to swap it out.

Further Reading

What Stays Expensive series

Sources

  • No Silver Bullet — Wikipedia summary — Fred Brooks and his 1986 split between accidental and essential complexity, plus the claim that no single development promises a tenfold improvement within a decade. Read 2026-08-15.
  • The seven-step procedure and the observation-first reverse-engineering order are not from that source; they are assembled in this post.