똑똑한 개발자들을 바보로 만드는 방법

오늘 티맥스 OS 발표 및 시연이 있었다. 유투브로 생중계된 발표를 많은 개발자들이 지켜보았고, 유투브 대화창, 트위터, 페이스북에는 티맥스 OS에 대한 조소와 비난이 넘쳐났다. “자체 개발”을 강조했지만 FreeBSD, LibreOffice, Chromium, Wine 등 수많은 오픈소스를 가져다 썼다는 사실을 숨길 수가 없었고, 그럼에도 불구하고 짧은 시연 중에도 OS가 멈추는 등 완성도 면에서 불안한 모습을 보였다.

티맥스가 그저 이상한 사람들이 보인 별 것 아닌 회사였다면 오늘 티맥스 OS 발표는 그저 웃고 넘길 수 있는 해프닝으로도 끝날 수 있는 일이다. 문제는 티맥스가 지금도 500명 이상의 직원이 일하는 시스템 소프트웨어 개발에 있어서는 국내 최고 수준의 회사라는 점이다. (참고로 7년 전 OS 발표 시에는 2000 명 이상 있었다)

티맥스에서 일하는 엔지니어들은 바보가 아니다. 한 명 한 명을 놓고 보면 존경심을 가져도 좋을 만큼 국내 최고 수준의 엔지니어들도 다수 일하고 있다. 그런데 이렇게 좋은 엔지니어들이 모인 조직에서 만든 소프트웨어가 발표만 하면 조롱이 대상이 되고 있다. 뭐가 잘못된 것일까?

난 티맥스에서 일을 한 적도 조직의 내부도 들여다 본 적이 없지만, 국내에서 소프트웨어 개발이 이루어지는 양태를 보면 그 이유를 어렵지 않게 짐작할 수 있다. 결론부터 이야기하면 기술적으로 중요한 의사결정을 내려야 하는 사람들이 그 결정을 내릴 수 있을 만큼의 실력이 없다.

이와 관련해서 내 경험을 이야기해보고 싶다. 난 작년 5월 회사를 그만두기 전까지 한 중소 기업의 CTO로 웹킷/크롬 기반의 브라우저 기술을 7년간 개발했다. 그 중 마지막 2년은 삼성전자와 일을 하였다. 당시 계약한 기술은 TV에서 웹킷의 렌더링 속도를 향상시키기 위한 멀티코어 및 GPU 가속 솔루션이었다.

당시는 Chromium이 아직 임베디드 시스템에 사용되기 전이라 WebKit2 최신 버전을 기준으로 해당 내용을 작업했었다. 각 가속 기술 자체는 PC 환경에서 유의미한 수준의 성능 향상이 있었고, 이를 근거로 삼성TV에 포팅하는 프로젝트를 1년간 진행했었다.

하지만 프로젝트를 진행이 매끄럽지는 않았다. TV는 1년 단위로 신규 제품을 출시하는데 매년 칩셋이 바뀌기 때문에 이와 관련된 드라이버나 운영체제 버전 등이 모두 교체된다. 특히, GPU 드라이버는 안정성이 떨어져서 프로젝트 내내 문제를 일으켰다. 성능도 안정적이지 않아 똑같은 바이너리가 운영체제 버전에 따라 100% 이상의 성능 차이를 보이는 경우도 흔했다.

특히, 일부 가속 기술은 지속적으로 문제를 일으켰다. 성능 향상을 위해 코드가 지나치게 복잡해지면서 유지보수가 힘들어진 면도 있고, GPU 드라이버에서도 예상치 못한 버그들이 발견되면서 안정성 문제가 계속 이슈가 되었다. 당시 실무 엔지니어들은 당연하게도 문제가 되는 일부 가속 기술을 포기하는 것이 제품의 성능 측면에서는 더 낫겠다는 판단을 했었다.

문제는 의사 결정을 내리는 결정권자들은 이런 상황을 전혀 이해하지 못한다는 점이다. 개발 책임자라고는 하지만 자기가 만드는 제품의 코드 한 줄 본 적이 없는 사람이, 성능 향상을 위해 코드의 복잡도가 얼마나 증가했고 이게 앞으로 제품 양산에 어떤 식으로 영향을 미칠 것인지에 대해 판단을 내리는 것은 불가능하기 때문이다. 그저 전년 대비 올해 성능이 얼마 향상되었는지를 윗선에 보고하는 것에만 관심이 있다.

CTO로 해당 솔루션 개발을 총괄한 나의 책임도 있다. 삼성과의 계약 관계가 아닌 단독 프로젝트였다면 문제가 되는 상황에서 해당 기술을 포기했을 것이다. 하지만 삼성과의 계약 조건이 문제였다. 해당 기술을 탑재하는 것으로 계약을 했는데, 안정성이나 기타 이유로 해당 솔루션이 출시되는 제품에서 빠지면 이번 계약은 물론이거니와 후속 계약에도 영향을 미칠 것이 틀림 없기 때문이다. 그리고 계약의 연장 여부는 회사의 존폐와 진결된다.

결국 객관적으로는 문제가 되는 가속 기술을 제품에 탑재하지 않는 것이  정답이었음에도 불구하고 각자의 이해 관계 때문에 아무도 이런 결정을 내릴 수가 없었다. 그리고 그 책임은 고스란히 실무 엔지니어들이 떠 안고 밤을 새면서 프로젝트를 진행해야만 했다. 하지만 이미 중요 의사 결정이 잘못 내려진 상태에서 엔지니어들이 아무리 노력을 해봐야 제품의 안정성을 확보하는 게 불가능에 가깝다.

소프트웨어 개발에서 이런 시행 착오가 없을 수 없다. 성능은 아이디어가 있어서 열심히 구현하면 반드시 나온다. 이런 건 대학을 갓 졸업한 똑똑한 개발자면 누구나 한다. 문제는 성능이 10% 개선된 대신에 뭐가 희생되었는지를 판단할 수 있는 능력이다. 코드가 지나치게 복잡해지지는 않았는지, 안정성에 문제가 생기지는 않았는지 종합적으로 판단해서 아닌 건 아니라고 할 수 있는 게 엔지니어의 경험이고 연륜이다. 하지만 우리나라에는 이런 경험이 없다.

반면 웹킷 오픈소스 활동을 하면서는 전혀 다른 모습을 보았다. 구글, 애플 엔지니어들은 무서울 정도로 코드의 품질에 집착한다. 모든 패치에 대해 한 줄 한 줄 리뷰를 수행하고, 상당한 성능 향상이 있더라도 코드가 지나치게 복잡해지면 과감하게 포기하고 다른 방법을 찾는다. 처음 웹킷 버그질라에 패치를 제출하고 받은 리뷰는 너무 충격적이라 아직도 기억이 난다.

난 티맥스의 상황이 내가 삼성에서 일하면서 느꼈던 상황과 다르지 않다고 생각한다. 의사 결정권자들이 자신들의 필요에 의해 성능이든, 기능이든 여러 요구사항을 제시했고, 이게 실제 코드에서 어떤 형태로 반영되고 어떤 문제를 일으키고 있는 지에 대해 전혀 이해하지 못하고 있을 거다. 겉으로 보기에 거의 다 만들어졌으니깐 개발자들 열심히 굴리면 몇 달 후에는 안정적인 버전이 나올 거라고 기대하고 있을지도 모르겠다.

그리고 티맥스만의 문제도 아니라고 생각한다. 정도의 차이가 있을 뿐 대부분의 회사가 마찬가지다. 그저 나이가 많다는 이유로 개발에 대한 깊이 있는 이해와 실력도 없이 개발 업무에 전반에 관해 중요한 의사 결정을 내리고 있는 40대 이상의 의사결정권자들이 우리나라 소프트웨어 산업, 그리고 젋은 개발자들의 미래를 망치고 있다고 생각한다.

이들이 과거에 코딩을 했는지 아닌지는 중요하지 않다. 지금도 부지런히 공부하고, 코드 읽고, 현업 개발자들이 어떤 문제로 고민하고 있는지 같이 고민하고 해결해 줄 수 있어야 한다. 이런 경험 많고 노련한 개발자가 의사 결정권자가 되지 않으면 우리나라 소프트웨어 산업에 미래는 없다.

소프트웨어 개발에서 선행 개발 조직의 의미

소프트웨어 기술 기반의 스타트업을 하면서 필연적으로 국내 제조 기반의 대기업과 오랜 기간 일을 했습니다. 제조 회사 내의 소프트웨어 개발 조직의 문제점을 열거하기 시작하면 끝이 없겠지만, 오늘 이야기할 문제점은 선행 개발에 대한 이야기입니다.

제조사에서 일을 한 경험이 없는 개발자는 선행 개발의 의미를 잘 모를 수 있습니다. 선행 개발이란 당장 출시 제품에 탑재될 소프트웨어가 아닌 작게는 1-2년 멀리는 3-4년을 내다보고 새로운 기술을 프로토타이핑해보는 것을 말합니다. (제가 경험한 과제는 대부분 1년 이하였습니다.)

물론 사전적인 의미의 선행 개발은 나쁠 것이 없습니다. 소프트웨어를 한 번 만들어보는 것만큼 요구사항을 확실히 이해하고, 제대로 된 설계를 도출해 내는 방법이 없기 때문입니다. 제품 출시라는 제약이 없기 때문에 좀 더 실험적인 아이디어를 적용해 볼 수도 있습니다. 선행 개발은 가장 값비싼 소프트웨어 개발 방법이기 때문에 대기업이 아니면 사실 시도해보기도 어렵습니다.

여기까진 좋습니다. 하지만 국내 제조 대기업들은 이런 선행 개발의 장점을 전혀 못 살리고 있는데 이유는 크게 두 가지입니다.

1) 선행 개발의 목표는 경험이 아닌 산출물이다.

선행 개발의 목표가 개발자들이 지식과 경험을 쌓는데 있지 않고 양산에 사용할 수 있는 유형의 산출물을 만드는데 있습니다. 프로젝트 자체가 실패하더라도 거기서 얻은 경험을 통해 다음 제품에서 시행 착오를 줄이는 것이 아니라, 선행 과제도 어쨌든 과제 책임자가 있고 실적을 평가해야 하고 결과에 대해 책임을 져야하기 때문에 실험적인 시도를 하기가 어렵습니다.

2) 선행 개발 조직과 양산 조직이 완전히 분리되어 있다.

선행 개발 조직과 양산 조직이 철저하게 나뉘어 있습니다. 때문에 선행 개발을 통해 얻은 경험은 선행 개발팀만 가지게 되고, 선행 개발을 통해 나온 결과물만 공유 받은 양산팀은 사실상 기술 부채만 떠안는 꼴이 됩니다. 당연히 양산팀은 선행 팀이 만든 산출물을 제품에 활용하기가 어렵습니다. 덕분에 양산팀은 선행팀이 제품을 모르는 아마추어로 생각하는 경우가 많습니다.

선행 조직의 예산에 대한 문제도 시행착오를 거듭하고 있습니다. 회사가 여유 있을 땐 자율성이란 명목으로 선행 조직에 독립적인 예산을 줍니다. 회사가 어려워지면 가장 만만한 것이 선행 조직이라 과제를 축소하고, 예산권을 뺏어서 양산 조직으로 넘깁니다. 이렇게 되면 선행 조직은 회사 내의 을이 되어 양산 조직이 시키는 일만 수동적으로 하게 됩니다.

제조 기업이 소프트웨어 역량을 제대로 갖추려면 제조 기반의 선행 개발 방식을 과감히 버리고 소프트웨어 개발 조직을 하나로 통합해야 한다고 생각합니다. 정말 10년 이상을 내다보고 논문과 특허를 준비하는 연구 조직은 따로 유지하고, 선행 개발 조직과 양산 조직을 하나로 통합하여 제대로 된 제품 개발을 해야 합니다.

그리고 조직 통합만 하면 사람 내보낼 생각을 할 게 아니라 개발자를 더 뽑아야 합니다. 하루 12시간 이상 일을 해도 매일 리포팅되는 버그조차 제대로 해결하지 못하는 양산 조직에서 좋은 소프트웨어 개발을 기대하는 것 자체가 어불성설입니다.

자바스크립트 튜플 만들기

자바스크립트에는 튜플이 없어요. 1과 “abc” 두 개의 값을 변수에 저장하거나 리턴하려면 오브젝트 리터럴을 만들거나 배열에 저장해야 하는 불편함이 있지요.

> {n: 1, s: "abc"}
{ n: 1, s: 'abc' }
> [1, "abc"]
[ 1, 'abc' ]

오브젝트 리터널은 각 필드마다 이름을 지어줘야 하고, 배열은 길이가 고정되어 있지 않죠. 매번 여러 개의 값을 변수에 저장하거나 리턴할 때마다 불편함을 감수하며 살던 자바스크립트 개발자는 어느날 곰곰이 생각을 해요.

“튜플이란 게 별 것 아닌데… 그냥 (1, “abc”) 이런 걸 표현할 수 있으면 되는 거잖아. 원소 a, b를 들고 있는 데이터 타입이니 (a, b)”

하지만 자바스크립트는 어쨌거나 튜플 타입이 없기 때문에 “(a, b)”라는 타입을 어떻게 만들어낼 수 있을까 고민에 고민을 거듭했어요.

그러다가 문득 비동기 프로그래밍에 사용하는 callback (continuation) 개념을 떠올렸어요. a라는 값은 사실 a를 인자로 r을 리턴하는 함수 (a -> r)을 인자로 받아 다시 r을 리턴하는 고차 함수로 표현할 수 있다는 개념이죠.

a ~is isomorphic to~ (a -> r) -> r

예를 들어 var a = 1을 다음과 같이 표현할 수 있죠.

function makeA(a) {
return function cont(f) {
return f(a);
};
}

function id(x) {
return x;
}

var a = makeA(1);

a(id)를 호출하면 1이 나오니깐 두 코드는 완전히 똑같아요.

같은 방법으로 (a, b)도 ((a, b) -> r) -> r 함수로 표현하면 되겠다고 생각했어요. 자바스크립트에 (a, b)라는 타입은 없지만, 자바스크립트 함수는 인자를 여러 개 받을 수 있으니깐 (a, b) -> r이라는 타입은 가능하다는 것에 착안을 한거죠. 이런 타입을 갖는 함수는 사실상 하나 밖에 없으니깐 구현은 간단했어요.

function makePair (a, b) {
return function (f) {
return f(a, b);
};
}

이제 makePair(1, “abc”)라고 하면 (1, “abc”) 튜플이 만들어지게 되었어요. 이렇게 만든 튜플을 사용하려면 첫 번째 원소와 두 번째 원소를 끄집어 낼 수 있는 함수 fst와 snd 함수가 필요하겠죠?

튜플 p 자체가 (a, b) -> r 타입의 함수를 인자로 받아 r을 리턴하는 함수니깐, fst와 snd의 함수 구현도 정해져 있는 것이나 마찬가지에요. fst가 p에 넘기는 함수의 타입은 (a, b) -> a가 되고 a와 b 중에서 a를 리턴하면 되죠. snd가 p에 넘기는 함수의 타입은 (a, b) -> b이니깐 a와 b 중에서 b를 리턴하면 되고요.

function fst (p) {
return p(function (a, b) { return a; });
}

function snd(p) {
return p(function (a, b) { return b; });
}

자 이제 자바스크립트도 튜플 생성자와 첫 번째, 두 번째 인자를 끄집어낼 수 있는 함수를 가지게 되었어요.

> var p = makePair(1, "abc");
> fst(p);
1
> snd(p);
"abc"

프로그래밍 즐거우세요?

프로그래밍 혹은 개발을 잘한다는 건 무슨 뜻일까요? 소프트웨어 엔지니어링, 애자일을 위시한 각종 소프트웨어 개발 방법은 누굴 위한 걸까요? 개발자의 생산성 혹은 효율이란 단어는 대체 뭘 말하는 걸까요? 기업 입장에서 생산성 혹은 효율은 명료합니다. 투자한 비용 대비 이익(ROI)로 이해하면 되기 때문입니다. 소프트웨어 개발의 효율은 생산 비용(주로 개발자의 임금) 대비 산출물(개발된 소프트웨어) 양과 품질입니다.

기업 입장에서 좋은 개발자란 돈 적게 받고 품질 좋은 소프트웨어를 많이 만들어 주는 사람을 말합니다. 물론 소프트웨어의 품질은 정성적이기 때문에 요구사항 이해, 설계, 코딩, 테스트 뿐만 아니라 고객과의 커뮤니케이션, 협업, 개발 문화 등 여러 세부 사항에 대한 경험과 노하우가 필요합니다.

이렇게 기업 관점에서 ROI를 높여주는 개발자를 우리는 보통 좋은 개발자라고 부릅니다. 원활한 인력 수급을 위해 보수적인 기술 스택을 선택하고, 출시 일정을 맞추기 위해 일정 부분 코드 품질을 포기할 수도 있어야 하고, 테스트는 필요한 수준으로만 적절하게 해야 소위 프로페셔널입니다.

하지만 묻고 싶습니다. 그렇게 일을 하면 즐거우세요? 출시일을 맞추기 위해 철야를 하고 코드는 동료들에게도 보여주기 부끄러울 만큼 스파게티가 되었어도 제품만 성공하면 그만인가요? 맨날 똑같은 기술에 똑같은 일을 똑같이 반복해도 성과를 냈으니 프로페셔널한 개발자라고 자부하고 계신가요? 그건 개발의 재미가 아니라 성공의 재미입니다.

개발은 재미가 있어야 합니다. 같은 문제도 매번 다른 방법으로 풀어보고, 새로운 기술도 과감히 도입해보고, 반복되는 문제들을 자동화하고, 당장의 생산성과 거리가 있어도 기술적으로 흥미 있는 문제를 풀어볼 여유도 필요합니다. 단순히 홈페이지를 하나 만들어도 그저 빨리 산출물을 내는 것과 개발의 즐거움을 추구하면서 새로운 방법을 시도하는 것 사이에는 큰 간극이 존재합니다.

물론 사업이야 망하든 말든 내가 좋아하는 기술만 하라는 이야기는 아닙니다. 하지만 반대로 개발자 스스로가 철저하게 ROI 관점에서만 소프트웨어 개발을 바라보고 개발 생산성만 이야기하면 개발자가 응당 누려야 할 기술적 즐거움을 자기 스스로 차버리는 것이나 마찬가지입니다.

기업의 이해와 개발자의 이해는 달라야 합니다. 개발자는 임금의 대가로 사업이 성공할 수 있도록 노력할 의무가 있지만, 동시에 재량껏 기술적 즐거움을 추구할 권리 또한 있습니다. 그리고 적절한 선은 기업이 결정해 주는 것이 아니라 개발자가 스스로 찾아서 기업과 끊임 없이 협상해야 합니다.

XP든, 스크럼이든, 디자인 패턴이든, 테스트 주도 개발이든, 함수형 프로그래밍이든 중요하지 않습니다. 아무리 새로운 아이디어가 나와도 그 아이디어가 기업 입장에서 소프트웨어 개발자의 생산성을 높이는 것 하나에만 초점이 맞춰지는 순간 이미 개발자 입장에서는 경계해야할 대상이 됩니다. 최근 개발자들 사이에 애자일 방법론에 대한 비판이 커지는 것도 애자일 방법론의 내용이 바뀌어서가 아니라, 애자일이 기업 입장에서 개발자의 효율을 높이는 방법론으로 편입되었기 때문입니다.

개발의 즐거움을 되찾으세요. 하지만 소프트웨어 개발자에게 전통적인 의미의 노동 쟁의는 어울리지 않습니다. 파업을 한다고요? 아니 왜 좋아하는 개발을 자발적으로 중단합니까? 즐겁게 개발하세요. 새로운 기술도 배우고, 코드 품질도 높이고, 동료 개발자들과 교류하세요. 회사의 이익을 위해, 제품을 위해, 프로페셔널하기 위해 개발자의 즐거움을 희생하지 마세요.

조직 기술

개발자의 프로그래밍 능력을 크게 두 가지로 분류하라고 하면 알고리즘 기술과 조직(organizational) 기술로 나눌 수 있다.

알고리즘 기술은 작게는 stack, heap, hash table, balanced binary tree, sorting 등을 얼마나 잘 이해하고 구현할 수 있는지를 의미하고, 크게는 주어진 문제를 컴퓨터로 어떻게 풀 것인지 생각하여 답을 내는 사고 능력을 의미하기도 한다.

반면 조직 기술이란 소프트웨어의 복잡도를 줄이고, 수정 및 유지보수의 편의를 증대시키는 모든 종류의 기술을 통칭한다. 작게는 함수나 변수 이름을 잘 짓는 것부터 시작해서, 크게는 디자인 패턴, 리팩토링, 아키텍처, DSL 등을 망라한다.

혹자는 알고리즘이 문제다라며 알고리즘을 강조하지만, 사실 알고리즘의 중요성은 이미 대중적으로 널리 알려져 있고 충분히 강조되고 있다. 정보올림피아드나 ACM-ICPC 같은 프로그래밍 대회에서 알고리즘 문제를 출제하고 있고, 대학에서도 최소 2-3개 이상의 데이터 구조와 알고리즘 과목을 전공 필수로 가르치고 있다. 더불어 구글, 페이스북, 마이크로소프트 등 많은 기업들이 입사 면접에 알고리즘 문제를 출제하고 있기도 하다. 우린 이미 알고리즘 기술 없이 좋은 개발자란 평가를 받기 힘든 시대에 살고 있다.

반면 프로그램을 잘 작성하기 위해 필요한 조직 기술은 간과되고 있다. Organizational Skills Beat Algorithmic Wizardry라는 글에서도 비슷한 문제 제기를 하는데, 조직 기술은 명확한 기준도 평가 방법도 없기 때문에 상대적으로 기준이 명확한 알고리즘 기술만 강조되는 면이 있다. 하지만 대부분의 개발자가 정작 필요로 한 기술은 알고리즘 기술이 아니라 조직 기술인 경우가 많다. 앱이든 웹서비스든 수많은 요구사항을 코드로 반영하고, 지속적으로 수정, 유지보수할 필요성이 있기 때문이다.

복잡한 알고리즘 문제를 풀고 힘들게 입사했더니, 정작 출근 첫날 주어진 업무는 서비스 중인 웹페이지의 버튼을 1px 옮기는 일이었다는 말이 농담만은 아니다.