2025.12.14 - [잡다한 지식] - 인지부하가 핵심입니다(Cognitive load is what matters) 를 읽으며 - 1편
인지부하가 핵심입니다(Cognitive load is what matters) 를 읽으며 - 1편
https://github.com/zakirullin/cognitive-load GitHub - zakirullin/cognitive-load: 🧠 Cognitive load is what matters🧠 Cognitive load is what matters. Contribute to zakirullin/cognitive-load development by creating an account on GitHub.github.com 이 글
seungsang.tistory.com
1편은 저의 경험담과 더불어 인지부하에 대해 간단히 알아봤습니다.
코드에서의 인지부하 사례에 대해서 조금 더 알아보겠습니다.
이번에도 https://github.com/zakirullin/cognitive-load 글을 참고하여 작성하였습니다.
복잡한 조건문
if val > someConstant // 🧠+
&& (condition2 || condition3) // 🧠+++, 이전 조건은 참이어야하고, condition2 또는 condition3 중 하나는 참이어야 함.
&& (condition4 && !condition5) { // 🤯, 계속된 조건식과 조건식안에 다양한 연산 문자들이 들어가면서 복잡해짐..
...
}
이렇게 If 문이 중첩되어있다면, 특정 조건을 한눈에 알아보기 힘듭니다.
!condition5 와 같이 조건에 부정 연산이 섞이면,
뇌가 조건을 한 번 더 뒤집어서 생각해야 하므로 인지 부하가 들어갑니다.
그래서 우리는 의미있는 이름을 가진 추가 변수를 사용하여 복잡성을 숨겨야 합니다.
isValid = val > someConstant
isAllowed = condition2 || condition3
isSecure = condition4 && !condition5
// 🧠, 변수가 이미 의미를 표현하기 때문에 조건을 기억하지 않아도 됨.
if isValid && isAllowed && isSecure {
...
}
중첩된 IF 문
if isValid { // 🧠+, '유효한' 입력일 때만 통과
if isSecure { // 🧠++, '유효'하고 '안전한' 입력만 통과
stuff // 🧠+++
}
}
위 코드는 stuff 를 읽는 순간에도 이 코드가 isValid 이면서 isSecure 일 때만 실행된다는 것을 끊임없이 기억해야 합니다.
이러한 코드는 조기반환으로 변경합니다.
if !isValid
return
if !isSecure
return
// 🧠, 조기반환은 신경쓰지 않고, 코드가 여기까지 실행됐다면 모든게 Good 임.
stuff // 🧠+
개발자는 메인 로직(stuff)에 도달했을 때,
"이전에 설정된 모든 전제 조건이 이미 충족되었다"는 것을 의식적으로 확인하지 않아도 됩니다.
코드에 대한 확신을 가지고 가장 중요한 작업(stuff)에만 집중할 수 있습니다.
또한 조기 반환은 중첩된 들여쓰기(Indentation)를 만들지 않기 때문에,
코드가 오른쪽으로 깊어지지 않고 평탄하게 유지되어 읽기가 훨씬 쉽습니다.
(에디터에서 좌우 스크롤 할 필요가 없습니다)
상속의 악몽
"AdminController extends UserController extends GuestController extends BaseController"
AdminController 는 수많은 Controller 를 상속합니다.
각 컨트롤러를 수정하기 위해 개발자는 자신이 위치한 클래스의 모든 부모 클래스를 알아야합니다.
각 부모 클래스의 해당 기능이 어떻게 구현되고, 수정되었는지 모두 파악하고 기억해야 합니다.
가장 하위 클래스인 AdminController 를 건드리기 위해서는,
그 위의 4개 계층을 모두 이해해야 하는 엄청난 인지부하를 경험해야합니다.
이런 경우에는, 구성(Composition)이나 믹스인(Mixins) 패턴을 사용하여 해결하는 것이 좋습니다.
상속은 'IS-A(이것은 ~이다)' 관계일 때만 사용하고,
'HAS-A(이것은 ~을 가지고 있다)' 관계는 구성(Composition)을 사용해야 합니다.
믹스인(Mixin) 패턴은 기능을 역할별 인터페이스(믹스인)로 분리하고 필요한 컨트롤러에 명시적으로 연결하여,
깊은 상속 없이 코드를 재사용합니다.
너무 작은 함수, 클래스/모듈
"함수는 5줄 이하여야한다." 같은 주장을 많이 접합니다.
추상화 레벨을 분리하고, 단일 책임 원칙을 준수하고, 테스트를 용이하게 해줍니다.
하지만, 얕은 모듈이 많아지면 프로젝트를 이해하기 어려워질 수 있습니다.

너무 잘게 쪼개져 있다면 각 모듈의 책임뿐 아니라,
각 모듈들간의 상호작용도 고려해야 합니다.
이는 복잡성을 그다지 많이 숨기지 못하는 결과를 만들기도 합니다.
또한 얕은 모듈 자체만으로는 명확한 목적을 가지기도 어렵습니다.
우린 복잡한 내부 구현을 숨기고 단순하고 명확한 인터페이스만 외부에 노출해야 합니다. (높은 응집도, 낮은 결합도)
"외부인터페이스는 작고 단순하지만, 내부 구현은 크고 복잡한 깊은 모듈을 사용하도록 해야합니다."
유닉스의 I/O 의 인터페이스는 아래 다섯가지만 있습니다.
open(path, flags, permissions)
read(fd, buffer, count)
write(fd, buffer, count)
lseek(fd, offset, referencePosition)
close(fd)
이 인터페이스 뒤에는 수십만 줄의 코드가 있습니다.
내부에 복잡성이 숨겨져 있고 간단한 인터페이스를 제공하기 때문에 사용하기 쉽습니다.
한 가지 책임
"모듈은 한 가지 일에만 책임져야 한다."는 원칙들에 따라 얕은 모듈을 만들게 됩니다.
여기서 '책임'은 단순히 '하는 일'이 아니라, '변경의 이유'로 해석해야 합니다.
모듈은 한 명, 오직 한 명의 사용자 또는 이해 관계자(Actor)에게만 책임져야 합니다.
그리고 너무 얕아서 여러 구성요소를 오가는 것보다,
쭉 내려갈 수 있는 선형적 사고가 인간에게 더 자연스럽습니다.
선형적 사고에 대한 인사이트는 아래의 글을 참고하세요.
2025.12.13 - [잡다한 지식] - 코드 가독성의 딜레마: 쪼갤 것인가, 흘려보낼 것인가? - Part 1. 추상화 수준 일치
코드 가독성의 딜레마: 쪼갤 것인가, 흘려보낼 것인가? - Part 1. 추상화 수준 일치
Part 1. 읽기 좋은 코드를 만드는 비결: 추상화 수준 일치시키기우리는 "돌아가는 코드"를 짜는 것을 넘어 "읽기 좋은 코드"를 짜기 위해 끊임없이 고민합니다.코드를 작성하는 것보다 기존 코드를
seungsang.tistory.com
2025.12.13 - [잡다한 지식] - 코드 가독성의 딜레마: 쪼갤 것인가, 흘려보낼 것인가? - Part 2. 선형 코드
코드 가독성의 딜레마: 쪼갤 것인가, 흘려보낼 것인가? - Part 2. 선형 코드
Part 2. 때로는 '선형 코드(Linear Code)'가 더 읽기 쉽다SOLID 원칙의 첫번째인 "하나의 함수는 한 가지 일만 해야한다(SRP)" 는 많이 들어보셨을 겁니다.그래서 "함수는 작게 만들어라", "한 함수는 한 가
seungsang.tistory.com
2025.12.13 - [잡다한 지식] - 코드 가독성의 딜레마: 쪼갤 것인가, 흘려보낼 것인가? - Part 3. 추상화와 선형코드 사이에서 균형 잡기
코드 가독성의 딜레마: 쪼갤 것인가, 흘려보낼 것인가? - Part 3. 추상화와 선형코드 사이에서 균형
2025.12.13 - [잡다한 지식] - 코드 가독성의 딜레마: 쪼갤 것인가, 흘려보낼 것인가? - Part 1. 추상화 수준 일치2025.12.13 - [잡다한 지식] - 코드 가독성의 딜레마: 쪼갤 것인가, 흘려보낼 것인가? - Part 2.
seungsang.tistory.com
너무 많은 얕은 마이크로서비스 (Too many shallow microservices)
세상의 많은 서비스들이 마이크로서비스로 동작합니다.
FAANG 같은 대기업이 사용하는 방식을 작은 팀이 따라하는것이 맞는지 확인해야합니다.
(대규모 시스템에서 사용하는 방식을 바로 적용하는 것은 오버엔지니어링일 수 있습니다)
시스템의 크기에 따라 모놀리스식 사용할지 마이크로서비스를 도입할지 고민해봐야합니다.
함수 호출이 네트워크 호출로 바뀌는 순간, 개발자가 감당해야할 인지 부하는 급격하게 늘어납니다.
이론적으로 좋아보이는 마이크로 커널보다 실용적인 모놀리스 리눅스가 세상에서 더 널리 사용되는 이유를 생각해볼 필요가 있습니다.
처음부터 시스템을 프로젝트 안에서 코드를 모듈화하는 모듈러 모놀리스로 시작하는 것이 훨씬 현명합니다.
내부 정리만 잘해두면 관리가 훨씬 쉽게 유연하기 때문입니다.
팀이 커져서 배포를 따로 해야할 만큼 중요해졌을 때 쪼개도 늦지 않습니다.
기능이 풍부한 언어
언어의 새로운 기능이 출시될 때 기능을 배우는데 시간을 보냅니다.
그리고 단지 그 기능을 써보고 싶다는 이유로, 굳이 필요 없는 곳에 적용하기도 합니다.
React에서 지금 당장 필요하지도 않은 최신 훅(Hook)이나 복잡한 패턴을 적용한다고 생각해봅시다.
(현재 사용하지 않아도 되는 프레임워크의 기능을 오버엔지니어링으로 추가할 수도 있습니다.)
나중에 이 코드를 다시 봤을 때, "도대체 왜 이렇게 짰지?"를 이해하기 위해 우리는 불필요한 사고 과정을 거쳐야 합니다.
우리는 이 복잡한 프로그램을 이해해야 할 뿐만 아니라,
프로그래머가 사용 가능한 수많은 기능 중에서 왜 하필 이 방식으로 문제에 접근했는지까지 역추적해야 합니다.
우리는 선택의 수를 제한하여 인지부하를 줄여나가야 합니다.
다음번 포스팅은 남은 추가사례를 소개해드리겠스빈다.
'잡다한 지식' 카테고리의 다른 글
| 소프트웨어 개발하는 방법 1편 - 요구사항 (0) | 2026.02.19 |
|---|---|
| 인지부하가 핵심입니다(Cognitive load is what matters) 를 읽으며 - 3편 (0) | 2025.12.16 |
| 인지부하가 핵심입니다(Cognitive load is what matters) 를 읽으며 - 1편 (0) | 2025.12.14 |
| 코드 가독성의 딜레마: 쪼갤 것인가, 흘려보낼 것인가? - Part 3. 추상화와 선형코드 사이에서 균형 잡기 (0) | 2025.12.13 |
| 코드 가독성의 딜레마: 쪼갤 것인가, 흘려보낼 것인가? - Part 2. 선형 코드 (0) | 2025.12.13 |