레거시 시스템 개선을 위한 기술의사결정

David Ha (Hyeonsu)
9 min readFeb 18, 2024

--

초기 프로젝트를 개발할 때는 빠른 출시가 중요하기 때문에 우리는 항상 주어진 상황속에서 최선의 선택을 하게되고 그 선택은 관성을 만들어내고 다음에 참여하는 엔지니어들은 관성에 따라서 기능을 개발하게 됩니다.

하지만 불행하게도 우리가 마주하게 되는건 최선의 선택과 선택이 쌓여서 만들어진 거대한 레거시 시스템을 마주하게되고 어느순간 구조설계상 한계를 마주하게 되며 좌절하게 됩니다.

이 때 생각나는 드라마의 한 명대사가 생각납니다.

이태원클라쓰

어찌 되었든 우리는 이 제품을 미래까지 안정적이며 확장가능하게 지속하기 위해 이 레거시 시스템을 개선할 수 밖에 없고 이건 우리 엔지니어들의 소명입니다.

이러한 문제를 해결하기 위해서 필요한 것들은 무엇이 있고 어떤 과정을 거치면 정신건강을 챙기며 중간에 좌절없이 격파해 나갈 수 있는지 최근 레거시 시스템 해결한 프로젝트를 예시로 공유해보고자 합니다.

그 땐 최선이였어

앞서 말했듯이 제품 초기 개발시에는 빠른출시와 최선의 선택의 연속이였습니다. 당시 기술부채로는 서버-클라이언트 end-point 설계상 몇가지 결함이 있었는데 다음과 같습니다.

결함1

서버상 error를 클라이언트에 전달할 시 명시적인 HTTP response status codes(403, 404등)와 클라이언트가 취해야하는 행동에 대한 스펙이 바른상태는 아니였습니다. 서버는 error에 대한 응답값을 제공하기는 하지만 HTTP response status codes를 200으로 내려주고 있었습니다.

그래서 당시 사용자 Permission 로직을 개선하기 위해 Error 구조를 먼저 개선하진 않았고 빠른출시를 위해 permission관련된 end-point를 하나 개설한 다음 행위에 대한 값을 서버에 전달하면 서버는 성공 응답값에 granted (boolean) flag와 클라이언트가 해야할 행위에 대한 value object 객체를 제공했습니다.

결함2

어떤 Entity의 특정 상태값을 변경하는 경우라면 PATCH method가 떠오르실껍니다. 하지만 과거 관성으로 인해 전역적으로 특정 Entity의 여러 상태값을 갱신하기 위해 PUT method를 통해서 이뤄지는 경우도 있었습니다.

따라서 구체적으로 사용자가 어떤 상태변경을 요구해서 해당 API를 호출했는지 서버입장에선 명확하지 않았기 때문에 Permission 로직을 붙이기엔 한계가 있어서 앞서 설명했던 permission end-point에 행위값을 전달하는 방식으로 풀었습니다.

이 시스템은 만들어지고 3년동안 큰 문제의식을 많이 느끼진 못했습니다. 그리고 새로운 비즈니스를 그 위에 덧붙일 때마다 iOS/Android 배포필요 없이 구현만 하면되니까 당시엔 정말 은총알 같이 받아들였습니다.

단지 중간중간 value object에 새로운 값을 추가해나가고 클라이언트 코드베이스에 구석구석 전역적으로 퍼져나가면서 점점 발생하는 문제는 아래와 같았습니다.

  • value object에서 다루는 비즈니스가 많아지면서 단일책임위반을 하게 되며 사이드 이펙트에 대한 두려움이 커지기 시작했습니다.
  • iOS/Android 배포의존이 필요없다는 건 거짓말입니다. 결국 새로운 화면이나 클라이언트상 새로운 기능에 대해서 Permission이 필요할 때 서버에 전달하는 행위식별자는 그 만큼 늘어나게 되고 서버 코드도 기하급수적으로 Massive 해지기 시작했습니다.
  • 여전히 에러로 해결할 수 있는 문제를 Permission으로 해결하다보니 Permission API를 호출한 후에 Permission 성공시 서버 API호출을 하는 현상이 잦아지게 되면서 사용자가 인내해야하는 시간이 두배로 커졌습니다.

결국 터지다

시간이 지나면서 Permission을 다루게 되는 엔지니어 수도 많아지고 사람들이다 보니 휴먼 에러를 일으켜서 특정 식별자 적용을 누락하기도 하고 엉뚱한 이름으로 설계해서 서버가 불필요하게 두개의 식별자를 수용하는 등과 같은 상황들이 연출되고 이러한 것들에 대해서 교통정리하는 Product Manager의 문서는 시스템이 얼마나 복잡한지 적나라하게 보여주었습니다.

Product Manager가 교통정리하는데 있어 도움을 주기위해 엔지니어들도 코드를 뒤져가면서 파악하느라 많은 시간을 들였고 이건 모두에게 고통스러운 순간이였을껍니다.

그래서 킥오프미팅이 진행되고 문제의식을 공유받은 후 담당엔지니어가 소집되고 필자는 해당 프로젝트를 이끄는 기술리더 역할을 위임받게됩니다.

현황파악 및 리스트업 그리고 중장기적인 시야를 곁들인

Product Manager도 나름 고생많으셨지만 문서화가 덜되고있고 오래된 레거시 시스템을 정리하는건 정말 힘든 일입니다. 하지만 우리 엔지니어는 다 알다싶이 코드는 거짓말하지 않습니다.

그래서 가장 먼저 접근한건 Server, iOS, Android 프로젝트상 관련 코드베이스를 전역적으로 둘러보고 리스트업을 하는겁니다. 그리고 어떤 문제가 있고 어떤 결함이 있는지 리스트업을 한 후에 중장기적인 시야를 바탕으로 각 항목별로 설계 방향 제안서를 작성합니다.

너무 쉽게 말한거 같지만 이는 분명 쉬운일은 아닙니다.

특히 한 플랫폼에 종속된 엔지니어라면 다른 플랫폼에 대한 구조나 언어적인 차이가 있기 때문에 다른 플랫폼의 코드 베이스를 파악하는 건 쉬운 일은 아닙니다. 하지만 제품을 담당하는 특정조직에 몸을 오래 담그고 있는 엔지니어일수록 이러한 노력과 의도적인 수련은 필요하다고 생각합니다. 또한 엔지니어 매니저나 또는 조직 리더는 조직 내에서 오랫동안 기여한 시니어 엔지니어가 이런 역할을 할 수 있도록 적극적으로 지원하고 도와줄 수도 있어야겠죠.

레거시 시스템에서 21개에 대해서 수정이 필요한걸 확인할 수 있었고 이를 가시화했다.

의견의 총알이 빗발치는 참호 속에서

이렇게 리스트업 하고 빚어낸 Tech Spec 초안을 가지고 작업을 담당하게 될 엔지니어들은 다같이 모여서 미팅을 가지게 됩니다.

미팅 참석전에 담당 엔지니어들은 미리 현황파악된 문서를 숙지한 상태기 때문에 미팅시간엔 배경을 설명해서 귀한 시간을 레거시 시스템 소개시간에 다 소비할 필요없이 엔지니어들은 바로 기술의사결정 과정에 몰입하게 됩니다.

위와 같은 효율적인 미팅진행을 위해선 미리 기술문서의 배경과 방향성을 숙지하는것이 조직 내에 엔지니어들간에 약속이 전제되어야합니다.

그럼 리스트업한 항목을 기준으로 하나씩 엔지니어들은 의견을 냅니다. “Server에선 이런식으로 가져가는거 보단 이런식으로 하는게 더 효율적일꺼같아요. Android에선 이런식으로 설계하는덴 무리가 있는데 이런식으로 가져가면 안될까요?…”

이 때 킥오프미팅을 진행을 주도하는 엔지니어는 딱 4가지만 잘하면 됩니다. 경청, 조율, 결정, 기록

가끔 과몰입하다보면 엔지니어들은 해결해야하는 문제의 scope를 벗어난 상상력을 발휘해 입밖으로 꺼내는 엔지니어도 있고 상대 플랫폼에 대한 이해도가 낮은 엔지니어들 간에 의견 충돌도 발생하는건 매우 자연스러운 일입니다.

이때 지속적으로 경청은 하더라도 scope에서 벗어나지 않도록 다음에 논의할 기회를 제공해주겠다 약속을 하고 끊어낼 수 있어야하고, 충돌에 대해서는 서로 알지 못하는 부분에 대해서 간단이 이해시켜주되 미팅이 끝나고 나면 서로 배우고 이해할 수 있는 시간을 가질 수 있도록 독려 해봅니다.

의견이 총알처럼 빗발치는 상황속에서도 의견을 지속적으로 식별하면서 결정을 하는 것도 참 쉬운일은 아닙니다. 이 혼란스러운 상황에서 천재가 아닌이상 좋은 결정을 내리기는 쉽지않습니다. 이럴 때 가장 큰 힘을 발휘하는게 “기록"입니다.

이걸 전문적으로 기록하면 ADR(architecture decision record)라고 부르기도 합니다. 우리가 어떤 의견을 서로 제시하고 거기에 따른 이득이 무엇이며 어떤 반대의견이 있었는지 적나라하게 적고 결정되지 않았을 땐 잠시 머리를 식히고 제시했던 의견을 다시 되새김질하고 합의점을 찾아 최적의 결정을 하게 됩니다.

회의 과정에서 발휘해낸 새로운 의견이나 생각들을 그 순간순간 인지하는건 정말 쉬운일이 아닙니다. 우리는 기록을 통해서 기술결정과정 속에서 어떤 마인드 셋으로 임했는지 너무 섣부른 의견을 제시한건 아닌지 스스로 인지하고 고찰할 수 있는 있는 좋은 성장기회를 제공하기도 합니다.

이렇게 논의와 결정의 반복을 통해서 우리 엔지니어들은 레거시 시스템을 어떻게 도축할지 설계된 작전전략대로 IDE를 열고 프로그래밍을 수행하게 됩니다.

마무리

새로운 기능을 개발하는것보다는 레거시 시스템을 개선하는것이 더욱 어렵습니다.

새로운 기능 개발을 비유하자면 평탄한 사막위에서 오아시스까지 어디를 달려가든 목적지에만 도착하면 되고 그 과정에 특별히 장애물은 많이 없습니다. 물론 가끔 가시많은 선인장이 있을 수는 있겠죠.

반면 레거시 시스템을 개선하는 건 아마존 열대우림을 통해 바다까지 가는 여정과 비슷할 껍니다. 하지만 위 사진에서 보았듯이 강물줄기만 잘 따라가도 바다까지 이르는건 보기보다 쉬운일로 보일껍니다.

따라서 이 글의 내용을 짧게 정리 요약하자면 “레거시 시스템에 대해서 분석하고 정리한다음 함께 이해를 바탕으로 의사결정하고 노를 저어서 전략적으로 치밀하게 계획된 방향대로 가기”만 하면 됩니다.

읽어주셔서 감사하고 함께 레거시 시스템을 격파해나가주신 msrband, heka1024, LeeOhHyung 동료들에게 이 글을 통해 감사를 표합니다.

--

--

No responses yet