프로그래머에게 지속적인 학습은 기본적으로 갖춰야 할 덕목 중 하나라고 생각합니다. 문제를 해결하는 방법들은 계속 발전하고 변해가며 하나를 배우면 오히려 배울 것이 늘어나는 경험을 항상 합니다. 당장 우아한형제들의 구성원을 봐도 직급이나 연차와 상관없이 아침, 점심시간을 아껴 공부하는 모습이 낯설지 않습니다.

하지만 익혀야 할 것은 무수히 많고 시간은 한정되어 있습니다. 따라서 어떤 것을 먼저 할지 우선순위를 정하고, 선택하고, 집중해야 합니다. 그것도 아주 효과적인 방법으로요.

사실 저는 지난 몇 달간 비효과적인 방법으로 시간을 낭비했습니다. 이 글에서 제가 학습하고, 학습에 실패한 경험을 공유합니다.

study

무엇을 잘못했나?

막연한 목표 설정

올해 초, 업으로서 프로그래밍을 시작한 지 1년쯤 될 때입니다. 개인적인 할 일, 공부할 것, 읽어보고 싶은 책들은 큐Queue에 쌓아 두고 관리 합니다.

my-queue

그 당시에도 여러 주제가 쌓여 있었고 큐의 전방front에는 객체지향 프로그래밍이 있었습니다. 그래서 그 능력을 향상하겠다는 목표로 본격적인 학습을 시작했습니다.

너무 막연하고 두리뭉실하며 학습의 성과를 측정하기 힘든 목표였습니다.

편안한 학습법

평소 책을 통한 지식 습득을 선호합니다. 주제를 정하면 그것과 관련된 여러 책을 연속해서 찾아봅니다. 역시 하던 방식대로 학습을 시작했습니다. 객체지향 프로그래밍에 관련된 책들을 찾아서 읽어 보고 책의 예제를 따라 했습니다. 유튜브 같은 곳에서 관련 강의를 찾아보기도 했습니다. 지금 생각해보면 단순히 읽고 반복하는 편안한 방식의 학습이었습니다.

그렇게 한 달, 두 달, 석 달… 문득 이런 생각이 들었습니다.

내가 제대로 하고 있는 건가?

하지만 어떤 입력에 대해 출력이 있는 것처럼 명확한 답이 있는 주제가 아니었기에 현재 상태를 측정하기 힘들었습니다.

진척도를 측정하기 힘든 학습 목표, 끝이 정해져 있지 않은 학습 과정.

시간이 좀 더 흘러서는 자신도 뭘 하고 있는지 몰랐고 지루해지기 시작했습니다. 그러면서도 아직 부족 하다는 생각에 시간만 질질 끌기 시작했습니다.

무언가 완전히 잘못하고 있다

꽤 많은 시간을 어영부영 흘려보내다 문득 이런 생각이 들었습니다. 그러자 더 학습을 진행하는 것은 힘들었습니다. 읽던 책, 학습하던 것 모두 중단한 후 며칠을 온전히 놀았쉬었고 그 후, 효과적인 학습 방법을 찾기 시작했습니다. 그때, 의식적인 연습이 떠올랐습니다. 주변의 괜찮은 프로그래머라고 생각한 분들이 한 번씩 언급했지만, 이전에는 관심 두지 않던 키워드입니다.

의식적인 연습

책 ‘1만 시간의 법칙’에 의식적인 연습이라는 표현이 등장합니다. 재능보다 노력이 중요한데 이 노력과 성실함에도 전략이 필요하다고 합니다.

이를 설명하기 위해 많이 인용하는, 걷기로 역시 예를 들자면 우리는 태어나서 부모님의 도움과 많은 연습을 통해서 걸을 수 있게 됩니다. 이렇게 스스로 직립 보행을 할 수 있게 된 후 마냥 30년을 더 걷는다면 걷기 1년 차 보다 발의 피로를 줄이는 효과적인 발 디딤과 효율적인 호흡을 하며 걸을 수 있을까요? 만약 팔자걸음이 습관에 베였다면 마냥 많이 걸어서 걸음걸이가 저절로 교정 될까요?

이는 걷기, 테니스 그 외의 무엇에도 적용됩니다. 만족하고 기계적으로 할만한 수준에 도달하게 되면 더 발전을 멈춥니다. 즉, 단순히 행위를 반복하는 것은 연습이 되지 않으며 실력이 늘지 않습니다. 노하우가 쌓일 뿐이죠. 자신의 약점을 고치려고 의식적으로 노력해야 합니다. 김창준 애자일 코치님의 ‘프로그래밍 어떻게 공부할 것인가’ 강의에서 업무와 놀이는 연습이 아니라고 말합니다.

Work != Deliberate Practice != Play

hard-working

집중하고 고치고 반복하라 이 세 가지가 의식적인 연습의 핵심 키워드입니다. 의식적인 연습은 다음과 같은 특징을 가집니다.

  • 널리 알려지고 통용되는 효과적인 훈련 기법을 통해 기술을 연마한다.
  • 자신의 현재 능력을 살짝 넘어서는 작업을 지속적으로 시도해야 한다.
  • 명확하고 구체적인 목표를 가지고 진행된다.
  • 신중하고 계획적이다.
  • 피드백이 있고 피드백에 따른 행동 변경을 수반한다.
  • 효과적인 심적 표상을 만들어 내고 거기에 의존한다.
  • 기존에 습득한 기술의 특정 부분을 집중적으로 개선함으로써 이를 한층 발전시키거나 수정하는 과정이 수반된다.

프로그래밍 의식적 연습하기

programming

기존에 했던 방법을 돌아보면 구체적이지 못한 목표를 세우고 단순 반복적으로 읽는 학습 방식을 취했으며 성과를 측정할 방법이 마땅치 않았습니다.

단순히 많은 시간을 들여 꾸준히 한다면 실력이 늘 것으로 생각했지만 의식적인 연습 방법들은 이제까지 해왔던 방법들과 조금 달랐습니다. 따라서 앞으로 의식적으로 교정하려는 것은 다음과 같습니다.

학습 시작 전에 구체적인 계획과 목표 세우기

결심에는 두 가지 종류가 있다고 합니다. 목표 의도Goal Intention와 실행 의도Implementation Intention입니다. 목표 의도는 “살을 빼겠다”와 같은 결심이고 실행 의도는 “매일 달리기를 해서 두 달 안에 5kg 빼겠다”와 같이 구체적인 실행방법을 포함한 결심입니다.

객체지향 프로그래밍을 학습하기로 했다면 이 목표는 다시 (1) 만들고자 하는 주제를 정한 후, 그 안에서 객체들을 추출해본다. 그리고 각 객체에 책임을 할당하고 서로 협력하도록 프로그램을 작성해본다 (2) 회사 코드에 객체지향 생활체조 규칙을 적용해본다 (3) 한 달 전에 작성한 코드를 객체지향적으로 리팩토링해본다 와 같이 구체적인 실행 계획과 기간을 포함한 세부 목표로 나눠 실천할 수 있을 것입니다.

단순 타이핑 하지 않기

책의 예제를 쉽게 따라 하기 위해 화면의 반은 코드 작성 도구, 나머지 반은 전자책을 띄워놓는 경우가 많았습니다. 하지만 이런 식의 학습법은 단순히 받아 적기, 옮겨 적기밖에 안 된다고 생각됩니다. 인출연습Retrieval Practice을 해야 합니다. 단순히 반복해서 하거나 읽는 것은 장기 기억에 비효율적입니다. 공부한 내용을 일정한 주기로 인출 혹은 회상하는 것이 기억을 강화하고 망각을 막아준다고 합니다. 따라서 책을 통해 학습한다면 한번 전체적으로 살펴본 후, 코드를 작성하는 일은 최대한 스스로 하려 합니다.

일정 주기로 반복하기

한 달 또는 일정 주기로 이전에 학습했던 내용을 다시 학습해 보는 것은 장기 기억에 도움이 된다고 합니다. 이전에 풀었던 알고리즘 문제를 다시 풀어보거나 작성했던 코드를 개선해보려 합니다.

부숴도 좋은 장난감 만들기

많은 사람이 프로그래밍을 효과적으로 학습하기 위해서 개인 프로젝트를 많이 하라고 했습니다. 하지만 항상 주제 선정의 어려움을 겪어 선호하지 않는 방법이었습니다. 주제를 정한다 하더라도 너무 목표만 높이 잡아 계획만 세우다 끝나는 일이 다반사였습니다. 효과적인 학습 방법을 조사하며 왜 많은 사람이 이 방법을 권했는지 조금 이해하게 됐습니다.

하나의 프로그램을 만드는 과정은 많은 실행 오류들을 겪게 되고 자신의 노력을 끌어내게 됩니다. 이를 바람직한 어려움Desirable Difficulties이라고 하는데 적절한 학습의 난이도는 더욱 탄탄한 학습으로 이어집니다. 또한, 이렇게 작성된 프로그램은 다른 용도로 또다시 활용될 수 있습니다. 이런 프로그램들은 언제든 바꾸고 부술 수 있는 장난감이기 때문에 새 기능을 마음대로 추가하고 다양한 방식으로 리팩토링해 볼 수 있는 놀이터play ground로 활용할 수 있습니다.

앞으로 주제는 너무 거창하게 정하지 않으려 합니다. 연습을 위해 하는 프로젝트에서 너무 멋진 프로그램을 만들려고 하기보다 당장 내가 필요한 작은 프로그램으로 시작해 보는 것이 좋겠습니다.

피드백을 받을 방법과 피드백에 따른 교정

프로그래밍 학습의 피드백은 작성한 프로그램을 실행해 동작을 살펴보는 방식을 취할 수 있습니다. 하지만 이는 프로그램이 어느 정도 완성이 되어야 가능하기에 피드백이 너무 늦어질 수 있습니다. 학습에 TDDTest-Driven Development 방식을 취한다면 좀 더 작은 단위로, 좀 더 빠르게 피드백을 받을 방법이라고 생각합니다.

객체지향설계나 좋은 코드에 대한 피드백은 어떻게 받을 수 있을까요? 일단 가장 쉽고 낮은 수준의 피드백은 정적분석 도구를 활용하는 것입니다. 학습을 위해 작성한 코드에도 정적 분석 도구를 적용함으로써 아주 기본적인 피드백을 받을 수 있습니다. 또 한 가지 방법은, 많이 알려진 주제를 선택하는 것입니다. 예를 들어 TDD를 연습한다면 볼링게임이나 계산기 만들기를 주제로 정하는 것입니다. 이런 주제들은 잘 알려져 다른 사람의 코드를 많이 찾을 수 있습니다. 스스로 코드를 작성해본 후, 다른 코드와 비교해보는 방법을 취할 수 있습니다.

사실 가장 좋은 방법은 다른 개발자의 리뷰를 받는 것으로 생각합니다. 상대에게 너무 부담을 주지 않는 선에서 이런 부탁을 한다면 리뷰를 통해 또 다른 토론을 이끌어낼 수 있고 이런 토론들이 생각을 더 확장 시켜줄 것입니다. 스터디 모임에 참여하는 것도 좋은 방법일 수 있겠네요.

왜 공부하는가

글의 서두에서 지속적인 학습은 프로그래머의 기본 덕목이라고 적었습니다. 그리고 효과적인 학습을 위한 방법들을 정리해보았는데요. 한가지 놓친 것이 있었습니다. 우리는 왜 공부해야 하나요?

최종 목적지가 확실해야 가끔 딴 길로 새더라도 결국 그 방향을 향해 갈 수 있을 것 같습니다. 더 나은 커리어 패스를 위해서? 돈을 많이 벌기 위해서? 배움 그 자체의 즐거움으로? 개개인의 목표는 다를 수 있고 각 목표는 존중받아야 합니다.

저는 돌이켜보니 어느 순간 학습을 위한 학습을 하고 있었습니다. 뛰어난 동료들, 그럼에도 꾸준한 자기계발. 그런 분위기 속에서 어떤 목표를 위한 학습이 아니라 단지 ‘학습해야 한다!’라고 자신을 압박만 했습니다. 처음 프로그래밍을 접한 후 프로그램을 동작시키기 위해 공부해야 했습니다. 그 목표를 어느 정도 스스로 이룰 수 있게 된 후 항상 머릿속에 담고 있던 것은 ‘잘 작동하는 깔끔한 코드 (Clean code that works) ‘이고 그것을 실천하기 위해 노력하는 과정이 즐거웠습니다. 참 간결한 문장이지만 서비스는 계속해서 성장하고 있고 그만큼 늘어나는 트래픽과 트랜잭션을 처리할 수 있어야 합니다. 또, 더 높은 사업적 목표를 달성하기 위해서 소프트웨어는 계속 함께 자라나야 합니다. 그 과정에서 좋은 품질도 유지하는 일은 절대 만만치 않은 일입니다.

정리하자면 저는 결국 프로그램은 잘 동작하고 코드는 사람이 이해하기 쉽도록 작성하기 위해 학습한다고 정리했고, 이 목표는 학습의 우선순위 등을 정할 때 가장 먼저 고려 될 부분이 될 것입니다.

사실 실패하지 않았다

노력과 학습이 뇌를 변화시키고 지적 능력이 자신의 통제에 크게 의존한다는 점을 이해하도록 도움을 받은 사람들은 어려운 도전에 착수하고 꾸준히 버틸 가능성이 더 높다. 이들은 실패를 무능력의 표시이자 막다른 길이라고 생각하는 대신 노력의 표시이자 전환점으로 여긴다. (중략) 실패는 숙달된 상태로 가는 데 필수적인 경험이 된다.

-어떻게 공부할 것인가, 헨리 뢰디거, 마크 맥대니얼, 피터 브라운 저, 김아영 역, 와이즈베리 2014

학습에 실패한 이야기라는 제목으로 시작했지만 사실 스스로 실패라 생각하지는 않습니다. 이전에는 단순히 많은 시간을 들여 많이 읽는, 어쩌면 너무 편안한 학습 방법을 취해왔습니다. 지금이라도 이렇게 학습 방법에 대해 돌아보고 교정할 수 있는 시간을 가져 다행입니다. 위에 나열한 방법들은 절대적인 방법들이 아닙니다. 학습하고자 하는 주제, 개인의 성향에 따라 방법은 무궁무진할 수 있습니다. 다만 기존에 하던 방법보다 더 효율적인 방법은 없는지 고민하며 학습 전략을 나에게 맞도록 조정해 가는 것은 분명히 필요한 일이라는 생각합니다. 저와 같은 고민을 하는 분들에게 조금의 도움이라도 되길 바랍니다.

참고자료