이 책은 목차만 보고 읽기로 결정했는데, 책의 전반부는 코드를 잘 읽는 방법, 후반부는 코드를 잘 작성하는 방법을 다루고 있다. 흥미로웠던 점은 기초적인 뇌과학 원리를 설명하면서, 동시에 프로그래밍을 할 때 어떠한 방식으로 행동해야하는지 여러 연구를 통해 보여준다. 요즘 선배들이 연구했던 코드를 볼 일이 생겨서 틈틈이 보고 있는데.. 시간만 가고 잘 이해가 되지 않았는데.. 흑흑 😭 이 책에서 언급하는 방법들을 통해 처음 보는 코드도 잘 이해할 수 있도록 해봐야겠다
1. 코드 더 잘 읽기
프로그래밍을 하다보면, 마냥 "이해가 안된다" 또는 "어렵다" 는 단순한 혼란이 아닌, 알고보면 서로 다른 3가지 유형의 혼란이 발생한다. 그리고 각 혼란은 뇌의 서로 다른 부분에서 발생한다.
(1) 지식의 부족: 우리는 APL 언어에 대해 알지 못하고, 특히 T 가 의미하는 바를 모르기 때문에 혼란스럽다. = LTM
// APL에서의 이진수 표현
2 2 2 2 2 T n
(2) 정보의 부족: Integer.toBinaryString 이라는 메서드 이름으로 어떤 일을 하는지 유추할 수 있지만, 내부적으로 어떻게 동작하는지에 대한 정보를 얻으려면 메서드 내부 코드를 살펴봐야 한다. = STM
// Java 에서 이진수 표현
public class BinaryCalculator {
public static void main(Integer n){
System.out.println(Integer.toBinaryString(n));
}
}
(3) 처리능력의 부족: 변수에 임시로 저장되는 값 등을 따라가기 위해 머릿속으로만 처리하기 어려워서 종이에 따로 표시 등을 해둬야 한다. = 작업기억공간
// 베이직에서 이진수 표현
LET N2 = ABS(INT(N))
LET B$ = ""
FOR N1 = N2 TO 0 STEP 0
LET N2 = INT(N1/2)
LET B$ = STR$(N1-N2*2) + B$
LET N1 = N2
NEXT N1
PRINT B$
그래서 코드를 잘 읽기 위해서는 뇌의 다양한 부분이 사용되고 있다는 점을 인지하고, 뇌의 각 부분에 대한 특징을 이해해야한다.
우리가 코드를 기억할 때는 짧은 기간동안 정보를 저장하는 STM 과 장기적으로 정보를 저장하는 LTM 이 함께 작용하는데, STM 의 용량이 적고 정보를 저장하는 시간이 짧기 때문에 이해하거나 기억한 정보를 처리할 때는 LTM 과 상호작용한다. 이때 기억 공간에는 `청크` 단위로 저장된다. 청크는 배경 지식에 따라 큰 단위가 될 수도, 작은 단위가 될 수도 있다. 숙련된 프로그래머들은 LTM 에 저장된 익숙한 키워드, 구조, 도메인 개념 등을 활용하여 코드를 이해한다. 실험 결과, 특히 디자인 패턴에 대한 지식을 가지면 청킹 능력이 향상되고, 코드를 빠르게 이해 및 수정 할 수 있었다. 주석도 도움이 될 수 있다.
이 책에서는 쉽게 정보를 찾을 수 있는 환경에서는 문법을 기억하지 않아도 된다는 인식이 발생하여 인출 강도가 약해지고(알긴 아는데 계속 입 안에서만 맴도는 상태), 악순환이 이어진다고 주장한다. 이를 해결하기 위해서는 검색하기 전에 먼저 의도적으로 기억하려고 노력해야 한다.
복잡한 코드를 읽는 일은 작업 기억 공간에 과부하를 일으키기도 한다. 작업 기억 공간은 STM과는 다르게, 정보를 처리하는 프로세서 역할을 한다는 차이점이 있다. 작업 기억 공간 또한 STM 과 마찬가지로 용량(인지 부하)이 정해져있으며, 청크 단위로 이루어진다. 만약 청크 단위로 나뉘지 않는 너무 많은 요소를 가진 문제를 풀려고 하면 과부하가 걸린다.
여기서 말하는 인지부하는 크게 3가지로 나뉘는데,
- 내재적 부하: 문제 자체가 얼마나 복잡한지
- 외재적 부하: 외부적 요인에 의해 문제에 추가된 것
"""
10보다 큰 항목을 선택하는 파이썬 프로그램 = 동일한 내재적 인지 부하 (문제 그 자체)
"""
# List Comprehension 에 대한 배경지식에 따라 외재적 인지 부하가 달라질 수 있다
above_ten = [a for a in items if a > 10]
# 일반적인 for 문
above_ten = []
for a in items:
if a > 10:
above_ten.append(a)
- 본유적 부하: 생각을 LTM 에 저장하는 과정에서 일어나는 인지적 부하
인지 부하를 줄이기 위해서는 리팩터링을 하면 된다. 리팩터링은 코드의 기능은 유지하되, 구조를 개선하는 것이다. 일반적으로는 코드의 유지 보수를 쉽게 하기 위한 목적으로 이루어지지만, 저자는 장기적으로 가독성이 높은 코드를 작성하도록 리팩터링 하는, 인지적 리팩터링도 중요하다고 한다.
그러나 리팩터링을 해도 코드의 구조가 복잡하다면, 예를 들어 정확히 코드의 어디를 파악해야 하는지 모르거나 코드가 서로 밀접하게 연결되어 많은 코드를 읽어야 하는 경우 작업 기억 공간 용량을 초과할 수 있다. 이런 상황에서는 코드 기반으로 의존 그래프 또는 상태표를 만들어 작업 기억 공간을 보조하면 도움이 된다.
프로그램을 깊이 이해하기 위해서는 변수가 중심적인 역할을 하는데, 변수를 파악할 때에는 변수 이름뿐만 아니라 타입과 역할을 살펴보는 것이 도움된다.
앞서 코드를 이해하는데 도움이 되는 의존 그래프 와 상태표를 소개했는데, 이 방식은 다소 국지적이라는 단점이 있다. 코드를 보다 깊게 이해하기 위해서는 텍스트 구조 지식과 계획 지식에 대해 살펴봐야 한다.
- 텍스트 구조 지식: 키워드가 하는 일이나 변수의 역할 등과 같은 프로그램의 표면적인 이해와 관련됨
- 계획 지식: 프로그래머가 프로그램을 작성할 때, 계획한 것이 무엇인지 혹은 무엇을 달성하려고 했는지
뿐만 아니라, 코드가 어떤 구조로 되어 있고 어떻게 연결되어 있는지 살펴봐야 하는데
다음 4가지 단계를 거쳐 표면적 지식으로부터 좀 더 깊은 이해로 진행할 수 있다.
- 프로그램의 시작점(초점, focal point)을 찾는다. ex) main()
- 초점으로부터 지식을 확장 ex) 초점에서 시작해서 변수, 메서드, 클래스 등의 연결 파악
- 관련된 개체로부터 개념 이해 ex) 입력값에 대한 함수의 결과 이해, 클래스가 가지는 필드의 지식 이해 등
- 여러 개체에 걸쳐있는 개념 이해 ex) 제약조건이나 오류 등
코드를 읽을 때에는 모든 라인을 순차적으로 읽기보다는, 전체적으로 스캔 후 함수의 콜 스택을 따라 읽으면 좋다.
2. 코드에 대해 생각하기
지금까지 코드를 읽고 이해하는 데 도움이 되는 방법들에 대해 알아봤으니, 문제를 해결을 위한 통찰력을 얻는 방법에 대해 알아보자. '모델링'은 소프트웨어 설계 결정을 내리는 데 도움이 된다. 상태표, 의존 그래프, 개체 관계도 등 실제 모델이
아니라, 우리가 머릿속에서 생각하는 정신적 모델을 사용하는 것도 문제 해결에 도움이 된다.
- 정신모델: 풀어야 할 문제에 대해 추론하기 위해 사용할 수 있는 작업 기억 공간 내의 추상화
- 방향/무방향 그래프 또는 다양한 형태의 리스트와 같은 자료구조
- 디자인 패턴
- 모델 뷰 컨트롤러와 같은 아키텍쳐 패턴
- 개체 관계도 또는 시퀀스 다이어그램과 같은 도표
- 상태도 또는 페트리 넷과 같은 모델링 도구 등
또한, 이미 배운 지식은 다른 영역에서도 유용하다. 이를 학습 전이와 학습 도중 전이라고 한다.
그림과 같이 새로운 정보를 습득하면, 먼저 감각 기억 공간과 STM에 의해 처리되며 작업 기억 공간으로 전송된다. 작업 기억 공간은 이에 대해 생각하는 동시에 LTM에서 관련 정보를 검색하여 가져온다. 그래서 자바를 알고 있는 상태에서 파이썬 메서드에 대해 배우면 조금 다르게 동작하더라도 파이썬 메서드에 대해 더 빨리 학습할 수 있는 것이다.
- 저도 전이: 자동화된 기술을 이전하는 것 ex) Ctrl+C, Ctrl+V
- 고도 전이: 복잡한 작업이 전이되는 것 ex) 프로그래밍 시 변수를 사용하려면 먼저 선언을 해야한다고 생각하는 것
- 근거리 전이: 서로 가까운 영역 사이에서 지식이 전이되는 것 ex) 미적분학과 대수학
- 원거리 전이: 서로 먼 영역 간에 일어나는 전이 ex) 라틴어와 논어학
그렇다고 해서 전이가 항상 도움되는 것은 아닐 수 있다.
- 긍정적 전이: 무언가를 알고 있어 새로운 작업을 할 때 도움이 되는 전이
- 부정적 전이: 기존 지식이 새로운 것을 배우는 데 방해가 되는 경우
긍정적 전이가 일어나면, 새로운 상황에 대한 정신 모델을 처음부터 만들 필요 없이 LTM에 저장된 정신 모델을 부분적으로 활용하여 형성할 수 있다. 그러나 이미 알고 있던 지식이 새로운 지식을 배울 때 유사하지 않음에도 불구하고 비슷하다고 인식될 경우 오개념을 발생시킬 수 있는데, 이러한 상황을 부정적 전이라고 한다. 예를 들어 자바에서는 변수를 초기화하지 않으면 사용할 수 없지만, 파이썬에서는 이러한 가정이 혼란을 야기할 수 있다. 오개념을 방지하는 데 코드베이스 내의 테스트와 문서화가 도움이 된다.
3. 좋은 코드 작성하기
좋은 코드를 작성하기 위해서는 변수, 클래스 및 메서드 등 코드 내 구성 요소들에 이름을 잘 명명하는 것이 중요하다. 변수명은 그자체로 코드를 설명하는 주석문처럼 작용하기도 하며, 초기에 부여한 이름이 대부분 유지되기 때문이기도 하다.
좋은 변수명을 인지적 관점으로 바라보면, 의미가 담긴 구성요소가 명확한 이름이라고 할 수 있다. 1부에서 배운대로 변수명을 읽을 때는 각 부분을 분할하고, 작업 기억 공간으로 전송될 때 각 부분과 관련된 정보를 LTM에서 검색하여 작업 기억 공간으로 전송한다.
이 책에서는 더 나은 변수명을 위해 페이텔슨은 3단계 모델을 제시하고 있다.
- 이름에 포함할 개념을 선택: 의도를 고려하여 개체가 어떤 정보를 보유하고 있으며 무엇을 위해 사용되는지 나타낸다.
- 각 개념을 나타낼 단어 선택: 일관성 있는 단어를 사용한다.
- 단어들을 사용하여 이름 구성: 자연어에 맞추어 이름 틀을 사용 ex) points_max (x), max_points (o)
주의할 점은 클린 코드를 위반하는 구조적 안티패턴뿐만 아니라 언어적 안티패턴도 고려하여 이름을 지어야 한다는 점이다. 이러한 안티패턴은 우리 뇌에 혼란을 초래하여 인지 부하를 일으킬 수 있다.
좋은 코드를 작성하면서 어려운 문제를 해결하는 것은 LTM을 강화하는 것이 가장 도움 된다. 문제 해결은 문제 이해, 계획 수립, 계획 실행 단계로 구성되며, 각 단계에서 LTM이 중요한 역할을 한다. 뿐만 아니라 LTM에 저장된 다양한 유형의 기억이 문제 해결을 돕는데 기여한다.
- 절차적(암시적) 기억: 운동 능력이나 의식하지 않고 발휘하는 기술로, 반복 연습에 의해 형성된다. ex) 단축키, 괄호를 열면 자동으로 괄호를 닫는 코드 작성 등
- 선언적(명시적) 기억: 기억할 수 있는 사실이 있고, 그 사실을 자신이 알고있다는 것도 안다. 명시적 기억은 명시적 주의가 필요하다.
- 일화적 기억(경험): 과거에 문제를 어떻게 해결했는지 기억할 때 사용된다. 전문가들은 주로 익숙한 문제를 '해결' 하기보다는 '재현'한다. 즉 새로운 해결책을 찾는 대신 이전에 유사한 문제에 효과가 있었던 해결책에 의존하는 경향이 있다. ex) 계층 구조와 관련된 문제를 해결할 땐 트리를 사용했었지~
- 의미적 기억(사실):
- 일화적 기억은 추가적인 노력을 하지 않아도 생성되지만, 의미적 기억과 마찬가지로 기억을 많이 생각해야만 인출 강도가 높아진다.
위 기억 분류에 따르면 암시적 기억은 작업을 신속하게 실행하는데 도움이 됨을 알 수 있으며, 암시적 기억이 형성되기 위해서는 인지 단계, 연상 단계, 자율 단계가 필요하다.
- 인지 단계: 새로운 것을 배우는 때로, 새로운 정보를 더 작은 부분으로 나누고 당면한 작업에 대해 명시적으로 생각한다. ex) 배열의 인덱스는 0부터 시작하니까, 인덱스 3인 원소는 4번째 원소구나!
- 연상 단계: 응답 패턴이 나타날 때까지 새 정보를 적극적으로 반복한다. ex) 인덱스를 계산할 때는 항상 1을 빼면 되네!
- 자율 단계: 기술을 자동화 한 상태로, 인지 부하가 증가하지 않는다. ex) 리스트와 리스트 연산을 마주하면 숫자를 세거나 명시적으로 생각하지 않고도 인덱스를 즉시 알 수 있는 상태
문제 해결 능력을 향상시키는 또 다른 방법은 본유적 부하이다. 프로그래밍 능력을 향상시키기 위해 모든 프로그램을 처음부터 작성하는 것이 중요하다고 생각하는 사람들도 있지만, 연구 결과에 따르면 다른 사람이 작성한 코드를 읽고 해당 코드를 분석하는 것이 프로그래밍 능력 향상에 도움이 될 수 있다고 한다. 이는 작업 기억 공간의 인지 부하(본유적 부하)와 관련 있다.
작업 기억 공간의 내용이 LTM 에 다시 저장되기 위해서는 본유적 부하가 뒤따른다. 그러나 작업 기억 공간의 부하가 너무 많으면 결과가 LTM으로 옮겨지는 것이 어려울 수 있다. 따라서 본인만의 힘으로 프로그래밍 구현을 연습하는 것은 물론 실력이 향상되지만, 내재적 부하와 외재적 부하로 인해 본질적 부하가 부족할 수 있다. 다른 사람의 코드를 읽을 때는 인지 부하가 그렇게 높지 않으므로 코드 구조를 자세히 검토하고 이를 기억할 수 있게 된다. 따라서 프로그래밍 실력을 향상시키기 위해서 GitHub 탐색, 오픈 소스 코드 분석 등을 통해 코드를 연구하는 것이 유용하다.
4. 코딩에서의 협업
실제로 소프트웨어는 팀에 의해 개발되므로 동료와 함께 몰입하며서 코드를 작성하는 것이 중요하다. 특히 다른 사람들과 함께 작업할 때는 업무 중단이 흔하고 다시 돌아와 원래 하던 업무를 계속하기가 어려운데, 어떻게 하면 중단에 더 잘 대비할 수 있을까?
- 정신 모델 저장(brain dump): 정신 모델은 중단으로부터 복구하는데 유용할 수 있으므로 정신 모델에 대한 메모를 주석문으로 남기는 것이 도움된다. 코드는 프로그래머의 사고 과정을 모두 설명하진 못하므로 코드에 특정 접근 방식을 선택한 이유, 코드의 목표 또는 구현을 위해 고려한 다른 대안과 같은 내용은 주석으로 남겨두면 좋다.
- 미래 기억 향상: 미래 기억은 미래에 무언가를 할 것에 대한 기억으로, to-do 주석문 등을 활용할 수 있다.
- 하위 목표 라벨링: 문제를 어떤 작은 단계로 나눌 수 있는지 명시적으로 기록함으로써 업무가 중단된 후 하던 업무를 계속할 때 자신의 생각을 정리하는데 유용하다.
후기
뇌가 코드를 처리하는 방식에 대해 새롭게 알 수 있었다.
저자가 LTM의 중요성에 대해 정말 많이 강조하고 있어서 그동안 모르면 구글링 하면 되지~ㅋ 하고 대수롭지 않게 생각했던 나를 반성함 🥲
새로운 코드를 읽을 때는 왠지 집중도 안되고 코드 분석도 어려워서 그냥 ADHD인줄 알았는데,,,
이 책을 읽고나서부터는 여기 나오는 방법대로 새로운 코드를 마주칠 때 잘 대처할 수 있을 것 같다.
4부도 딱히 정리는 안했지만 흥미로웠던 부분이, 사람은 멀티태스킹이 안된다고 한다. 그런데 멀티태스킹을 하는 사람들은 자신이 매우 생산적이라고 느낀다고 한다...!! 그들 자신의 수행능력이 만족스럽다고 느끼지만, 실상은 한가지 일만 하는 사람들에 비해 결과도 좋지 않고 시간도 오래쓴다는 것이다
아무튼 뇌의 행동 기반으로 인간이 왜 이렇게 되는지 설명해줘서 좋았고, 사회 과학 분야에서 이루어진 실험과 함께 예시를 들어줘서 이해가 쉬웠다. 앞으론 학교에서 수업을 듣거나.. 시험공부하거나.. 연구할땐 이 책 내용을 떠올리면서 의식적으로 노력해야겠다.
'책을 읽자 > 간단한 후기' 카테고리의 다른 글
대학원생 때 알았더라면 좋았을 것들 & 그렇다면 실험실 죽순이가 될 수밖에 후기 (2) | 2023.02.27 |
---|---|
Building Machine Learning Powered Applications 후기 (0) | 2022.11.14 |
CPython 파헤치기 후기 (0) | 2022.10.21 |
TDD(테스트 주도 개발) 후기 (0) | 2021.02.12 |