블로그 태그를 붙인 글을 최신 순으로. 좀더 개인적인 글은 일기장에. 블로그 글 전체 목록은 내 글 모음에.
Simple Design
드라이퍼스 모델에 따르면, 전문가는 직관으로 일하지만 초보자는 규칙이 있어야 성과를 낼 수 있다. 나는 내 경력의 대부분의 기간 동안 전문성이 높은 시니어 프로그래머들과 함께 일해왔기 때문에, 코드 품질에 대해서도 각자의 주관을 충분히 발휘할 수 있게 하되, 충돌이 날 때는 서로 토론해서 맞춰가는 식으로 해결해왔고, 이 방식은 꽤 잘 동작했다. 하지만, 프리랜서를 다수 고용해야 하는 외주 프로젝트들, 그리고 큰 팀을 빌딩해야 하는 상황 등을 거치면서 다양한 전문성 레벨의 팀원들과 함께 일할 때도 코드 품질을 잘 다룰 수 있는 방법이 필요하다고 느꼈다. 그래서 XP 커뮤니티의 코드 품질에 대한 글들, 내 생각, 몇 가지 책들을 조합해서 원칙을 정리해보기로 했다.
코드 품질에 대한 느낌적 느낌#
다양한 전문성 레벨의 프로그래머들과 일하면서 느낀 점 중 하나는, 전문가들은 직관으로 코딩해도 좋은 코드가 나오는 경우가 많고 직관이 나쁜 냄새를 잘 짚어내지만 그럼에도 불구하고 자신의 설계를 끊임 없이 의심하고 논거를 찾으려 하고 더 나은 방법을 생각해본다는 것이다. 반대로 초보자들은 직관이 아직 부족한데도 오히려 명확한 논거 없이 자신의 주관으로 설계를 한다. 그래서 코드 품질을 개선했다고 주장하는데 왜 이렇게 했냐고 물어보면 객관적인 근거를 이야기하기보다 그냥 이게 더 좋은 구조 같아서
, 이게 내 멘탈 모델에 더 잘 맞아서
, 더 깔끔해보여서
, 가독성이 좋은 것 같아서
같은 느낌적 느낌을 이야기한다. 근데, 이게 또 느낌이다보니 사람마다 달라서 다른 사람의 느낌과 충돌하는 경우도 흔하다.
코드 품질을 표현하는 말 중에 가독성이라는 표현이 해로운 방향으로 동작하는 경우도 많았다. 그냥 자기 눈에 잘 안 들어오면 코드 읽기 어렵다
라고 표현하는 경우가 많았다. 재미있는 점은 다른 사람의 코드를 읽기 어렵다는 불평을 많이 하는 사람들의 코드가 대체로 그런 불평의 대상이 되는 경우도 많았다는 것. 아무래도 가독성
이라는 말, 코드가 읽기 쉽다 어렵다
는 말 자체가 코드를 주관적으로 평가하게 만들고 또 주관적으로 코드를 작성하게 하다보니 사람마다 그 느낌이 일치하지 않는 문제가 생길 수 밖에 없는 것 같다.
클린 코드
도 좀 비슷하다. 다만, 이건 책이 있다보니 어느 정도 고유 명사처럼 기능하기도 하면서 기준을 제시하기도 하는데, 나는 클린 코드 책의 기준들은 절반 정도만 동의하는 편이라 이 기준을 가져다 쓰고 싶지는 않았다. 마찬가지로 코드를 "깔끔하다", "지저분하다" 등으로 표현하는 것도 코드 품질을 높이는데 오히려 방해가 되는 표현들이라고 본다.
이런 표현들의 또 다른 문제 중 하나는 본질적 복잡성의 문제를 간과하게 만든다는 것이다. 프로그래밍의 복잡성은 두 가지, 본질적 복잡성과 우발적 복잡성이 있다. 우발적 복잡성은 개발 도구, 프로그래밍 언어, 코드 품질 등으로 해결할 수 있는 것이지만, 본질적 복잡성은 소프트웨어로 해결하려는 문제 자체에 담긴 복잡성이라 코드로 해결할 수가 없다. 그런데, "가독성" 관점으로 이런 코드를 바라보게 되면 본질적 복잡성을 우발적 복잡성으로 오해해서 잘못된 해결책을 시도하게 된다.
주관을 배제한 코드 품질 기준#
그래서, 나는 코드 품질에 대해서 주관을 배제해보면 어떨까 하는 생각이 들었다. 다만 한 가지 우려가 있었다. 초보자들은 규칙에 따라 일하면 성과를 낼 수 있지만, 전문가들은 그 규칙을 넘나들면서 직관에 따라 일하기 때문에 지나치게 객관적인 규칙을 제시하면 전문가들의 생산성을 깎아먹지 않을까 하는 것이다. 나는 전문가들이 초보자의 몇 배 생산성을 내기 때문에 팀이 초보자보다는 전문가에 맞춰져서 굴러가야 한다고 보는 편이라 더욱 걱정이 컸다. 그래서, 어떤 규칙을 적용할 경우 전문가의 생산성을 유지하면서 초보자의 생산성을 업그레이드할 수 있을지 시뮬레이션을 해보았다.
여러 가지 시행착오를 거치면서 내가 확인한 것은, 애자일 & XP 커뮤니티에서 이야기하는 좋은 코드의 기준들은 대개 전문가의 생산성을 떨어드리지 않는다는 것이었다. 그런 기준들은 어떤 코드에서 냄새가 나는지는 모호함 없이 판단 가능하게 해주지만, 어느 정도 냄새가 심할 때 개선해야 할지, 또 어떤 식으로 개선할지 등에 대해서는 다양한 여지를 열어두기 때문에, 초보자에게 지침이 되어주면서도 전문가를 속박하지 않는 좋은 기준이 될 수 있다.
하지만, 이런 기준들이 또 너무 많으면 곤란하다. 실용주의 프로그래머의 다양한 원칙들, 리팩토링의 나쁜 냄새 목록 등은 모두 유용하지만, 이걸 다 머리 속에 담고 코드를 볼 수는 없는 노릇이다. 코드 품질 뿐 아니라, 팀을 운영하는 원칙도 너무 개수가 많으면 작동하기 어렵다. 그래서, 좀더 단순하면서도 부작용 없이 목적을 달성할 수 있는 원칙을 찾고자 했다. 코드의 문제는 곧 복잡성의 문제인데, 그 복잡성을 해결하기 위한 원칙이 복잡하다면 그것도 문제 아니겠는가. 단순한 원칙이 단순한 코드를 만든다.
Simple Design#
이런 고민 끝에 찾아낸 규칙이 켄트 벡의 Simple Design이다. 네 가지에 불과해서 기억하기도 쉽고, 그러면서 코드 품질 문제의 핵심을 잘 정의하고 있다. 켄트 벡이 처음 표현한 문구와 마틴 파울러가 재해석한 문구 두 버전이 있는데, 둘 모두 가치가 있어서 적당히 조합해서 표현해본다.
- 테스트를 모두 통과할 것
- 중복이 없어야 한다. 평행상속구조 같은 숨은 중복에 주의할 것
- 의도를 드러내라 - 프로그래머에게 중요한 의도를 모두 서술할 것
- 최소한의 문법요소 - 클래스와 메서드 등의 개수가 최소한이어야 한다.
근데, 이것도 실무적으로는 더 단순화할 수 있다. 첫번째 규칙은 설명이 필요 없는 규칙이라 대부분의 팀에서는 거론할 필요도 없을 것이다. 그리고, 세번째 규칙은 이 중에 가장 주관적인 규칙이라 역시 전문가들에게는 유용한 규칙일 수 있지만 초보자들에게는 또다른 부작용을 유발할 수 있는 규칙이며, 빼도 타격이 적다. 그래서, Simple Design을 다음과 같이 요약해서 정의할 수 있다.
중복이 없으면서 최소한의 문법 요소로 구성된 코드
이 정도면 기억하기도 쉽고, 실무에서 적용하기도 쉽고, 사람마다 다르게 해석할 여지도 적다. 중복이 뭔지는 굳이 해설이 필요 없을 텐데, 켄트 벡이 명시한 것처럼 숨어 있는 중복을 찾아내려는 노력은 좀 필요하다. 최소한의 문법 요소라는 게 좀 해설이 필요할 수 있는데, 켄트 벡은 원래 클래스와 메서드라고 표현했었던 것을 마틴 파울러는 최소한의 요소라고 좀더 일반화했고, 나는 이걸 다시 좀더 좁혀서 문법요소라고 표현했다. 클래스, 메서드 뿐 아니라 상속 계층, 콜 스택, 멤버 변수, 로컬 변수, 데코레이터, if 분기, 루프 등등이 다 문법 요소다. Cyclomatic Complexity가 늘어나는 것도 다 문법요소의 증가라고 볼 수 있다. 이런 게 최소한이 되는 설계를 찾아야 한다는 것이다. 여기에 더해 TLoC(전체 코드 분량)까지 최소화하면 더 좋다.
물론 중복을 해결하면서 문법 요소가 늘어나지 않을 수는 없다. 간단하게 extract method만 해도 메서드가 늘어난다. 하지만, 똑같이 중복을 해결하면서도 상속 계층이 몇 개씩 추가되거나, 클래스가 추가되기도 하는데, 메서드 하나만 늘어나면 더 유리한 것이다.
중복을 너무 일찍 제거하면 안된다고?#
최근 Don't DRY Your Code Prematurely라는 글이 유행하면서 중복을 내버려둬야 할 때도 있다 이런 주장이 나도는데, 나도 중복을 내버려둬야 할 때도 있다고 보지만, 저 글은 좀 문제가 많다. 특히 premature라는 표현을 쓴 것이 premature optimization과 비슷한 문제인 것으로 오해하게 만들 수 있다는 점도 꺼려지는 점이다.
말 꺼낸 김에 저 글에 대해 좀더 구체적으로 반론하자면, DRY를 하지 않는 이유로 다음 이야기를 하고 있는데, 이거야말로 같은 글에서 언급한 YAGNI다. 앞으로 일어날지 아닐지 모를 일을 근거로 들면서 YAGNI를 이야기하면 곤란하다.
However, tasks and payments represent distinct concepts with potentially diverging logic
그리고, 중복을 해결하는 방식도 최소한의 문법요소로 해결했다고 할 수 없다. 나라면 이런 방법을 생각했을 것이다.
def assert_future(deadline):
if deadline <=
datetime.now():
raise ValueError('blah')
return deadline
set_task_deadline(assert_future(datetime(2024, 3, 12)))
YAGNI도 그렇지만 좋은 코드는 현재에 충실하게 Simple Design을 하는 것이지 미래에 일어날 그 어떤 변화를 미리 예상해서 유연하게 준비해두는 것이 아니다. 변화를 예상해서 DRY를 하지 않는다는 것은 좋은 생각이 아니다.
밥 먹기 전에 설거지하기#
저 글은 다분히 잘못된 방향으로 독자들을 이끌고 있지만, 나 역시도 중복을 내버려 둬야 하는 경우는 존재한다고 생각하고, 또 그 방향 역시 YAGNI라는 관점이긴 하다. 근데 그 이유는 저 글처럼 모순된 이유가 아니라 바로 비용이다. 코드 품질을 개선하더라도 그 코드를 다시 만질 일이 없거나, 그 코드가 영향을 미치는 범위가 좁다면 코드를 개선해도 이득이 없다. 그러니까 코드를 개선하는 비용이 허공으로 사라지는 것이다.
그래서, 나는 밥 먹기 전에 설거지하는 전략을 섞어서 쓴다. 보통은 밥 먹고 나서 설거지하는 것이 좋은 생활 습관이지만, 설거지한 이득은 다음 밥 먹을 때가 되야 발생한다. 그렇다면 밥 먹고 설거지를 쌓아두었다가 밥 먹을 때가 되었을 때 설거지하는 전략을 쓸 수 있다. 아마 많은 자취생들의 전략일 것이다. 집을 청결하게 유지한다는 목적에서는 나쁜 전략이지만, 자취생들은 에너지를 절약하는 것도 중요하다. 다음에 언제 또 집에서 밥 먹을지도 모르는데 지금 설거지하는 것은 심리적 저항이 크다. 하지만 다음에 밥을 먹을 때가 되면 설거지 안하고는 밥을 못 먹기 때문에 설거지를 하게 되서 저항이 작아진다. 심리적 저항도 실무에서는 시간이라는 비용으로 현실화되기 때문에 우습게 보면 안된다.
그러니까, 코딩할 때도 필연적으로 발생하는 중복들을 바로 제거하는 것이 아니라 그 중복이 악영향을 미치기 시작할 때(설거지 하지 않으면 밥을 못 먹을 때처럼) 제거하는 것이다. 근데, 이게 좀 작은 단위로 일어나야 한다. 예를 들어, 주어진 작업을 완료하기 위해 A, B, C, D 네 가지 모듈을 작성해야 한다고 가정해보자. A는 B에서 사용되고 B는 C, D에서, C는 D에서 사용된다. D는 그 자체로 최종 목적이며 다른 곳에서 더 사용되진 않는다. 이런 기능을 개발할 때 A를 개발 완료하고 나면 이게 다시 B에서 쓰이니까 A에는 나쁜 냄새가 남아 있으면 안된다. 그래서 A는 충분히 리팩토링을 해두고 넘어간다. B, C도 마찬가지. 근데 D는 다른 곳에 영향을 안 준다면 굳이 리팩토링하지 않고 내버려 둔다. 다음에 다른 곳과 연관이 되기 시작할 때 리팩토링한다.
이런 식으로 비용과 타협하면서 코드 품질을 높여가자는 것이고, 이걸 한 마디로 표현한 것이 YAGNI라고 할 수 있다.
가끔은 극단적으로#
근데 밥 먹고 설거지하는 전략은 초보자에게 추천할 만한 전략은 아니다. 코드 개선에 드는 비용이 얼마나 될지 추정하기 어렵고, 개발 단계에 따라서 다를 수도 있기 때문이다. 당장 기능 개발을 빨리 해내는 것이 회사의 운명을 좌우할 정도로 급하지 않다면 때때로 극단적인 코드 품질을 추구해보는 것이 좋다. 모든 회사가 스타트업인 것도 아니고, 유지보수가 중요한 단계로 넘어간 회사들이 더 많다. 그래서, 나는 상황에 따라 중복을 하나도 살려두지 말고 다 잡으라는 조언을 하는 경우가 많다.
또, 생각보다 많은 스타트업이 코드 품질 때문에 장벽에 가로막힌다. 몇 달 개발하지도 않았는데 코드가 지저분해서 더 못하겠다면서 갈아 엎자고 하는 사람이 나오는 팀을 숱하게 봤다. 이미 돌고 있는 비즈니스가 있고 핵심 경쟁력이 될 기능 하나를 추가해야 하는데 코드 품질 문제로 버그가 양산되면서 사고가 터지는 경우도 많다. 스타트업이라고 해도 상황에 따라 코드 품질을 높여야 하는 경우는 많다.
회사 뿐 아니라 개인에게도 이런 관점이 도움이 될 때가 많다. 극단적으로 코드 품질을 추구하는 경험을 해보면 다양한 방법들을 탐색해보게 되고 이 과정에서 좋은 학습이 일어난다.
또 하나 생각해야 하는 것은, 코드 품질을 떨어뜨리면서 개발 속도를 높이는 게 생각보다 어렵다는 것이다. 중복 코드도 종류에 따라 팀 전체의 생산성을 떨어뜨리는 것도 있고 별 영향을 안 주는 것도 있다. 어떤 종류의 나쁜 냄새는 내버려두면 하루이틀 짜리 개발 작업도 늦어지게 만든다. 이런 걸 판단하는 게 곧 실력이기도 하다.
코드 품질을 높이려는 이유 자체가 더 빨리 개발하기 위해서다. 간혹 코드 품질을 높이려면 프로젝트 기간이 더 필요하다는 주장을 접하는데, 프로젝트를 더 늦게 완료할 거면 뭐하러 코드 품질을 높이나? 주객이 전도된 것이다. 더 빨리 개발할 수 있게 해주는 코드가 아니라면 품질이 높은 코드가 아닌 거다.
코드 품질을 희생해서 개발 속도를 높인다는 건 컨텍스트가 머리 속에 다 들어 있을 때만 가능한 일이다. 머리 속에 담은 양을 벗어나서 작업하게 되면 결국 자신이 작성한 코드를 다시 읽어야 하고 사용해야 하는데, 그 코드들의 품질이 낮다면 손해를 보기 시작하는 것이다. 근데 프로그래머의 머리 속에 들어갈 수 있는 컨텍스트의 분량은 얼마나 되나. 보통은 30분 안팎일 것이다. 좀 큰 사람은 한두 시간, 천재들은 며칠 정도 되겠지. 근데 그 한계를 벗어난 크기의 일을 하게 되면 이미 코드 품질로 인해 생산성 하락을 겪기 시작하는 것이다. 한 달 정도 규모의 일을 나쁜 코드 품질로 빨리 완료할 수 있는 사람은 존재하지 않는다.
그래서, 나는 다소 극단적으로 코드 품질 - 중복이 없으면서 최소한의 문법 요소로 구성된 코드 - 을 추구해보라고 이야기하고 싶다. 비용과 타협해가면서 리팩토링을 저울질 하는 것은 자신이 코드 품질 전문가가 되었다고 생각할 때 시작해도 늦지 않다.
리팩토링의 나쁜 냄새는 어떤가?#
내가 코드 품질에 대해 이야기할 때 실무적으로 가장 많이 활용하는 것은 리팩토링에서 말하는 나쁜 냄새(Code Smell)다. 이것도 매우 잘 정리되어 있고, 코드에서 바로 이건 이 냄새니까 이렇게 리팩토링하는 게 좋겠다고 설명하기 좋다. 켄트 벡의 Simple Design만으로는 충분히 구체적이지 않다고 느낄 때 나쁜 냄새 목록에서 찾아보는 것은 추천할 만하다. 목록이 많아서 Simple Design처럼 머리에 담아두고 즉시 활용하기는 어렵지만, 코드에서 나쁜 냄새를 맡았을 때 이게 무슨 냄새인지 찾아보고 생각해보는 용도로는 아주 훌륭하다.
본질적인 복잡성에도 도전하자#
앞서서 본질적인 복잡성과 우발적인 복잡성을 언급했고, 코드 품질 개선의 대상은 우발적인 복잡성이라고 이야기했다. 하지만 여기서 한 발 더 나아갈 수 있다. 본질적인 복잡성으로 인해 복잡해진 코드를 보면 코드를 개선하자고 나서는 대신, 비즈니스를 건드려야 한다. 개발자가 이해하기도 어려울 정도로 복잡한 코드로 표현되는 비즈니스 로직이라면 비즈니스를 운영하는 실무자들도 이미 어려움을 겪고 있을 것이다. 그 복잡성이 정말 피할 수 없는 복잡성인지 고민하고 개선 방법을 찾아야 한다.
내가 이전에 경험한 팀에서도 환불과 관련된 규칙이 무려 30개의 조항에 달했었다. 처음에 담당자들과 미팅했을 때는 8개 정도로 정리가 되었었는데, 알고보니 담당자들도 인지하지 못하는 규칙들이 세세하게 많았고, 개발이 진행되면서 계속 새로운 규칙이 튀어나왔다. 그러니 담당자들도 어떻게 계산해야 할지 모르는 상황이 빈번하게 나오고 개발하기도 어려웠다. 근데 그 규칙들을 세세하게 뜯어보면 굳이 필요한가 싶은 규칙들이 정말 많았다. 그냥 우리가 월 수백원 손해보면 되는 것, 수천원 손해보면 되는 것, 혹은 아무도 손해보지 않는 것 등등 없애기 쉬운 규칙들이 많았고, 그런 것들을 하나하나 협의해서 없애나가서 나중에는 10여개의 규칙으로 정리할 수 있었다.
비즈니스에서 나오는 요구사항은 대개 담당자마다 다른 생각에서 나오고 통일된 기본 원칙 하에서 나오는 것이 아니기 때문에, 이런 걸 다 수용하다보면 본질적인 복잡성이 끝도 없이 커질 수 있다. 이럴 때 전체 규칙을 다 볼 수 있는 개발자가 비즈니스 규칙도 같이 다듬어 가면 비즈니스 전체에 이익이 될 수 있다. 나쁜 코드가 나오게 만드는 요구사항은 비즈니스적으로도 비용을 크게 증가시키는 경우가 많다. 나쁜 냄새의 기원이 본질적인 것이든 우발적인 것이든 일단 냄새를 맡았으면 개선하려는 시도를 해보자.
코드 품질과 비즈니스 성과#
최근 좋은 코드, 돈 버는 코드 등의 이야기, Premature abstraction 등의 이야기가 나오면서 코드 품질을 꼭 추구할 필요는 없다는 주장이 종종 나온다. 나 역시도 QuickAndDirty의 중요성을 강조하는 글을 쓴 적이 있다. 실제로 코드 품질이 좋다고 비즈니스가 성공하는 것도 아니다. 하지만, 코드 품질이 나빠서 실패한 프로젝트는 수없이 많다. 코드 품질이 나쁨에도 불구하고 성공한 비즈니스들이 있기 때문에 종종 간과되는 사실이지만, 정말 많은 회사들이 이미 만든 서비스에 약간의 기능 추가하는데 실패해서 성장이 정체되고 있다.
전에 애자일 방법론에 관한 글에서도 이야기한 적 있지만, 코드 품질을 개선하는 활동도 일종의 방법론이고, 과학적 방법론과 비슷하게 볼 필요가 있다. 과학적 방법론을 사용한다고 해서 과학적인 연구 성과가 보장되는 것은 결코 아니다. 또한, 과학적이지 않은 방법으로 여러 가지 직관과 우연이 겹쳐서 나온 과학적 발견도 무수히 많다. 그렇다고 해서 현대의 과학자가 과학적 방법론을 사용하지 않는다면 그게 말이 될까? 방법론이란 그런 거다. 절대 성과를 보장해주지 않지만, 성과를 낼 확률을 높여주기 때문에 하는 것이다.
그런 만큼 코드 품질을 높이느라 프로젝트 기간이 늘어난다면 코드 품질이란 걸 잘못 알고 있는 것이다. 더 빨리 개발하기 위해 코드 품질을 개선하는 것이라는 점을 잊지 말아야 한다.
내가 개발팀을 운영하는 원칙
블로그를 복구한 기념으로, 내가 그동안 개발팀을 운영해왔던 원칙들을 좀 정리해보기로 했다. 예전에는 이런 원칙들을 이미 내재화한 동료들과 많이 일했었기 때문에 이런 원칙들을 문서화해보지 않았는데, 최근 직장인 메디쿼터스에서는 처음부터 개발팀을 새로 빌드업해야 했기 때문에 원칙들에 대해 자주 반복적으로 설명해야 해서 자연스럽게 글로 적어보게 되었고, 이 원칙들을 내 스스로 돌이켜볼 계기가 되었다. 그 원칙들을 여기서 다시 한 번 정리하고 해설을 덧붙여보고자 한다. 이 내용들은 내가 리더로 일하기 시작한 10~15년 간 일관되게 지켜온 것들이지만, 최근의 경험에 좀더 맞춰서 이야기해본다.
애자일 선언과 eXtremeProgramming의 가치를 이해하고 따르려고 노력한다.#
팀에서 공식적으로 애자일과 XP를 선언하고 시작했다. 애자일에 대해서는 수많은 논란이 있고, 또 애자일이라는 걸 너무 드러내지 말고 조금씩 도입해야 진짜 애자일이라는 둥 다양한 전략들이 거론되지만, 나는 직진을 택했다. 다만, 애자일이라는 용어가 이미 국내외를 막론하고 정반대의 의미로 많이 오염이 되어서, 애자일이라는 표현을 직접 쓰기보다는 애자일 선언을 거론하거나, 구체적인 방법론으로 XP를 들어 소통하는 방식을 취했다.
애자일 선언은 단어 하나하나가 정말 세심하게 선택되어 있어서 주의 깊게 읽는다면 잘못 해석할 여지도 적고, 추상적이면서도 모호하지 않다. 그러나, 쉬운 문장은 아니기 때문에 어느 정도 해설이 필요하다. 그래서 애자일 선언 다시보기 같은 글을 쓰다 말기도 했었다. 하지만 여기서 애자일 선언 해설을 다 할 수는 없고, 애자일 선언의 세부원칙 12가지 중에 많은 팀이 어려워하는 거 몇 가지에 대해서만 내 관점을 적어본다.
Welcome changing requirements, even late in development. Agile processes harness change for the customer's competitive advantage.#
경력이 적은 주니어들은 요구사항이 자주 바뀌는 것을 보고 팀이 체계 없이 일해서 그렇다고 생각하는 경우가 많다. 하지만, 요구사항이 바뀌는 것은 소프트웨어 개발에서 필연적인 것이며, 안 바뀌는 것이 훨씬 위험하다. 요구사항이 중간에 안 바뀐다는 것은 개발하는 과정에서 개발에 참여한 사람들이 아무 것도 배우지 못했다는 뜻이기 때문이다. 물론, 보통의 회사에서는 합리적인 이유로 요구사항이 바뀌기보다는 의사결정자의 갈대 같은 마음으로 바뀌기 때문에 요구사항 변화에 거부감을 갖기 쉽다. 하지만, 그런 의사결정자라면 더더욱 요구사항이 안 바뀔 때의 리스크가 더 클 것이다. 개발자는 언제든지 자기가 작업한 코드를 버릴 준비가 되어 있어야 한다.
Business people and developers must work together daily throughout the project#
PO라는 포지션의 등장으로 이게 점점 더 어려워져 가고 있다. PO가 다리 역할을 한다는 명분으로 비즈니스 피플과 개발자 사이의 직접적인 소통을 끊고 중간에 정리해서 따로따로 소통하게 하고는 소통 시간을 절약해준다고 말한다. 도대체 누구의 시간을 절약하는 걸까? 아무리 뛰어난 PO라도 소통 과정에서 정보의 유실이 발생하지 않을 수는 없다. 담당자끼리 직접 소통하면 금방 될 일을 여러 단계로 핑퐁하면서 10분 만에 결정할 수 있는 일이 며칠 씩 걸리기도 한다. 그래서 나는 늘 비즈니스 피플과 개발자가 직접 소통하기를 권하고, 개발자가 자신이 맡은 작업의 비즈니스 가치에 대해 이해하기를 요구한다. 개발자에 따라 이걸 싫어하고 그냥 기획서만 쳐다보고 일하고 싶어하는 경우도 많다고 하는데, 적어도 내 팀에서는 대개 비즈니스랑 맞닿아 있는 것을 좋아하는 사람들이 대부분이었다. 자신의 일의 결과로 돈을 얼마 버는지, 혹은 비용을 얼마나 아끼는지 이해할 때 개발자는 더 보람을 느끼고 일에 매진할 수 있다.
Working software is the primary measure of progress.#
애자일이 잘못 전파된 사례 중 하나가 스크럼 보드다. 스크럼 보드, 칸반, 또는 백로그 등의 시스템에서 ToDo 카드가 무슨 상태로 바뀌었냐를 가지고 프로젝트 관리를 하려는 조직들이 많다. 하지만, 이건 진짜 진척도가 아니다. 진짜 진척도를 알고 싶으면 소프트웨어를 돌려봐야 한다. 개발 진척 상황을 100% 작업관리 시스템과 싱크시키는 것은 생각보다 비용이 크다. JIRA를 열심히 쓰는 팀 중에는 JIRA를 쓰는 시간이 코드를 작성하는 시간 못지 않게 많은 팀도 흔하다. 리더 혼자 편하자고 팀원의 시간을 이렇게 써서는 안된다. 칸반의 목적도 이런 게 아니다.
현재까지 개발된 소프트웨어를 계속 실행해보고 여러 가지 관점에서 테스트하다보면 다음으로 해야 할 중요한 일이 무엇인지는 자연스럽게 나온다. 개발이 진척될수록 일정도 자연스럽게 예측 가능성이 높아져 간다. 카드들 늘어놓고 우선순위 열심히 토론한다고 잘 정리되는 게 아니다.
Simplicity--the art of maximizing the amount of work not done--is essential.#
이건 개발자들이 심리적으로 잘 못하는 부분이다. 개발자는 요청 받은 일이 뭐든 다 빨리 해주는 게 능력이라고 생각하기 때문에 일을 거절하거나 더 쉬운 방법을 찾기보다 그냥 해달라는 대로 해주는 경우가 많다. 그런데 비즈니스 피플은 소프트웨어 전문가가 아니라서 어떤 대안들이 있는지 잘 모른다. 코드 한 줄 변경 없이 목적을 달성할 수 있는 방법이 있는데도 개발해 달라고 하는 경우가 많다. 매우 어려운 길로 개발하는 대신 손쉽게 조금만 고쳐서 원래 목적을 달성할 수 있는 경우도 많다. 이런 건 개발자가 이야기해줄 수 있어야 한다.
모든 의사결정은 뒤집을 수 있다.#
애자일 선언 다음으로 중요하게 이야기한 원칙이 이것이다. 사실 이것도 embrace change를 내세우는 애자일의 연장선이기는 하지만, 좀더 구체적으로 선언해둘 필요가 있었다. 의사결정은 당연히 바뀔 수 있는데 굳이 선언해둘 필요가 있나 싶을 수 있지만 대부분의 조직은 한 번 의사결정한 것을 바꾸는데 대단한 거부감을 느낀다. 특히 가장 나쁜 것이 "우리 이거 전에 이야기해서 결정한 거잖아?" 같은 말이 나오는 것이다. 이런 말은 우리가 이전에 했던 나쁜 의사결정을 뒤집는 것도 가로막게 된다. 또 이런 말이 반복적으로 나오게 되면 그 팀은 중요한 의사결정을 내리기 어려워진다. 되돌릴 수 없는 결정이라는 걸 알고 결정한다면 사람들이 어떻게 행동할까? 절대 실패하지 않는 결정으로 만들기 위해 더 많은 검토를 해야 하고 반대 의견을 쉽게 수용하기 어려워진다. 그래서, 나는 팀에서 저런 말이 나오는 것을 극도로 경계한다.
법정에서도 증거나 진술 등에 허위가 있었을 때는 일사부재리의 원칙의 예외로 재심이 가능하지만, 회사는 그런 제약도 필요 없다. 이전에 의사결정했을 때보다 팀이 더 발전했고 그에 따라 생각이 바뀌었다면 의사결정을 뒤집지 못할 이유가 없다. 그래서, 실제로 다른 팀에서는 거의 바꾸지 않는 것들을 우리 팀에서는 많이 바꾸었다. js와 ts 사이를 왔다갔다 하기도 하고, 구현 상의 원칙도 여러 번 변경되었다.
나중에 더 좋은 결정을 내리는 게 가능해졌을 때 이전의 의사결정을 뒤집을 수 있다는 확신이 있으면 거꾸로 가벼운 의사결정이 가능해지기도 한다. 반대 의견을 주장했던 사람들도 일단 해보고 안 좋은 점이 발견되면 다시 바꾸자고 할 수 있기 때문이다.
업무에 대한 의사소통은 가능하면 사적인 채널보다 공적인 채널을 우선한다.#
오래된 팀들에서 주로 일해오다가 신세대(?) 회사를 경험하면서 느끼는 것 중 하나는 개인적인 소통을 상당히 많이 한다는 것이다. 당연히 팀 차원에서 논의해야 할 일인데 DM으로 보낸다든지, 둘이서만 미팅 잡는다든지 하는 일이 많았다. 이건 팀 전체에 흘러야 할 정보가 흐르지 않게 만든다. 설령 나 혼자만 하면 되는 일이라 하더라도 그 정보가 팀에 흘러야 한다. 그래서, 대체로 다음과 같은 우선순위로 소통하기를 권장한다.
- 오프라인 미팅은 되도록 모든 관련자들에게 참석을 요구하고, 온라인으로도 중계(허들 등)해서 원하는 사람이 참관할 수 있게 한다.
- DM보다는 팀원들이 모두 소속된 채널에서 소통하는 것을 우선한다.
- 쓰레드보다는 탑 레벨 메시지를 우선한다.
- 채널은 되도록 비공개보다는 공개로 만든다.
이것만으로도 의사소통의 투명성도 높아지고 정보가 좀더 잘 흐르게 된다.
의사소통에서 메시지 전달의 책임은 받는 사람이 아니라 보내는 사람에게 있다.#
회사에서 또 분쟁이 많이 생기는 포인트 중 하나가, "전에 말씀드렸잖아요." 같은 것이다. 그런데, 직원들이 성과를 내려면 집중이 필요하고, 머리 속에 집중해야 할 일이 있을 때 들은 이야기는 놓치기 쉽다. 개발자만 그런 게 아니라 거의 모든 직군이 그럴 것이다. 그런 것들을 꼼꼼하게 챙기도록 요구할 수도 있겠고, 그게 프로페셔널의 자세라고 말할 수도 있겠지만, 나는 그렇게 생각하지 않는다. 꼼꼼하게 챙기는 것은 공짜가 아니다. 많은 비용이 들고, 때때로 집중하는데 써야 할 에너지를 소모시키는데, 이것은 회사에 더 큰 손해다. 하지만, 메시지를 보내는 사람은 보통 자신에게 필요해서 보내는 것이기 때문에 컨텍스트를 끊지 않아 전환 비용이 적게 발생한다. 그래서, 나는 메시지 전달의 책임을 송신자에게 부여한다. 이 문제에 관해 여러 가지 다양한 방법을 시도해봤지만, 효율성 측면에서도, 분쟁의 최소화 측면에서도 이게 가장 좋은 방법이었다.
이 원칙은 여러 가지로 파생된다. 이를테면 질문할 때 답변자가 놓치고 답을 안했다고 해서 답변자를 나무랄 수 없다. 그냥 질문자가 다시 한 번 질문해야 한다. 슬랙으로 공개 채널에서 질문했는데 답을 안 주면 멘션을 걸고, 그래도 안되면 DM을 보내고, 그래도 안되면 전화를 해야 한다. 물론 보통은 멘션 수준에서 끝나지만. 코드 리뷰를 받는 것도 리뷰어의 책임이 아니라 커미터의 책임이다. 리뷰가 지연되면 커미터가 계속 리뷰어들을 재촉해야 하는 의무를 진다. 대신 리뷰어는 재촉을 귀찮아해선 안되고.
다만 개발팀 바깥과의 소통에서는 튜닝이 좀 필요하다. 전사적으로 이런 원칙을 적용하는 것은 아니었기에, 외부의 요청에 대해서는 좀더 꼼꼼하게 대응하기를 요구하되, 개발팀이 타 부서나 다른 회사에 요청할 때는 응답이 안 오면 상대를 질책하지 않고 그냥 우리가 요청을 반복하도록 했다.
개발팀 내에서의 의사소통은 비동기가 원칙이었기 때문에 이 원칙과 더 시너지가 나는 부분도 있었다. 메시지 송신자는 언제든지 자기가 급할 때 메시지를 보내도 되고, 수신자도 자신이 가능할 때 답을 하면 된다. 일하는 시간대가 다른 사람도 많았기 때문에 더더욱 이 원칙이 잘 동작했던 것 같다.
이 원칙을 명시하고 여러 번 강조한 이후로는 이런 종류의 분쟁도 사라졌고, 그러면서 의사소통을 꼼꼼하게 챙기기 위한 부담도 줄어서, 상당히 유익한 정책이었다고 보고 있다.
허락을 구하기보다 용서를 구하라.#
이건 아마도 설명이 필요 없는 원칙이지만, 이게 좋은 원칙이냐 아니냐는 아마 팀마다 다를 것이다. 내가 이 원칙을 세운 이유는 애자일 선언의 첫번째 가치, "Individuals and interactions over processes and tools"와도 연관이 있다. 개인이 프로세스보다 중요하다는 것은 팀에서 합의하는 과정을 생략하고 개인의 판단으로 움직일 수도 있다는 뜻이다. 상황에 따라 완전한 합의를 구해가면서 하기에는 발이 느린 경우도 많고, 의사결정자가 빨리 응답해줄 수 없는 경우도 많다. 그럴 때 개인의 판단으로 일단 밀고 나갈 수 있어야 좀더 기민하게 움직일 수 있고, 또 그런 개인의 판단을 존중할 때 개인의 능력과 창의성을 최대한 이끌어낼 수 있다. 그래서, 공식적으로 허락을 구하기보다 용서를 구하는 것을 권장한다.
단, 이게 가능하려면 위에서 언급한 의사결정과 의사소통의 원칙도 같이 맞물려야 한다. 개인이 잘못된 판단으로 추진한 일을 다시 되돌릴 수도 있다. 그래서 더더욱 부담 없이 용서를 구하는 모드로 일단 밀어붙여 볼 수 있는 것이다. 물론 이렇게 추진하는 개인도 자신이 작업한 내용이 한 순간에 다 날아갈 수 있다는 각오가 필요하다.
이 원칙이 잘 동작하기 위해서는 개인이 팀, 그리고 리더를 믿을 수 있어야 한다. 이 원칙을 믿고 자기 생각대로 했는데 왜 너는 허락도 안 받고 이랬냐고 질책을 받는다면 이 원칙은 동작할 수 없다. 설령 개인의 판단이 틀렸더라도 질책하지 않고 바꾸어야 한다. 또, 이런 신뢰를 얻기 위해서는 때때로 최선이 아닌 판단을 보더라도 그대로 끝까지 가도록 내버려 두어야 할 필요가 있다. 자신의 결정이 매번 뒤집어진다면 이 원칙이 진짜인지 믿기 어렵기 때문이다. 그래서 나는 팀원들이 다소 잘못된 길로 가더라도 바로 잡지 않고 놔둘 때가 종종 있다. 단, 이런 선택을 하려면 그 잘못된 선택의 결과를 감당할 수 있는 기술적 역량도 필요하다.
이 원칙은 코드 레벨에도 많이 스며든다. 파이썬에서는 EAFP 같은 원칙을 이야기하기도 하는데, 발생할 법한 에러를 미리 검사해서 방지하는 코드보다는 에러가 발생하면 끝까지 에러가 던져지게 하되, 잘 기록해서 추적할 수 있게 하고, 적절한 레벨의 알림으로 인지할 수 있게 하는 것을 중시한다.
불완전한 코드와 생각, 업무 현황을 자주 팀에 공유하라.#
개발 과제를 받았을 때, 처음부터 좋은 설계를 떠올리고 좋은 코드를 작성해 갈 수 있는 사람은 없다. 누구나 시행착오를 거치게 마련인데, 이 시행착오 과정을 팀에 드러내지 않으면 여러 가지 문제가 발생한다. 가장 심각한 문제는 자기 능력 밖의 과제를 붙들어매고 끙끙대다가 필요한 시점에 개발이 완료되지 않는 것이다. 이런 걸 짚어내서 해결하는 것이 매니저의 역할이기는 하지만, 그 이전에 시행착오들이 좀더 자주 공유된다면 팀 단위로 일찍 해결할 수 있는 가능성이 높아진다. 또, 같은 시행착오가 팀 내에서 반복될 수도 있고, 더 좋은 방법이 있는데 그저그런 방법에서 머무르게 되기도 한다. 그래서, 과제의 완료 여부만으로 소통하기보다 해당 과제의 디테일에 대해 깊이 소통할수록 여러 가지로 이득을 볼 기회가 늘어난다.
하지만, 불완전한 모습을 내보이고 싶지 않은 사람 심리상 이게 잘 안된다. 시행착오를 거친다는 것이 능력 부족으로 비칠까 두려워하기도 한다. 특히 주니어들은 이런 두려움을 많이 가지는 것 같다. 그리고 실제로 그런 시행착오를 겪는 것을 능력부족으로 평가하는 매니저들도 있다.
그래서, 나는 이 문제를 개선하기 위해 여러 각도로 노력을 했다. 우선, 그런 시행착오를 자주 공유하는 사람들을 공개적으로 칭찬하고, 개인별 면담할 때도 그런 사람들의 사례를 긍정적으로 이야기하며, 그런 사람들처럼 하기를 요구했다. 그런 사람들은 대개 시니어였는데, 시니어로서는 모르면 안될 것 같은 내용에 대해 질문을 하기도 하고, 명백히 틀린 구현 방법을 제안하거나, 장애 분석시 가능성이 낮은 가설을 이야기하기도 했다. 그러나, 그렇게 계속 제안을 해준 덕분에 해당 이슈에 대해 제대로 된 이야기가 오갈 수 있었고, 거기에 대한 지식도 팀에 확산될 수 있었다. 이런 시니어들이 있었기 때문에 나도 좀더 강하게 이 원칙을 이야기할 수 있었다. 사실 어느 팀을 가든 공유의 빈도는 실력과 상당히 크게 비례한다. 잘하는 사람일수록 자주 공유하고 문제가 될 만한 것을 미리 끄집어내서 팀이 같이 해결할 수 있게 만든다.
하지만 주니어들은 그래도 쉽게 자신의 작업 상황을 투명하게 공유하는 것을 두려워했다. 그래서, 이번에는 다소 깊이 멘토링을 해보기로 했다. 30분 단위로 커밋을 하거나, 커밋을 하나도 못했으면 그 사이 고민한 내용을 공유하는 프랙티스를 제안해서 실행했다. 이것도 처음부터 다들 잘한 것은 아니었지만, 몇 명 앞서가는 사람들이 있었다. 근데 재미있었던 것은, 그렇게 앞서갔던 주니어들이 좀 다른 각도에서 도움이 되었다. 그들이 공유하는 내용을 지켜본 다른 주니어들이, "아, 다른 사람들도 이렇게 삽질을 많이 하는구나."를 깨닫고, 자신도 그렇게 투명하게 공유할 용기를 낼 수 있었다고 했다.
그리고, 조금 자극을 줄 수 있는 방법도 시도했다. 사실 우리 팀은 20명도 안되는 팀이어서 내가 맘만 먹으면 누가 무슨 일 하는지 디테일까지 다 파악할 수 있다. 이 정도 일을 맡겼고, 그러면 이 정도 기간이면 결과가 나오든 뭔가 중간 산출물이 나오든 해야 하는데, 안 나오고 있으면 뭔가 잘못하고 있다는 정도는 추측이 가능하다. 이 사실을 짚어주면서 공유 안한다고 삽질 중인 거 모르겠냐는 이야기를 했더니 다들 깜짝 놀라는 반응을 보였다. 그 뒤로는 어차피 자기 실력이 다 드러나 있다는 사실을 아니까 마음이 편해져서 더 쉽게 공유를 하게 되었다는 회고를 들을 수 있었다.
이 원칙이 정착되어 가면서 팀 전체의 리스크도 많이 낮출 수 있었고, 주니어들이 빠르게 시니어로 성장해갈 수 있었던 것 같다.
문제가 있을 때 사람을 비난하기보다 문제 자체에 집중할 수 있는 방향으로 소통한다. 피치 못하게 사람을 비난할 때는 구체적이고 입증 가능한 근거를 제시해야 한다.#
위의 원칙들이 모두 가능하려면 팀에 심리적 안전감이 충분해야 한다. 내가 잘못된 코드를 작성하거나, 개발을 지연시키거나, 결함을 만들거나, 장애를 발생시키더라도 질책 받지 않고, 팀이 같이 문제를 해결한다는 믿음, 이게 있어야 위의 원칙들이 모두 가능하다. 이를 위해서는 문제가 생겼을 때 사람을 비난하지 말아야 한다. 개발에서의 문제는 대개 문제를 발생시킨 개인을 특정할 수 있고, 심지어 문제를 발생시킨 코드와 작성 시간까지 특정할 수 있지만, 그렇다고 해서 그 사람의 잘못이라는 식으로 소통해선 안된다. 그보다는 그 코드가 왜 문제인지, 그리고 그 문제를 어떻게 해결할 것인지에만 집중한다. 이것은 실용적인 원칙이기도 하다. 장애가 발생했는데 책임질 사람 찾는 게 무슨 소용인가, 일단 해결하고 봐야지. 이렇게 늘 문제 자체만 해결하려는 모습을 보이면 자연스럽게 안전하다는 느낌을 받게 되는 것 같다.
반대로 문제가 생겼을 때 책임자를 찾고 추궁하는 분위기가 되면 사람들이 어려운 문제에 나서지 않게 된다. 장애가 나면 자기 책임인지 아닌지만 빨리 확인하고 빠지고, 다른 사람을 돕지 않으며, 코드 리뷰에서도 논쟁적인 의견을 내지 않고 소심한 규칙 검사에 그친다. 이러면 팀이 죽어가기 시작하는 것이다.
내가 경험한 대부분의 팀에서는 그냥 문제에만 집중하는 분위기를 조성하는 것으로도 비난이 거의 안 나왔지만, 지난 번 팀에서는 좀 다른 상황이 있었다. 팀원들을 비난하는 발언임에도 불구하고 그게 비난이라고 생각하지 않고 하는 경우들이 많았다. 예의를 갖춰 조심스럽게 표현한다고 해서 비난이 아닌 건 아니다. 그래서, 어디까지가 비난이고 어디까지가 비난이 아닌지를 좀 정의할 필요가 있었다. 예를 몇 가지 들어보자.
만약에 누군가 JS에서 async의 동작을 잘 몰라서 잘못 작성한 코드가 있었다고 해보자. 이럴 때 async는 이러이러한 문법이고 이렇게 써야 한다고 말하고 넘어가면 좋은데, 그게 아니라 JS 기초가 부족하네요 같은 식으로 소통한다면 비난이 된다. 코드 품질에 대해서 이야기할 때도 이 코드는 너무 지저분해서 읽기 어려워요라고 말하면 비난인데, 이 코드의 이 부분은 shotgun surgery 냄새가 나고, 저 코드는 중복 조건문이 반복되는데 다형성으로 처리하면 좋다고 말하면 발전적인 방향이 된다. 대개 두리뭉실한 발언은 비난이 되기 쉽고, 또한 실용적인 가치도 없다.
이런 것보다 더 심각한 비난은 개인의 직업적 성실성이나 성인으로서의 판단력을 의심하는 발언이다. 예를 들어, 팀에서 토론을 하는데 분위기가 한쪽으로 너무 흐르고 있다면 어떤 점에서 편향되어 있는지를 지적하고 반대 방향의 이야기를 하면 건설적인 토론이 되지만, "너희들은 지금 객관적인 판단력을 잃었어"라고 말한다거나, "주니어라서 아직 이런 문제를 제대로 판단하긴 힘들다"라고 말하면 비난이 된다. 이런 발언이 튀어나올 때는 리더가 반드시 제지해야 한다.
근데, 그러면 사람을 향한 공격은 절대 하면 안되는가? 난 여기에 두 가지 명시적인 예외를 설정했다.
첫번째, 정말 꼭 해야 하는 비난이라면 근거를 정확하게 대야 한다. 예를 들어, 개인의 직업적 성실성을 의심하면 안된다고 했지만, 의심할 만한 사유가 발생핬다면 어떨까? 외주 계약을 실력이 없지만 친분이 있는 사람에게 주는 정황이 보인다면 그것도 공격하지 말아야 하나? 당연히 이런 건 잡아야 한다. 근데, 이런 비난은 중대한 비난이므로 근거가 필요하다. 아주 확정적이지는 않더라도 정황을 의심해보기에 충분한 근거가 있어야 한다. 새로 선정한 외주 업체가 일을 못하는데 알고 봤더니 친척이라든지.
두번째로 자신보다 직급이 높은 사람을 향한 비난은 근거가 다소 불충분하더라도 허용한다. 실무자가 매니저의 잘못을 정확하게 짚기는 어려울 수도 있다. 하지만, 그렇게 윗사람을 비난하고 싶은 일이 발생한다는 것은 뭔가 일이 잘못 굴러가고 있다는 것이고, 그게 그 윗사람의 잘못이 아니더라도 그 문제를 인식하고 해결하는 계기가 될 수 있다. 그래서, 윗사람은 아래로부터의 비난을 들을 수 있어야 한다. 물론 그게 꼭 수용해야 한다는 뜻은 아니다. 틀린 비난도 당연히 있을 수 있으니까. 적어도 그럴 때 비난 자체를 막기보다는 비난에 맞서 토론하는 자세를 보여줄 필요가 있다.
이렇게 비난에 대해서는 다각도로 신경을 썼지만, 막기 어려웠던 게 있다. 이 문화를 전사적으로 확신시킬 수는 없었기 때문에, 외부에서 개발팀을 향한 비난이 계속 발생하는 것은 막기 어려웠다. 그래도 우리는 다른 팀을 비난하지 말자고 했는데, 그렇게 생기는 그 감정의 골을 방치할 수는 없기 때문에 또 위의 두번째 원칙을 활용해서 그 비난을 나의 윗사람들에게 돌리고자 시도하는 정도가 한계였다.
DISCLAIMER#
이 이야기들은 내가 팀을 운영할 때 이렇게 했다는 것이고, 내가 주관적으로 좋다고 생각하는 원칙들이지, 다른 팀에도 적용해도 될 원칙이라고 주장하진 않는다. 이 원칙들 중 상당수가 대부분의 기업에서 적용되기 어렵고, 정반대의 문화를 가진 기업이 훨씬 많다. 대부분 논쟁적이기도 하다. 이를테면, 나는 사람에 대한 비난이 조직에 해롭다고 보지만, 문제가 생기면 책임자를 찾아내서 처벌해야 조직이 굴러간다고 생각하는 사람이 세상에는 더 많다. 나는 개인의 주관을 중시하고 허락을 구하기보다 용서를 구하는 것이 실용적이라고 보지만, 합의되지 않은 개인의 판단으로 조직이 움직여서는 안된다고 생각하는 사람이 많다. 나는 요구사항은 당연히 바뀔 수 있는 거라고 생각하고, 프로세스대로 일하기보다 사람과 사람의 상호작용으로 일하는 것을 선호하지만, 이런 것을 체계 없이 일하는 거라고 보는 사람도 많다. 나 역시 이런 원칙들이 논쟁적인 원칙들임을 알기에 대부분의 회사에는 이 원칙들을 권하지 않고, 좀더 소심하게 제안하곤 한다.
그래도 한 가지 자신 있게 말할 수 있는 게 있다면, 이런 원칙들 하에서 일해온 우리 팀이, 우리보다 몇 배는 큰 팀들보다 비슷한 미션을 훨씬 짧은 기간에 해냈다는 것이다. 심지어 IT 업계에서 이름 있는 회사도 아니어서 채용 난이도가 훨씬 높았음에도 말이다.
그리고, 이 내용의 많은 부분은 애자일 선언의 다른 표현에 불과하다. 애자일 선언만 깊이 있게 이해해도 팀 운영과 프로젝트 관리에서 많은 개선점을 찾을 수 있을 것이다.
API 서버 개발 중의 고민
외주로 위치정보를 많이 쓰는 앱의 API 서버를 제작 중이다. 이와 관련해서 요즘 하고 있는 설계 고민들을 적어본다.
데이터베이스 선택#
위치정보를 많이 쓴다면 2차원 인덱스를 통해 KNN Query 등의 위치정보 관련 쿼리를 쉽게 할 수 있는 MongoDB가 편하다. 그러니까 MongoDB 하나만 쓰고 RDBMS는 쓰지 말까? 아니면 그냥 Django 모델은 그대로 쓰고, MongoDB는 위치정보 인덱스로만 쓸까? Django 모델의 편리함을 그냥 버리긴 아깝다. 아니면 OpenGIS를 지원하는 PostgreSQL을 쓰면 다 해결되려나?
고민 끝에 일단 MongoDB를 전면적으로 쓰기로 결정했다. 이미 채팅촌에서 써본 경험이 있었는데 괜찮았고, PostGIS는 사용하기 그리 편하지 않았다. MongoDB를 위치정보 인덱스로만 쓰고 Django 모델을 주로 쓰는 접근법도 해봤는데, 나름 괜찮긴 하지만 조금 더 MongoDB를 깊이 써보고 싶었다.
모델 레이어#
MongoDB를 쓰기로 했으니 파이썬에서 어떻게 사용할지를 결정해야 했다. 크게 방법은 세 가지. pymongo를 그대로 쓰는 것, MongoKit, MongoEngine. 셋 다 나쁜 방법은 아니지만, 아무래도 MVC에서 모델 중심으로 가려면 pymongo를 그대로 쓰긴 좀 그렇고 뭔가 wrapping을 하긴 해야 한다. MongoEngine은 저번에 써봤는데, Django model을 닮은 게 그다지 맘에 들진 않았다. MongoDB로 계속 개발을 하려면 아무래도 MongoDB의 쿼리 문법에 익숙해져야 하므로 그걸 그대로 쓰는 게 유익하다. MongoEngine이 Django랑 억지로나마 연동이 되긴 하지만, Admin 연동이 제대로 안되는 이상 별로 큰 이득도 아니다. 그래서 MongoEngine은 시도도 안해보고 MongoKit으로 넘어왔다. 근데 MongoKit도 생각보다 불편하다. 가장 불편한 건 collection을 wrapping해서 관리해주지 않고 들고 다녀야 한다는 것이다. MongoKit에서의 document 생성은 다음처럼 database와 collection을 가져온 다음 거기서 모델 객체를 생성해야 한다.
connection.database.collection.MyDocument()
왜 MyDocument()를 바로 쓰는 걸 지원하지 않는지 이해할 수 없다. database와 collection을 미리 지정해두면 이 둘은 생략할 수 있지만, 그래도 connection에 붙여서 써야 한다. 쿼리도 마찬가지다. 별 거 아닐지 모르지만 그냥 이게 맘에 안 들어서 버리기로 했다. 그래서 그냥 예전에 내가 간단하게 만들어 둔 MongoDB model wrapper를 계속 쓰기로 했다. 이름도 붙였다. MongoDB Model을 줄여서 momo.
스키마 문서화#
외주다보니 스키마 문서화가 필요하다. Django 모델로 작성했으면 그냥 django-extensions의 graph_models 써서 다이어그램 넘겨버리면 그만이겠지만, momo는 그런 거 없다. 그리고 MongoDB는 schemaless가 기본이다보니 스키마를 정의하는 일이 부가 작업이 된다. 여기서 고민에 빠졌다. 따로 코드로 스키마를 정의할 필요가 없으니 그냥 수동으로 다이어그램만 그려서 관리할까, 아니면 그래도 스키마가 코드에 정의되는 게 명시성도 좋고 나중에 validation 붙이기도 좋으니 코드에 정의하고 다이어그램은 자동으로 뽑아낼까.
별도 문서화보다는 아무래도 코드에 정의를 하고 싶다. 코드에 정의를 하면 나도 개발을 하면서 계속 참조할 수 있어 이득을 얻기 때문이다. 사실 클라이언트에서 꼭 다이어그램까지 원하는 것은 아니기 때문에 스키마 정의한 문법을 그대로 보내줘도 될 것 같긴 하다. 다만 조금 세련된 문법이면서, 나중에 programmable하게 처리할 수 있는 구조이기만 하면 될 듯.
스키마를 코드에서 정의한다면 MongoKit을 베낄까, MongoEngine을 베낄까도 고민이다. MongoKit이 간결하고 시각적이지만, MongoEngine은 여러 가지 속성을 줄 수 있어서 확장성이 좋다. 문법 정의할 때 파이썬이 인터프리터 언어라는 점도 은근히 귀찮다. 클래스 정의할 때 자신을 참조하게 만들 수가 없기 때문이다. method 안에서는 참조할 수 있지만 클래스 레벨로 정의할 때는 참조할 수가 없어서 Django 모델도 문자열이나 'Self' 같은 문법을 쓴다. 아직 이 부분은 고민 중.
REST API 프레임워크#
일단 django를 쓰긴 할 텐데, REST API는 뭘로 만들까? 이전까지는 그냥 내가 만든 djangox-route를 써서 라우팅만 처리하고, JSONResponse 같은 걸 또 붙여서 대충 썼다. PUT, DELETE 따윈 지원하지 않지만 내 프로젝트라면 아마 또 그렇게 할 듯. 하지만 외주다보니 좀더 제대로(?) 만들어야 하고, 또 좀더 널리 알려진 프레임워크를 쓰는 게 좋을 듯 하다. 그래서 django-rest-framework와 tastypie를 비교하기 시작했다.
둘다 예제가 너무 Django model 연동 중심으로 되어 있다. 하지만 난 Django 모델을 안 쓰기로 한지라, 별로 도움이 안된다. 모델을 바꿔 끼우려고 해보니 tastypie는 상속해야 하는 메서드들이 좀 이상하다. get_object_list와 obj_get_list라는 어이 없는 네이밍을 해놨다. 확장하려고 문서를 찾아보니 문서도 좀 부실하다. 그래서 잠깐 django-rest-framework 문서를 더 보는데, 일단 문서가 좀더 풍부하고, browsable api가 있어서 이게 더 편할 것 같았다. View와 Serializer를 API마다 세트로 작성해야하는 것처럼 보여서 조금 꺼려지긴 했지만, 아마도 Serializer는 어떻게든 하나로 할 수 있는 방법이 있겠지. 그래서 일단 django-rest-framework로 왔다. 생각보다 쉽게 연동이 되서 Browserable API에서 JSON으로 POST하고 조회하고 하는 건 잘 된다. 일단 API 작성까지는 이게 괜찮은 것 같다.
그런데 또 하나 중요한 건 API 문서화다. 요즘 REST API는 executable documentation이 대세가 되어가고 있고, django-rest-framework의 Browsable API도 그걸 지원한다. 그런데, 이게 좀 제한적이다. 문서화 기능도 적고, list에 GET 요청을 할 때 파라미터를 줄 수 있는 UI는 없는 것 같아보인다. POST야 그냥 JSON으로만 해도 되서 별 상관은 없지만 필터링 파라미터는 필요한데 아직 어떻게 하는지 모르겠다.
그래서 documenting-your-api라는 문서를 봤더니 자체 Browsable API의 문서화보다 오히려 django-rest-swagger를 추천한다. 이건 swagger integration인데, 이것도 생각보다 쉽게 붙었다. 그런데, 클래스 레벨의 docstring만 파라미터 인식을 하고, 메서드 레벨로는 안되는 것 같다. 한글도 문제가 있는지 에러를 낸다. 하지만, 일단 UI 자체에는 필요한 기능이 다 담겨 있는 것 같다. 일단은 이걸로 좀더 파볼 듯. 처음 원했던 것처럼 손 안대고 코 푸는 건 아직 안되는 것 같다.
비 IT 기업에서 개발자 구인하기
요즘 일자리 제안을 받다가 거절하게 되면 꼭 그 뒤로, 구인을 어떻게 하면 좋겠냐는 질문이 이어진다. 그럼 나도 내 딴에 구인 방법에 대한 조언을 이것저것 해준다. 개발자 채용 같은 글도 쓴 바 있고, 나도 구인이라는 과정의 양쪽 입장을 다 꽤 여러 번 겪어봤기 때문에 해줄 수 있는 말이 그래도 좀 있다. 그런데, 요즘 들어 내가 조언해주기 힘든 상황들이 종종 생긴다. 그건 IT가 핵심이 아닌 기업에서 프로그래밍을 이끌어줄 리더를 뽑는 경우다. 나야 뭐 그런 거 상관 안하는 타입이고, 그냥 한국 회사 부적응자라서 취직 안하는 거지만, 나 같은 사람이 오히려 드물고, 대부분의 실력자들은 IT가 중심이 되거나, 혹은 중요한 드라이브가 될 수 있는 일을 원한다. 그러다보니 좋은 사람 뽑으려면 어떻게 해야 하는가에 적절한 조언을 해주기가 어렵다.
그런 분야들은 실제로 실력자들이 거의 가지 않기 때문에 소프트웨어의 품질 수준도 낮은 경우가 많다. 결함률에 있어서는 무한 테스트(?)를 거치기 때문에 오히려 좋은 경우도 있지만, 사용성이라든가, 성능, 확장성 등등이 떨어져서 10년이 넘은 소프트웨어를 그대로 쓰는데, 고칠 수도 없는 상황이 된 경우도 흔하다.
하지만, 그렇다고 포기할 것인가. 그런 회사들도 좋은 개발자를 뽑아야 하지 않겠는가. 나는 IT 회사를 만들 것이지만, 난 우리 회사의 프로그래머 이외의 직군도 모두 최고의 인재로 채워졌으면 좋겠고, 그건 아마 비 IT 회사도 마찬가지일 것이다.
이런 회사들은 어떤 구인 전략을 취할 수 있을까? 간혹 돈으로 지르는 경우도 보는데, 어느 정도는 효과가 있는 것처럼 보이지만, 충분한 수준은 아닌 것 같다. 아, 물론 돈마저 지르지 않으면 가능성이 아예 없는 것 같긴 하다.
한 가지 금방 떠오르는 건 개발팀 리더에게 높은 의사결정권을 주는 것이다. 개발팀을 알아서 꾸릴 수 있게 하고, 기술 선택 등등 다 자유롭게 하면, 리더급 중에는 그런 재미에 이끌리는 사람이 많을 것이다.
기업 문화도 도움이 될 수 있다. 이를테면 내가 지향하는 실무자 중심주의. 이런 회사들이 어렵게 구한 개발자가 자기들 맘에 안 들면 흔히 "너라도 나가면 안되니까 맞춰주기는 하지만 존나 짜증나" 같은 태도를 보인다. 이런 수준이 아니라 정말로 실무자의 판단을 존중하고, 실무자를 성의있게 설득해나가는 자세가 되어 있는 경영자가 있다면 플러스 요인이 될 수 있을 것이다.
하지만 무엇보다 중요한 건 기술적인 도전 과제가 있느냐가 아닐까 싶다. 해당 기업에서 기술적인 성취를 이루어내고, 또 그 성취를 커뮤니티에 공유할 수 있다면, IT가 중심이냐 아니냐는 아마도 개발자에게 그리 중요한 문제가 아닐지도 모른다. 뛰어난 개발자는 도전 과제를 만날 때 기뻐하고, 과제를 극복해낼 때 성취감을 느끼는 법이니까.
요컨데, IT 기업 평균보다 높은 급여 + 자율성 + 실무자 중심주의 + 기술적인 도전 과제. 이 정도가 내가 생각하는 답인데, 여전히 부족해보인다.
그래서 이 문서는 일단 미결로 남기며, 답을 구할 때마다 고쳐나갈 예정.
----
개발자 몸값 안 올리기에 대한 내 생각
몸값 안 올리기를 처음 읽고 딱 든 생각은, 어, 이거 내 얘기네
였다. 작년에 난 이콜레모를 그만두고 카카오에 입사했다가 다시 그만두고 이콜레모로 복귀했다가 또 요기요에서 제의를 받아 요기요에 입사했다. 카카오에 입사한 것은 물론 돈 보다도 기회라는 관점이 더 컸지만, 어쨋든 돈도 중요한 이유였고, 요기요에 입사한 이유는 80%쯤이 돈이다. 그래서 어쨋든 몸값을 좀 올린 셈인데, 그로 인해서 난 일에서의 행복을 상당부분 잃었다. 이콜레모를 할 때도 물론 스트레스 받는 일이 많았고, 업무 강도도 높은 경우가 많았지만 일 자체는 몹시 재미있었고, 대부분의 시간을 행복감을 느끼면서 일했다. 하지만, 카카오에서 일했던 4개월, 그리고 지금 요기요에서의 2개월은 회사에서의 스트레스를 집에까지 가져오고 있다. 카카오를 그만두었던 가장 큰 이유도 회사에서의 스트레스를 계속 집에 가져오다보니 만삭의 아내와 아기에게 나쁜 영향을 미칠 것 같아서였을 정도니까.
사실 내가 그냥 직원으로 일하는 것 자체에서 즐거움을 못 느끼느냐 하면 그런 건 아니었다. 내가 가장 재미있게 일했던 순간을 꼽으라면 NHN에서 창희형, 정환이형과 함께 일했던 시기, 그리고 오픈마루에서 권남님과 일했던 시기를 꼽곤 한다. 이콜레모에서 일할 때만큼은 아니지만, 매일매일 재미있는 일이 가득했다. 물론 그 땐 연봉이 낮았지. 그래서, 몸값 안 올리기의 내용이 내가 겪는 현상에 대한 적절한 분석인 것처럼 보인다.
하 지만, 그럼에도 불구하고 이의를 제기하고 싶은 부분이 몇 가지가 있다. 우선, 많은 사람들이 지적하는 숫자. 현장에는 안 갔기 때문에 모르고, 기사로 먼저 떴던 것에는 4500만원, 그리고 블로그에는 5만~7만5천불로 기술되어 있는데, 이것 때문에 상당한 비판이 나왔다. 그런데, 사실 이건 김창준씨가 제시한 숫자가 아니라 다른 연구 결과를 인용한 것이기 때문에 이걸 가지고 글에 대한 비난을 하는 것은 적절하지 않다. 다만, 내가 아쉽게 느끼는 것은, 그 숫자가 한계효용이 체감하기 시작하는 지점인지, 한계효용이 0에 가까워져 총효용의 증가가 없는 지점인지가 명확하게 명시되지 않았다는 것이다. 다음 부분을 보면 총효용 자체의 증가가 멈추는 지점인 것처럼 보인다.
그 뿐만 아니라 몸 값이 일정 숫자 이상 오르면 더 이상 행복이 유의미하게 늘지 않는다는 연구 결과[3]도 있습니다. 연구에 따라 다르기는 한데, 5만불에서 7.5만불 사이로 볼 수 있습니다.
하 지만 5~7.5만이란 숫자는 한계효용이 0이 되는 지점으로 보이진 않는다. 저 정도면 기본적인 욕구들이 어느 정도 충족되는 시점이니 한계효용이 체감하기 시작하는 지점이 아닐까 싶다. 물론 연구의 기준에 따라 다르고 저는 그 연구를 모르지만, 보통 사람들이 느끼기에 충분한 금액은 결코 아니니 비난에 휩싸일 수 밖에. 만약 그 연구가 한계효용이 체감하는 지점을 말한 거였다면 단순히 그걸 명확히 하는 것만으로도 비난이 많이 줄지 않았을까 싶다. 아, 물론 그 연구가 실제로 한계효용이 0인 지점이라는 얘기였으면 더 심한 비난을 받았을 수도...
여튼, 이게 첫번째 아쉬움이었고, 두번째 아쉬운 점은, 실제로 연봉을 잘 주는 회사가 더 좋은 회사일 가능성이 높다는 점을 간과했다는 것이다. 아, 물론 여기에 대한 데이터는 갖고 있지 않지만, 대체로 다들 비슷하게 느끼는 것 같다. 연봉이라는 게 회사가 직원을 생각하는 마음이기도 하니, 연봉을 많이 주는 회사는 다른 점에서도 직원에 대한 배려가 더 많은 게 보통이다. 내가 카카오와 요기요 모두 행복하지 않게 일했다고는 하나, 객관적으로 따져서 여기보다 좋은 회사는 한국에 별로 없을 거다. 당연히 그 이하의 보수를 제시했던 곳에 안 간 아쉬움 같은 건 손톱 만큼도 느끼지 않는다. 어차피 오너십을 공유하지 않고 직원으로 일하는 이상 근원적인 차이는 없다고 보면 연봉이 좋은 곳이 대체로 다른 것들도 좋다. 그래서 여전히 연봉 많이 주는 곳으로 이직하는 것은 현명한 선택이다.
세번째 아쉬움도 비슷한 맥락인데, 나도 기본적으로 성공해야 행복한 게 아니라 행복해야 성공한다는 관점에 동의한다. 하지만 그게 월급쟁이일 때는 아니다. 어떻게 보면 이것도 기본적 귀인오류일 수 있다고 본다. 성공이라는 건 개인의 역량도 중요하지만 그에 못지 않게 좋은 기회라는 게 필요하다. 그런데 그냥 월급쟁이로 변변치 않은 회사에 다니면 그 안에서 행복하게 일한다 해도 성공으로 이어질 가능성은 희박하다. 그보다 잘 나가는 회사에 들어갔을 때 성공에 올라타는 것이 훨씬 확률이 높을 것이다. 자신이 스스로 기회를 만들 수 있는 일, 그러니까 창업을 한다거나, 스타트업에 합류한다거나, 주식 투자를 열심히 한다거나 하는 일이라면 개인의 역량이 조금 더 중요하겠지만, 월급쟁이는 어떤 기회를 맞느냐가 더 결정적이고, 기회를 잘 찾아서 올라타는 것도 중요하다. 그런 면에서 적절한 이직 역시 중요하다.
물론 폭넓은 모집단으로 통계를 내면 경향성이 발견될 것이다. 이를테면 1만명 쯤 조사를 하면 그 중에 행복하게 일하는 사람이 아닌 사람보다 평균적으로 더 높은 성공을 거뒀을 것이다. 그런데, 내 옆에 성공한 월급쟁이 친구는 행복하게 일한 친구이기보다는 운 좋게 기회를 잡은 친구일 것이다. 이른바, 빌 게이츠가 선술집에 들어가면 선술집에 있는 사람들의 평균 연봉이 대폭 오르는 효과다.
그래서 행복이 일반적으로 성공에 선행한다고 말하는 것이 옳은 이야기이긴 하지만, 월급쟁이인 나한테 딱히 도움이 되는 이야기는 아닐 수 있다는 것이다.
네번째로, 인생의 행복은 일 바깥에도 있다. 수입이 늘어서 설령 회사에서 좀 행복이 줄었다고 해도 가족과의 삶에서 행복이 는다면 그 총합은 어떻게 되는 것일까? 언젠가 트위터에서 누군가 이런 말을 한 적이 있다.
연봉이 두 배 오르면 두 배 행복해질 것 같죠? 그렇지 않습니다. 열 배쯤 행복해집니다.
빌어먹을 트위터는 검색이 잘 안되서 못 찾겠지만, 여튼 대충 저런 글이었고, 난 꽤 공감했다. 물론 이건 아마도 돈이 없을 때도 행복한 사람들 이야기일 거다. 난 선화랑 연애하기 시작하면서 정말 전에 느끼지 못했던 행복감들을 느끼면서 행복의 절정이라고 생각했는데, 결혼하면서 좀더 행복해졌고, 아파트를 지르면서 좀더 행복해졌고, 차를 몰고 다니면서 더 행복해졌고, 또 아기가 태어나면서 더 행복해졌다. 이 과정에 돈이 기여한 바는 결코 작지 않다.
마지막으로, 연봉을 올리기 위해 이직하는 행위는 사회적으로 유익하다. 나는 아직도 우리나라의 노사 관계가 사측으로 심하게 기울어져 있다고 보며, 노동자들이 더 적극적으로 자신의 권리를 주장해야 개선될 거라고 생각한다. 권리를 위한 투쟁은 민주시민의 권리이자 의무이고, 내가 더 많은 연봉을 받기 위해 노력하는 것은 나 뿐 아니라 다른 노동자들에게도 도움이 되는 일이다. 특히 경력 많고 실력 있는 사람들이 낮은 연봉으로 일하는 것은 후배들에게 엄청난 민폐가 된다. 이것이 내가 이콜레모에서 자기 연봉을 자기가 정하되, 스스로 충분히 만족할 만큼의 연봉을 부르도록 유도했던 이유 중 하나다. (첨언으로 살짝 자랑하자면, 이콜레모 멤버들이 다들 그 때는 스스로 만족할 만한 연봉을 불렀다고 했는데, 이콜레모가 해체된 지금 모두 그 때보다 훨씬 많은 연봉을 받고 있다.)