리팩토링: Avoid return statement with value if you can.

영어로 제목을 쓰려던 것은 아니었으나, “Catch me if you can”을 의식하다보니, 이런 제목이 되었습니다. 사실 영어는 종종 의도를 드러내는데 유리하기도 하구요. 🙂

프로그래밍 언어에서 return문은 아주 중요한 역할을 합니다. 프로그래밍을 수학적 모델로 표현하는데 있어서, 함수라는 개념은 핵심적인 역할을 하고 있으며, 함수의 출력을 받는다는 면에서 매우 중요하지요. 하지만, return문은 독입니다. 왜냐구요? 중요한데 왜 독이냐구요? 이야기를 한번 풀어보도록 하겠습니다.

소프트웨어는 개발 기간이 길어지면, 복잡해지기 마련입니다. 처음 개발할때의 요구사항이 그대로 유지되는 경우는 없다고 보아도 무방하며, 늘어난 요구사항은 처음에 짜둔 아름다운 흐름을 망가뜨리기 시작합니다. 소프트웨어의 구조가 무너집니다. 코드는 점점 스파게티가 되어갈 것이고, 문제라도 생겨서 디버깅이라도 하려고 하면 지옥이 따로 없죠.

이런 코드들을 고통을 감내하며 Sequence Diagram을 그려보면, 왜 복잡한지 드러나는 경우가 많습니다. 클래스별로 호출이 들어갔다가 나오고, 그 결과에 따라서 새로운 분기가 발생하는 사태가 벌어지죠. 그리고, 이 분기의 수가 많아지면, Sequence Diagram은 읽기 힘든 선들의 난잡한 리좀이 되어버립니다. 들뢰즈가 극찬했던 리좀이지만, 각 클래스별의 자유로운 결합과 소통이 아닌 서로를 점점 더 구속하는 꼬인 실이 되어버리죠. 그냥 이정도면 모르겠는데, 반환값이 여러개여야 하는 경우에는 return문을 쓰지 못하고, reference나 pointer를 이용한 억지스러운 반환을 하는 경우까지 발생합니다. 점점 더 복잡해져만 갑니다.

갑작스런 이야기 전환이지만, 전투기에 탑승해서 미사일을 쏜다고 생각해봅시다. 미사일은 날아가고 있고, 그 미사일이 격추 결과를 반환하고, 그 결과에 따라 제어를 해야한다면.. 네, 생각만해도 복잡합니다. 반면에, 그냥 미사일을 쏘고 뭐가 어찌되든 알아서 해결된다고 하면, 편안하죠. fire-and-forget입니다. call-site에선 신경쓰지 않는겁니다. callee쪽에서 알아서 하겠죠 뭐.

함수를 호출하는데 있어서 그 결과값에 신경써야 한다는 것은 상당한 위험성을 내포하고 있습니다. 단순한 수학 연산이나, 문자열 검색같은 피할수 없는 반환값이라면 모르겠지만, 소프트웨어가 구현하는 Business Logic이라면, 그 결과값에 따른 논리구조의 분기는 피할 수 없습니다. 결과값이 존재한다는건, 그 결과값에 따라 무언가 다르게 하려고 했기 때문일테니까요. 그리고, 그 분기는 요구사항이 늘어나면 늘어날수록 두고두고 당신을 괴롭히겠죠.

Sequence Diagram을 생각해봅시다. return문이 없다면, 함수호출을 의미하는 화살표만 있으면 됩니다. 반환값에 따른 분기도 없을테고, 분기가 일어나는 시점은 바로 그 분기조건을 확인하는 그 순간입니다. 더욱 간단해지죠. 그래봐야 Sequence Diagram이 복잡해지는건 매한가지 아니냐? 라고 생각할 수 있겠지만, 원래 복잡한 논리구조를 표현하는데 복잡한건 당연하겠죠. 다만 그 복잡함을 따라가는데 얼마나 더 쉬운가를 이야기하는 겁니다.

이렇게 짜다 보면, 어떤 객체의 상태변화에 대해서 반응하는 코드를 구현하기가 어려워집니다. 이때 사용하는 기법이 Callback이고, Callback을 사랑하는 이유죠. Callback은 대부분의 경우, 직관적이지 못하다는 이유로 배척당하곤 하는데, 간단한 소프트웨어의 경우엔 그렇습니다. 하지만, 복잡해지면 복잡해질수록 그 진가를 발휘하곤 하죠. 특히, 복잡해지면서 유사한 상태변화가 늘어날 경우에 더더욱 심해집니다. Callback기법을 적절히 사용하고 있다면, 해당 상태변화가 감지되었을때, 그 감지에 대한 분기를 추가하는 것이 아니라, 미리 지정된 Callback을 호출하기만 하면 되니까요. 이렇게 하면, 소프트웨어의 실행흐름을 Input Layer -> Business Layer -> Reaction Layer로 나누게 됩니다. 그리고, Reaction Layer를 만들때 Callback을 활용하게 되죠.

이는 객체지향 패러다임의 원칙중 하나인 Encapsulation과도 관계가 있습니다. Encapsulation이 필요한 데이터만 노출해서 소프트웨어를 간단하게 만든다면, 이번에 제시하는 이 원칙은 대부분의 분기를 감추는 것으로 소프트웨어를 간단하게 만든다고 볼 수 있지요. 또한, Callstack을 보는 것 만으로 분기가 어떻게 일어났는지 확인할 수 있다는 장점도 있습니다. 재현가능한 버그라면 모르겠지만, 소프트웨어가 비정상종료 되면서 남긴 제한적인 Callstack정보로 디버깅을 하는 경우에는 더더욱 유리해집니다.

이게 뭔소리냐. 하실 수 있겠지만, 제목에 if you can이 붙은건 가급적이면 피하라는 이야기입니다. 반환값을 가진 return문은 결국 호출측에서의 분기를 유발하게 되고, 그 분기는 소프트웨어를 복잡하게 만들 가능성을 내포하고 있으니까요.

 

개인정보의 관리책임

개인정보 보호 전문기업에서 일한지 12년이다. 그리고, 그 짧지 않은 기간 동안 이렇게 전 국민적인 관심을 몰아받는 보안사고도 없었다. 단언컨데, 이건 최악의 “개인정보 유출 사고”다. 보는 관점에 따라서는. 이를 한 하청업체 직원이 작심하고 개인의 금전적 이익을 위해 빼돌린 범죄 사건이라고 볼지, 아니면 금융당국의 허술한 보안 체계에 의해 발생한 사고인지는 사건을 바라보는 사람에 따라 각양각색이겠지만, 보안전문가 입장에서는 단연코 사고다. 아직까지는.

사건의 개요를 잠시 되짚어보자면, 코리아 크레딧뷰로(이하 KCB)가 농협, 국민카드, 롯데은행에 가서 외주 프로젝트(카드 분실, 유실, 위변조 관계 시스템 개발)를 수주했고, 이 프로젝트를 진행하기 위해 파견된(!!!) KCB의 직원이 위의 3개 금융사에서 정보를 빼돌렸다는 것이 주된 골자다. 그 과정에서 어떻게 이렇게 쉽게 그 정보가 빠져 나갈수 있느냐! 라고 일갈하기는 쉽겠지만, 보안이라는 것도 생각보다 복잡하다.

정보와 관련된 보안은 보통 외부침입과 내부유출로 나뉜다. 이번의 농협말고, 2011년의 “농협”사건은 외부침입이다. 물론, 외주직원이 매개체가 되었지만, 그 외주직원의 의지가 아니었다. 북한의 소행이네 어쩌네 하는 말이 많았지만, 진실은 저 너머에 있으니 차치해두고 이야기하자면, 해당 정보를 관리하는 조직 내에 속한 사람이 아닌, 외부의 누군가가 용케 쳐들어와서 정보를 들고 날랐다는 소리다. 더 쉽게 말하자면, “강도질”. 반면에, 이번의 사건은 내부유출이다. 관계자가 내부의 개인정보를 들고 빼돌렸다는 이야기다. 즉, “배임행위”다.

헌데, 외부침입과 내부유출의 스케일을 비교해보면 이건 압도적으로 내부유출의 승리다. 놀라울 정도로 금융쪽 사고들과 닮아있다. 은행강도와 배임행위를 비교해보면 된다. 은행강도는 쳐들어와도 끽해야 몇억정도 털어가고 금고부숴지는 정도지만, 배임행위는 그 액수가 기본 수십억에서 수백억에 이른다. 스케일이 다르다. 개인정보쪽도 마찬가지다. 수십만건이 털렸으면, 그건 외부침입일 가능성이 크고, 이번 건처럼 수천만건이 털렸으면 내부유출일 가능성이 높다.

왜냐? 이유는 간단하다. 최근의 IT시스템들은 굉장히 복잡하다. 쉽게 말하자면, 책이 엄청나게 많이 꽂혀있어서 사서의 도움없이는 책을 찾을 수 없는 도서관을 생각하면 된다. 그 도서관에 불을 내고 몇권 훔쳐가는거랑, 그 도서관의 사서가 굉장히 비싼 일부 서적만 빼돌리는 것의 차이는 명확하다. 그렇다. 바깥에서 들어오는 도둑놈 막는 것도 중요하지만, 내부자들을 단속하는 것도 중요하다. 내부자는 비싼게 어디에 얼마나 있는지 정확하게 알고 있을테니까.

그런 이유로, 최근 기업들이 도입하는 수많은 보안솔루션들의 초점도 내부유출방지에 있다. 만약, 새로 설계하는 시스템들이라면, 설계단계에서 이미 개인정보에 대한 접근 가능성부터 관리부분까지 전부 신경써서 만들고, 이를 보조하는 형태로 보안 솔루션을 도입하고, 그게 아닌 기존의 시스템이라면, 기존 시스템의 유출 가능 경로들을 분석해서, 그 경로에 맞는 보안 솔루션을 도입하는 것이 일반적이다.

그리고, 정부에서는 각 기업에서 보안 솔루션을 도입할때 반드시 갖추어야할 기본 사항들에 대해서 법으로 지정하고 있다. 주로, 개인정보보호법과 정보통신망법인데, 이 두 가지 법안은 개인정보를 취급하는 기업에서 이를 처리하는 시스템에 대해 어떤 보안조치를 해야하는지에 대해 기본적인 사항들을 명시하고 있다. 이런 법안은 사실, 일부 잘나가는 기업들이 보안솔루션을 도입해서 사용하고 있는 상황에서, 개인정보 유출 사고들이 터지기 시작하니, 만들어진 법안이다. 그리고, 각 기업/기관들은 이 법안에서 명시한 사항들을 지키기 위해 솔루션을 도입하고 있다. 이런 상황이다보니 이제야 도입하는 기업/기관들은 이게 잘 될리가 없다. 왜냐? 처음에 사용하던 잘나가는 기업들과는 도입이유가 다르니까.

잘 나가는 기업들이 도입한 이유는 자신들의 기술자산을 보호하기 위해서다. 더 정확히는, 기술자산에 접근 가능한 인력들이 다른 생각을 못하도록 하기 위해서다. “우리는 기술자산에 이렇게 신경써서 보안적 조치를 하고 있다. 만약, 네가 이를 유출한다면, 이하 생략이다”라는 이야기를 하는거다. CCTV가 있는 곳의 범죄율이 낮다는 이야기와 동일한 논리적 구조다. 실제로 역할도 비슷하고.

하지만, 법을 준수하기 위해 기업/기관들이 도입한 내부정보 유출방지 솔루션들은 법에 정의된 항목을 만족시키기 위해 도입한 시스템이다. 내부유출방지에 도움이 되냐고? 당연히 된다. 잘 나가는 기업들에게 엄청나게 두들겨 맞으면서 만든 제품들인데, 도움이 안되는게 이상하지 않을까? 문제는 그 시스템들을 운영하는 주체-주로 보안팀-에게 있다. 반복적이고 지속적으로 내부자들을 귀찮게 하면서, 이런 정보를 함부로 다루면 안된다고 이야기해야하는데, 이게 말처럼 쉽지 않다. 내부정보 유출방지 솔루션들이 설치되면 당연히 인터넷도 불편하고, PC활용도 불편해진다. 이렇다보니, “일 못해서 손해나면 당신이 책임 질거야?” 류의 항의들이 들어오고, 유출방지 솔루션들은 하나 둘씩 무기력해진다. 그리고, 내부자들은 일을 더 중요하게 생각하게 되고, 개인정보에 대한 중요도를 잊게 된다. 그리고, 배고프면… 뭐… 게!다!가! 이번 사건으로 돌아와보면, 무려 외주직원이다. 더 이상 무슨 말이 필요한지…

이래서 사고라는 거다. 내부정보 유출방지를 위해 해야할 것들이 다 이루어지지 않은 상태에서, 일어난 일이니 사고라는 거다. 만약, 잘 나가는 기업에서 기술자산이 2014년에 유출되었다면 이는 사건이다. 필요한 보안 조치들과 이에 대한 문화적기반(?)이 모두 구축이 되어있으니까. 하지만, 2013년 6월의 유출은 사고다. 미리 대비하지 못한 사람들이 만들어낸 인재.

ps. 비현실적인 이야기라고 할 수 있겠지만, 대부분의 유출사고는 결국 배고파서 일어난다. 은행 직원들 월급 많이 받는다고 말이 많지만, 월급이 적으면, 은행들 다 털리고 난리도 아니겠지. 개인정보도 비슷하다. 민감한 정보를 외주업체들한테 그만 맡기고, 필요한 인력은 직접 채용해서들 쓰시라.