//
The Programmer's Brain · 펠리너 헤르만스
연구에 따르면 프로그래머는 업무 시간의 약 60%를 코드를 작성하는 것이 아니라 읽고 이해하는 데 사용한다. 이 수치는 직관과 어긋나 보이지만, 새로운 프로젝트에 합류하거나 낯선 레거시 코드를 마주할 때 우리가 얼마나 많은 시간을 소비하는지를 생각하면 납득이 된다.
헤르만스는 코드를 읽을 때 겪는 혼란을 세 가지 유형으로 분류한다. 이 분류가 유용한 이유는 혼란의 종류마다 해결 방식이 다르기 때문이다.
| 혼란의 유형 | 원인 | 해결 방향 |
|---|---|---|
| 지식의 부족 | LTM에 해당 내용이 없음 | 학습, 문서 참조 |
| 정보의 부족 | STM에 현재 맥락이 없음 | 코드 탐색, 추적 |
| 처리 능력 부족 | 작업 기억 공간 과부하 | 분해, 시각화 |
이 세 가지는 서로 독립적으로 작동하는 것이 아니라 상호 보완적이다. LTM에 패턴 지식이 많을수록 STM의 부담이 줄고, 작업 기억 공간의 처리 여력도 늘어난다.
LTM은 프로그래밍 언어의 문법, 알고리즘, 디자인 패턴, 도메인 지식을 저장하는 방대한 창고다. 용량에는 사실상 제한이 없지만, 저장된 정보를 얼마나 빠르게 인출할 수 있는가는 훈련에 달려 있다.
캘리포니아 대학교의 로버트 비요크와 엘리자베스 비요크는 기억 인출에 두 가지 강도가 있다고 분류했다.
즉, 알고 있지만 생각이 나지 않는 상황은 저장 강도는 높지만 인출 강도가 낮은 상태다. 이를 회복하는 가장 효과적인 방법은 능동적으로 기억을 꺼내려 시도하는 것이다. 검색 엔진에 바로 의존하는 대신 잠시라도 스스로 기억하려는 노력 자체가 인출 강도를 강화한다.
STM은 현재 작업과 관련된 정보를 임시로 저장한다. 지금 읽고 있는 코드의 변수명, 방금 본 함수 시그니처, 로컬 스코프의 상태 같은 것들이 여기 있다.
20세기 인지과학자 조지 밀러의 유명한 논문 "마법의 수 7, 플러스 마이너스 2"에 따르면, STM은 동시에 약 5~9개의 항목만 저장할 수 있다. 현대 연구에서는 이 수치를 더 좁혀 약 4개 전후로 보기도 한다.
이 제한이 코드 읽기에 직접적인 영향을 미친다. 함수 하나가 스코프를 공유하는 변수 15개를 조작한다면, 그 함수를 이해하는 것만으로도 STM이 과부하 상태에 놓인다.
작업 기억 공간은 단순히 정보를 기억하는 것이 아니라 처리하는 공간이다. 코드를 읽고 의미를 파악하며, 조건을 추론하고, 흐름을 예측하는 활동이 모두 여기서 일어난다. STM과 마찬가지로 동시에 처리할 수 있는 항목 수는 2~6개 수준이다.
LTM에 저장된 지식이 풍부할수록 STM이 처리해야 하는 저수준 정보(변수명, 키워드 등)가 줄어들고, 작업 기억 공간은 더 고수준의 추론에 집중할 수 있다. 이것이 숙련 개발자와 초보 개발자 사이의 본질적인 인지적 차이다.
1940년대 네덜란드 수학자 아드리안 더흐로트는 체스 마스터와 일반 플레이어에게 실전 게임 중의 말 배치를 잠깐 보여준 후 재현하게 했다. 마스터들은 놀랍도록 정확하게 재현했지만, 일반 플레이어는 대부분 실패했다.
그런데 말을 무작위로 배치했을 때는 두 그룹의 차이가 거의 사라졌다.
이 실험이 의미하는 바는 체스 마스터의 기억력이 뛰어난 것이 아니라는 점이다. 그들은 수천 번의 실전 경험으로 쌓인 패턴 지식을 갖고 있었고, 실전 배치를 볼 때 그 패턴을 청크(chunk)로 인식해 STM에 효율적으로 저장했다. 무작위 배치는 기존 패턴과 맞지 않아 청킹이 불가능했기 때문에 마스터도 일반인과 다를 바 없었다.
코드 읽기도 마찬가지다. 숙련 개발자가 낯선 코드를 빠르게 파악하는 것은 그 코드 안에서 익숙한 패턴 — 팩토리 패턴, 반복자 관용구, 특정 라이브러리의 사용 방식 — 을 청크로 인식하기 때문이다.
청킹의 핵심은 LTM에 있는 패턴 지식이 STM의 용량 제약을 극복하게 해준다는 점이다. for (let i = 0; i < arr.length; i++)를 처음 보는 초보자는 6~7개의 개별 토큰으로 인식하지만, 숙련 개발자는 "배열 순회 관용구" 하나의 청크로 처리한다.
디자인 패턴: 팀 내에서 패턴 이름을 공유하면 그 자체가 하나의 청크가 된다. "싱글턴으로 구현했다"는 한 문장이 여러 줄의 코드를 설명한다.
표식(Beacon): 코드를 읽을 때 특정 개체가 프로그램 구조나 동작에 대한 단서를 제공한다. 함수명 parseConfig, 예외 클래스명 NetworkTimeoutException, // FIXME: 같은 주석이 표식 역할을 한다. 단순 표식(single beacon)은 특정 기능의 존재를 암시하고, 복합 표식(compound beacon)은 여러 요소가 모여 더 큰 개념을 전달한다.
주석: 저수준 주석(변수의 타입을 설명하는 등)은 오히려 코드 가독성을 낮추지만, 코드의 의도나 결정 이유를 설명하는 고수준 주석은 청킹을 돕는다. 유지보수 부담 때문에 주석을 꺼리는 경향이 있지만, 적절한 위치의 주석은 인지 부하를 크게 낮춘다.
독일 심리학자 헤르만 에빙하우스는 1885년 자기 자신을 실험 대상으로 삼아 기억의 망각 곡선을 연구했다. 학습 직후부터 기억이 급격히 소실되다가 시간이 지날수록 감소 속도가 줄어드는 패턴을 발견했다.
오하이오 웨슬리언 대학교의 해리 바릭 연구는 중요한 사실을 추가했다. 짧은 간격으로 자주 반복하는 것보다 긴 간격을 두고 반복하는 분산 학습이 장기 기억에 훨씬 효과적이라는 것이다. 이것이 분산 반복(Spaced Repetition)의 과학적 근거다.
저자는 새로운 언어나 API를 배울 때 플래시카드를 만들어 분산 반복 방식으로 학습하기를 권장한다. 앞면에 함수명이나 개념, 뒷면에 사용법이나 설명을 적는 방식이다. Anki 같은 도구를 활용하면 최적화된 간격으로 복습 알림을 받을 수 있다.
이 전략은 문법 지식의 인출 강도를 유지하는 데는 효과적이지만, 업무 흐름을 자주 중단시키는 비용이 있다. 플래시카드 제작과 복습 자체가 또 다른 인터럽트다. 개인의 학습 스타일과 현재 업무 맥락을 고려해 선택적으로 적용하는 것이 현실적이다.
오스트레일리아 교육심리학자 존 스웰러가 제안한 인지 부하 이론(Cognitive Load Theory)은 작업 기억 공간이 처리할 수 있는 한계를 세 가지 종류로 구분한다.
문제 자체의 복잡성에서 비롯되는 부하다. 재귀 알고리즘이나 동시성 코드는 본질적으로 추적해야 할 상태가 많기 때문에 내재적 부하가 높다. 이는 코드 작성 방식이 아니라 문제 도메인의 특성에서 온다.
문제와 무관하게 외부 요인이 추가한 부하다. 불명확한 변수명, 일관성 없는 코드 스타일, 과도한 추상화 레이어, 사용하지 않는 코드가 남아 있는 경우 등이 외재적 부하를 높인다. 이는 코드 품질로 직접 통제 가능한 영역이다.
새로운 정보를 LTM에 저장하는 과정에서 발생하는 부하다. 이미 알고 있는 패턴에 연결 짓는 정교화(elaboration) 작업이 여기 해당한다. 적절한 수준의 본유적 부하는 학습에 필수적이다.
작업 기억 공간의 총 처리 능력은 고정되어 있다. 외재적 부하를 줄이는 코드 품질 개선이 곧 이해도 향상으로 이어지는 이유다.
저자는 코드를 자신의 인지 수준에 맞게 임시로 다시 작성하는 "인지적 리팩터링(Cognitive Refactoring)"을 제안한다. 람다나 리스트 컴프리헨션처럼 이해하기 어려운 구문을 for 루프로 풀어 쓰는 방식이다.
이 접근에는 동의하기 어렵다. 낯선 문법을 단순화하는 것은 그 문법에 대한 LTM을 쌓지 않겠다는 선택이기도 하다. 더 나은 방향은 해당 구문을 학습해 청크로 습득하는 것이다. 인지적 리팩터링이 의미가 있는 영역은 팀원이 아직 습득하지 못한 구문을 팀 코드베이스에 그대로 남겨두지 않는 팀 수준의 코딩 기준 합의에 있다.
코드가 복잡하게 얽혀 있어 흐름이 보이지 않을 때, 각 변수와 함수가 어떻게 연결되어 있는지를 손으로 그려보는 방법이다. 시각화 자체가 작업 기억 공간의 부담을 외부로 덜어낸다.
반복문이나 재귀가 복잡한 코드를 분석할 때, 각 반복 단계에서 변수들이 어떤 값을 갖는지 표로 추적하는 방법이다. 구조보다 값의 흐름에 집중하게 된다.
의존 그래프와 상태표는 디버거가 해결해주는 영역과 상당 부분 겹친다. 실제로 중단점(breakpoint)을 찍고 단계별로 실행하는 것이 상태표를 손으로 작성하는 것보다 훨씬 빠르고 정확하다. 이 기법들은 디버거를 사용할 수 없는 환경이나, 실행 전에 코드를 완전히 이해해야 하는 상황(예: 코드 리뷰)에서 유용하다.
1부에서 가장 명확하게 가져갈 수 있는 인사이트는 두 가지다. 첫째, 코드 이해도는 LTM에 얼마나 많은 패턴 지식이 저장되어 있느냐에 달려 있다. 이것이 "경험"이 유의미한 인지과학적 이유다. 둘째, 좋은 코드란 읽는 사람의 외재적 인지 부하를 낮추는 코드다. 변수명, 함수 분리, 일관된 패턴 사용이 단순한 취향 문제가 아니라 인지적 효율성의 문제임을 이 관점에서 근거 있게 설명할 수 있다.
이 글이 도움이 되셨나요?