가르치면서 배우기 : 최고의 학습법
2025-03-1310 분 소요0
최근 안드로이드 앱 개발을 해야 할 일이 생겨서, 이래 저래 코틀린(Kotlin) 언어 세미나를 자청해 배운 내용들을 정리하고 내부에 공유하는 작업을 진행하고 있습니다. 그러면서 자연스레 후배 동료분들에게 어떤 식으로 설명을 하는 게 좋을지, 어떤 개념들을 어떤 순서로 말하고 이해하도록 하는 것이 좋을지 고민하게 되었습니다. 그러다 문득, 깨달은 한가지가 있었습니다. 아 내가 안다고 생각했던 것들이 실제로는 제대로 아는 게 아니었구나, 하는 것을요.
변수인데 왜 변경이 안되는 게 있는거지?
코틀린 언어는 저에게 있어서도 생소했고, 부서원들에게도 물론 생소한 언어였습니다. 부서원 대부분은 C++만 사용하고 있고, 그마저도 최근에 조인하신 분은 파이썬으로 과제 정도를 진행해 본 것이 전부인 분입니다. 그래도 저의 경우 TSBOARD 프로젝트를 진행 하면서 Go 언어를 배우고 사용할 기회가 있었고, 타입스크립트(자바스크립트) 언어도 사용해서 그런지 문법이나 개념들이 크게 어려워 보이진 않았습니다. 즉 다른 언어를 사용하면서 무의식중에 체득한 지식들 상당수가 코틀린 언어에서도 그대로 적용된 것입니다. 그래서 처음에는 다른 동료분들에게 제가 배운 내용을 설명하는 것이 그렇게 어려울 거라고 생각하지 못했습니다. 제가 이미 아는 개념이 코틀린에서는 어떤지 파악한 다음, 그 내용을 잘 녹여서 설명하면 될거라고 (안이하게) 생각했던 거죠.
그러나 이 생각이 얼마나 잘못된 것이었는지 코틀린 언어의 변수 부분을 설명하면서 바로 깨닫게 되었습니다. 그나마 C++를 사용하고 있는 동료분들은 C++이라는 비교 대상이 있어서 공통점과 차이점 중심으로 빠르게 학습할 수 있는데, 파이썬만 접한 상황에서 코틀린의 변수 개념을 접할 때는 다소 이해가 안가는 게 있을 거라고 생각하지 못했습니다. 가령 이름이 변수인데 변경 가능한 변수가 따로 있고 변경 불가능한 것이 따로 있는 게 무슨 의미인가? 와 같은 생각을 제가 해본 적이 없었던 것이었습니다. 그저 의례 하는 것처럼 “대충” 다른 언어에 있는 개념이니까 깊게 생각하지 않았었는데, 이러한 의문에 대해 제가 답을 해야 하는 상황이 오자 답변이 막막했습니다. 스스로 굉장히 부끄러웠습니다.
변경 불가능한 변수가 왜 필요한가? 코드를 작성하면서 이후에 잘못된 변경 시도를 방지할 수 있다. 그렇게 했을때 뭐가 좋은가? 의도하지 않은 잘못된 값이 사용 되는 걸 방지할 수 있다. 그 밖에 무슨 장점이 있는가? 컴파일 시점에 이미 값이 변경 안되는 걸 알기에 더 최적화에 용이하다. 또 다른 장점은? 예를 들어 매직 넘버(숫자만 적힌 것)를 의미 있는 이름을 부여해서 사용할 수 있다. 등등…
이전까지 알고 있다고 착각했던 것들은 실제로는 아는 게 아니었습니다. 말 그대로 착각인 겁니다. 변수라는 개념은 프로그래밍 언어를 배울 때 가장 먼저 배웁니다. 하지만 그렇다고 해서 이 변수가 가장 쉽고 간단하기 때문에 먼저 배우는 건 아닙니다. 이 개념을 알아야 그 뒤에 이어지는 제어문이나 함수, 클래스와 같은 개념들을 이해할 때 더 쉽기 때문에 가장 먼저 배우는 것일 뿐입니다. 이름이 변수인데 정작 변경이 안되는 변수에 대한 의문을 깨닫게 되면서, 이런 중요한 걸 이제서야 배우다니! 하는 탄식도 들었습니다.
문은 뭐고 식은 뭔가요?
우리가 통상 제어문을 배울 때 의식하지 않고 “문” 이라고 표현해서 배웁니다. 저도 여지껏 새로운 언어를 배울 때마다 제어문(statement)이라는 단어에 대해서 생소하다는 느낌을 받아본적이 없었습니다. 하지만 이걸 설명하려고 다시 생각을 해보니까, 정확히 이걸 구분해서 생각한 적이 없었다는 생각이 들었습니다.
코틀린은 if나 else 혹은 switch를 대신하는 when이 표현식(expression)입니다. 보통 제어문이라고 배우는데, 코틀린은 아닙니다. if 나 else, when 같은 표현식은 마지막 값이 리턴값이 되어서 변수에 넣을 수가 있거든요. 아주 간단히 생각하면 값 처럼 평가가 되는 겁니다.
fun main() {
val a = 10
val b = 20
// if 표현식
val max = if (a > b) a else b
println("Max: $max") // 출력: Max: 20
// when 표현식
val grade = 85
val result = when {
grade >= 90 -> "A"
grade >= 80 -> "B"
grade >= 70 -> "C"
else -> "F"
}
println("Grade: $result") // 출력: Grade: B
}삼항 연산자가 없는 코틀린이 불편하지 않은 이유도 if 가 표현식으로 값으로 평가되기 때문입니다. 그런데 이 개념, C++만 사용한 동료들에게는 정말 생소한 개념이었습니다. if 가 값처럼 취급된다는 소리가 이해가 안되는 것입니다.
#include <iostream>using namespace std;
int main() {
int a = 10, b = 20;
// if 문 (표현식이 아님, 변수에 직접 할당 불가)
int max;
if (a > b)
max = a;
else
max = b;
cout << "Max: " << max << endl; // 출력: Max: 20
// switch 문 (값을 반환하지 않음)
int grade = 85;
string result;
switch (grade / 10) {
case 10:
case 9: result = "A"; break;
case 8: result = "B"; break;
case 7: result = "C"; break;
default: result = "F";
}
cout << "Grade: " << result << endl; // 출력: Grade: B
}그 때문에 문은 무엇이고 식은 무엇인지에 대해서 다함께 다시 생각해보는 시간을 가지게 되었습니다. 저에게 있어서는 비유를 들자면 C++에서 말하는 lvalue / rvalue를 명시적으로 구분하는 것에 버금가는 배움의 기회였습니다.
코루틴(Coroutine)은 스레드(Thread)에요?
코루틴에 대한 부분을 설명할 때는 정말 저 스스로가 진짜 많이 모른다고 생각이 들었던게, 그냥 스레드인데 가벼운 스레드다! 라고 설명 하자니 너무 축약된 부분이 많다는 점을 알게 되었습니다. 코루틴은 엄밀히 말하자면 스레드가 실행 환경이 되는 것이고, 그 안에서 돌아가는 중단 가능한 객체들을 코루틴이라고 해야 할텐데 이걸 설명하는 것도 쉽지 않았습니다.
그리고 스레드라는 개념도 약간 생소한 상황에서 저런 설명을 들어봤자, 이해가 하나도 안되는 게 사실입니다. 그래서 고민을 하다보니, 아래와 같은 순서로 개념들을 쌓아 나가야 코루틴까지 다다를 수 있겠다는 생각이 들었습니다.
동시성(Concurrency)은 무엇이고 병렬성(Parallelism)은 무엇인가?
기존의 멀티 스레드(Multi Thread) 방식은 무엇이 문제였나?
동기(Synchronous)와 비동기(Asynchronous)의 차이는 뭔가?
블록(Block)과 논블록(Non-Block)의 차이는 뭔가?
그리고 동기와 비동기와의 관계는?
코루틴은 멀티 스레드와 어떻게 다른가?
중단 가능한 객체라는 것은 무슨 의미인가?
코루틴 빌더는 무엇이고 코루틴 스코프는 또 무엇인가?
구조적 동시성이라는 개념은 무엇인가?
메인 스레드와 코루틴이 동작하는 스레드의 차이는 무엇인가?
그리고 코루틴이 동작할 스레드를 바꿀 수 있다는 의미는 무엇인가?
안드로이드에서 쓸 수 있는 코루틴 스코프는 무엇인가? 왜 따로 정의되어 있는가?
코루틴이라는 하나의 개념에 이르기까지 생각보다 많은 개념들을 알아야 한다는 걸 알게 되었습니다. 그냥 막연히 이럴 것이다, 혹은 Go 언어의 고루틴과 비슷한거야, 라고 단정짓는 것은 뇌에 일종의 속임수를 쓰는 것이나 다름 없었습니다. 더 깊게 고민하거나 개념들을 애써 정리하게되면 에너지가 소모 되니까, 에너지를 덜 쓰는 방향으로 그동안 스스로를 속였던 셈입니다.
이 모든 진실들을, 누군가에게 제가 알고 있는 개념이나 배운 내용에 대해서 설명하려고 할 때 비로소 깨닫게 되었습니다. 하나의 개념을 제대로 이해하기 위해서는 생각보다 더 많은 사전 지식이 필요합니다. 대충 설명하는 건 쉽지만 제대로 설명하는 건 어렵습니다. 때론 아주 단순한 하나의 개념 속에도 미처 생각하지 못한 점들이 많이 있었습니다. 겉으로는 제가 누군가에게 지식을 전달하는 단순한 일이었지만, 실제로는 제가 그동안 안다고 착각했던 지식들을 다시 한 번 점검하고, 이면을 깨닫고, 개념을 더 엄밀하게 파악할 수 있는 소중한 기회였습니다.
누군가를 가르친다는 건 실제로는 스스로의 무지를 깨우치는 훌륭한 학습법이라고 생각합니다. 이번 코틀린 언어 학습이 잘 마무리되면 자청해서 다른 프레임워크나 언어에 대한 세미나도 진행해봐야 겠습니다. 😊
