소프트웨어 개발/ 문제 해결하기
글을 올릴까 말까 수줍어 하지 않아도 된다는 걸 깨달았다. 페북에 공유를 안 하니까 조회수가 안 올라간다. 그래서 2편을 곧바로... 흐흐...
C.S.I 라는 미국드라마가 있다. 범죄에 대해 과학적으로 객관적인 사실들을 다각도로 분석하여, 그결과를 기반으로 범인을 잡는 그런 드라마이다. 소프트웨어 Integrator로서, 문제를 해결해 나가는 일은 과학수사대가 하는 일과 비슷한 부분이 많다. 편견 없이 객관적으로 사실들을 파악해 내야 하고, 사실들을 기반으로 가설을 세우고, 이를 증명하는 과정들이 필요하다. 이 글에서는 문제 해결을 해 나가는데 있어서 기억해야 할 중요한 원칙들을 얘기해 보고자 한다.
문제를 해결하기 위해서 가장 중요한 것은 “문제를 정확히 정의” 하는 일이다.
김밥을 하나 만드려면 그에 필요한 밑준비들이 필요하다. 밥도 해 놓고, 지단도 만들고, 채소도 볶아 놓고... 이러한 밑준비들이 다 끝나야 비로서 김밥말이가 등장하여 김밥을 하나씩 말 수 있게 된다. 문제 해결도 과정이 필요하다. 소프트웨어 Integrator 는 기본적으로, 문제를 해결하는 사람이 아니라, 문제를 해결할수 있도록 그 과정을 이끄는 사람이다. 즉, 김밥을 마는 사람이 아니고, 김밥을 누군가 말 수 있도록 밑준비를 다 해 주는 사람이다.
문제를 정의한다는 것은 그 문제를 반복적으로 재현할 수 있도록 만든다는 것이다.
일반적으로 1차적으로 오는 리포트는 매우 부정확하다. 특히 그 리포트가 일반 사용자로부터 오는 것이라면 더더욱 그러하다. 인터뷰를 통해서 일단 최대한 정보를 추출해 내야 한다. 이 정보를 기반으로 보고된 문제를 재현을 한다. 매우 명확한 시나리오를 찾아서 항상 재현할 수 있게 되면 사실 끝난 게임이다. 내가 하든, 니가 하든, 해결하면 된다. 어려운 것은, 문제가 거의 재현되지 않는 상황이다. 흔히 롱런 테스트에서 이런 상황들이 오게되는데, 이런 경우는 문제를 정의하기 위해서는 한발 더 나아가야 한다.
수치화를 해야 한다.
롱런 테스트를 하다가 소프트웨어가 죽는 문제가 생겼을 때, “이게 아닐까?” 라고 해서 수정한 다음에 다시 돌려보고, “여전히 죽는다” 따라서, “그건아니다” 라는 결론을 내는 경우들이 자주 있다. 소프트웨어가 한가지 문제로 죽고 있는지, 여러 문제로 죽고 있는지도 파악이 안 된 상태이므로, 문제가 생기는 빈도와 패턴을 보지 않고, 단순히 “또 죽었습니다. 해결되지 않았네요”라고 하는 것은 매우 위험하다.
이러한 잘못된 분석을 피하기 위해서는, 문제 상황을 수치화시켜서 파악할 필요가 있다. 가령, “주말에 소프트웨어를 켜 두고 갔는데 죽었다” 라는 리포트가 왔다고 하면, 가장 먼저 해야 할 일은, 테스트 대상을 넓히고, 기간을 잡아서, “이틀 동안, 10개 중에 5개가 죽는다” 같은 수치를 뽑아내는 일이다. 그래야 다시 돌릴 때 어느 정도의 기간을 돌릴 것인지, 증세가 완화되었는지, 그대로인지 등을 비교해서 판단해 나갈 수 있다.
문제를 정의하기 위한 테스트를 할 때는 기록을 꼼꼼히 하는 것도 중요하다. 오래 전 일인데, 아무리 테스트를 해도 일관적인 결과가 나오지 않아서 한참을 그간의 테스트 결과를 분석해 보다 보니, 특정 장소, 특정 시간대에서만 죽지 않는다는 결론이 나온 적이 있다. 그 장소와 그 시간의 공통점을 찾다가, 전등이 꺼져 있으면 안 죽는다는 사실을 알게 되었고, 결과적으로는 건물의 새로 바뀐 전등의 간섭 효과가 문제라고 찾아냈었다. 그 때 테스트를 하던 QA 가 테스트를 한 장소, 시간 등을 꼼꼼히 기록하지 않았다면, 그 결론에 다다르기가 힘들었을 것이다.
편견을 가지면 안 된다.
신입 사원들이 문제가 발생해서, 진도가 안 나가고 멈춰 있을 때, 뭘 하고 있는지 물어보면, 굉장히 높은 확률로, “내가 뭘 잘못한 것 같아서 보고 있다” 고 한다. 문제가 발생했는데, 그게 "나 때문" 이라는 것은, 아무런 과학적인 근거가 없다. 그냥 내가 신입이니까, 누군가 잘못해서 생긴 문제라면, “잘못한 누군가” 가 내가 아니겠냐는 추정에서 시작을 하는 것이다.
한편으로, 좀 안다는 선임들에게서 자주 발견되는 상황인데, “이게 문제일 거야” 라며 찍기를 하는 경우들이 있다. 가령 1-100 중에 숫자 하나를 스무고개를 통해서 맞춘다고 생각하자. 첫 번째 질문은 당연히 “50보다 작은 숫자인가요?” 가 되어야 한다. “이게 문제일 거야” 라는 것은 첫 번째 질문을, “25인가요?” 라고 하는 것과 다르지 않다. 물론 첫 번째 질문 만에 답을 찾을 확률도 1/100 이 존재하지만, 자칫하면 엄청난 시간을 낭비할 수가 있다.
과학 수사대가 수사를 할 때,“남편이 범인일 것이다” 라는 추정을 가지고, 남편이 범인이라는 걸 증명하기 위한 노력만 한다고 생각해 보자. 남편이 범인이면 좋은데, 그렇지 않으면 완전히 망하는 거다. 최대한 객관적으로 사실을 분석하고, 사실을 기반해서 소거할 것은 소거해 나가면서 진실에 다가가는 것. 이런 자세가 문제 해결에서 가장 기본적으로 갖추어야 할 마음가짐이다.
문제를 해결하는 데 걸리는 시간은 문제가 재현되는 시간에 비례한다.
테스트 과정을 거치면 많은 문제들이 쏟아진다. 문제가 일으키는 심각도에 따라서 나름의 우선순위가 함께 보고될 것이다. 결국은 보고된 문제들을 다 해결해야 하는 Integrator 입장에서 무슨 문제를 먼저 해결할 것인지 판단할 때 가장 중요하게 고려해야 할 요소는 “문제가 얼마나 잘 재현이 되느냐?” 이다. 왜냐면, 문제가 해결되는데 걸리는 시간은 일반적으로, 문제가 재현되는 시간에 비례하기 때문이다.
다르게 얘기하면, 문제를 빨리 재현할 수 있도록 만드는 노력이 매우 중요하고 의미 있는 노력이라는 것이다. 가령 화면 전환이 일어날 때 문제가 생기는 것 같다면, 프로그램으로 화면 전환을 매우 빠르게 하도록 강제로 만들 수 있을 것이다. 이러한 노력을 할 때도 역시 문제 정의는 되어 있어야 한다. 시뮬레이션을 통해 문제를 재현하고 해결하고 나서, 이 문제가 정말 해결이 된 것이 맞는지 최종 확인하려면, 수치화된 문제 재현 방법에 의거하여 다시 돌려봐야 하기 때문이다.
빨리 재현할 방법을 못 찾으면, 결국은 진실에 한걸음씩 다가가기 위한 노력을 할 수밖에 없다. 로그를 잡아 보고, 하나씩 다르게 해 보고 등등. 즉, 시간과의 싸움이다. 나의 생각이 멈췄다고 해서, 테스트가 멈추게 하지 말고 조금씩 더 사실관계를 파악해 나가야 한다.
("진실에 한 걸음 다가간다" 라는 표현은 "작전을 짜보자" 라는 표현과 함께 내가 개인적으로 가장 많이 하던 표현이었다... 문장으로 쓰고 나니 추억이 돋는다... ^^)