뒤로가기
아무도 안 쓰는 기능을 3주 동안 만들었다

December 28, 2024

frontendessay

3주 동안 야근까지 하면서 만든 기능이 있다. 고급 검색 필터. 사용자가 10개 이상의 조건을 조합해서 데이터를 필터링하고, 필터 조합을 저장하고, 저장된 필터를 불러와서 다시 쓸 수 있는 시스템이었다. 런칭하고 한 달 뒤에 분석 데이터를 봤다.

사용률 0.3%.

전체 사용자 중 0.3%만 이 기능을 한 번이라도 클릭했다. 필터를 저장한 사용자는 그보다 적었다. 저장된 필터를 다시 불러와서 사용한 사람은 거의 없었다.

이건 3주 동안 매일 야근하면서 만든 기능이었다. 주말에도 한 번 나왔다. 기술적으로 꽤 복잡한 작업이었고, 나는 그 과정에서 많이 성장했다고 생각했다. 근데 아무도 안 쓴다.

시작은 그럴듯했다#

그 기능이 나오게 된 배경은 이랬다. 우리 서비스는 B2B SaaS였고, 사용자가 관리하는 데이터가 많았다. 기존에는 기본적인 검색과 몇 가지 필터만 있었다. 어느 날 기획 미팅에서 누군가 이런 얘기를 했다.

"파워 유저들이 더 세밀한 필터를 원한다는 피드백이 있어요."

팀의 프로덕트 매니저가 이 피드백을 가져왔다. CS팀에서 올라온 요청이라고 했다. 고객사 중 몇 곳에서 "필터가 부족하다"는 말을 했다고.

여기까지만 들으면 합리적인 요구사항이다. 실제로 팀 전체가 그렇게 판단했다. 나도 포함해서. 기획서가 만들어지고, 디자인이 나오고, 내가 구현을 맡았다.

기술적으로는 재미있었다#

솔직하게 말하면, 이 기능을 맡았을 때 기뻤다. 일단 기술적으로 흥미로웠다.

필터 조건을 동적으로 추가/삭제할 수 있어야 했다. 조건 간에 AND/OR 로직을 선택할 수 있어야 했다. 날짜 범위, 숫자 범위, 텍스트 포함/미포함, 선택형 등 다양한 필터 타입을 지원해야 했다. 필터 조합을 JSON으로 직렬화해서 저장하고 복원하는 것까지.

나는 재귀적인 필터 트리 구조를 설계했다. 각 노드가 조건 또는 그룹이 될 수 있고, 그룹은 다시 조건과 그룹을 포함할 수 있는 구조. 이론적으로는 무한 중첩이 가능했다. 현실적으로 3단계까지만 허용했지만.

컴포넌트도 재귀적으로 렌더링했다. FilterGroupFilterConditionFilterGroup을 자식으로 가질 수 있는 구조. 상태 관리는 immer를 써서 불변성을 유지하면서 깊은 중첩 객체를 수정할 수 있게 했다. URL 쿼리 스트링과의 동기화도 구현했다. base64로 인코딩해서.

자랑하려고 쓴 게 아니다. 이 기술적 디테일을 나열하는 이유가 있다. 나는 이 모든 걸 만들면서 성취감을 느꼈다. "와, 이거 되게 잘 만든 것 같은데?" 코드가 예뻤다. 구조가 깔끔했다. 엣지 케이스도 많이 커버했다. 코드 리뷰에서 동료가 "오, 이 구조 좋네요"라고 했을 때 뿌듯했다.

근데 그게 함정이었다.

내가 놓친 질문들#

3주 동안 한 번도 이런 질문을 하지 않았다.

"필터가 부족하다고 한 고객이 정확히 몇 명이지?"

나중에 알아보니 3곳이었다. 전체 고객사가 200곳이 넘었는데, 3곳에서 비슷한 말을 했다. 1.5%의 고객이다.

"그 고객들이 원하는 게 정확히 뭐였지?"

돌이켜보면 이걸 제대로 파고들지 않았다. "필터가 부족하다"는 피드백에서 고객이 원한 건 어쩌면 단순히 한두 개의 필터 조건 추가였을 수 있다. 날짜 필터가 없어서 불편했다거나, 상태값 필터에 옵션이 부족했다거나. 그런 건 하루면 추가할 수 있었다.

하지만 우리는 "고급 필터 시스템"을 만들었다. 고객이 "문 하나 더 내주세요"라고 했는데 건물 전체를 리모델링한 격이다.

"이 기능을 실제로 쓸 사용자가 얼마나 되지?"

이 질문이 가장 뼈아프다. 기존 데이터를 보면 알 수 있는 거였다. 기존 필터를 3개 이상 동시에 사용하는 사용자가 얼마나 되는지 확인했으면 됐다. 아마 5%도 안 됐을 거다. 그 5%에게도 10개 이상의 조건을 AND/OR로 조합하는 고급 필터가 필요한 건 아니었을 거다.

아무도 이 질문을 하지 않았다. 나도, 기획자도, 디자이너도.

기술적으로 재미있는 것의 위험#

여기서 내가 배운 건 이거다. 기술적으로 재미있는 작업은 위험하다. 재미있으면 의심을 멈추기 때문이다.

만약 그 기능이 기술적으로 지루한 작업이었으면 — 예를 들어 필터 드롭다운 3개 추가하는 거였으면 — 나는 아마 기획에 더 의문을 제기했을 거다. "이거 꼭 해야 해요? 우선순위가 맞아요?" 하고 물었을 거다. 누구나 지루한 일을 피하고 싶으니까.

근데 재귀적 필터 트리? AND/OR 로직 빌더? 이런 건 만들고 싶었다. 만드는 게 재미있었다. 그래서 "이 기능이 정말 필요한가?"라는 질문을 건너뛰었다. 무의식적으로. 만들고 싶었으니까. 만들 이유를 찾으면 됐으니까.

이건 개발자한테 특히 위험한 함정이다. 우리는 만드는 게 직업이고, 만드는 걸 좋아하는 사람들이다. 복잡한 문제를 우아하게 해결하는 데서 쾌감을 느낀다. 그 쾌감이 판단을 흐리게 할 수 있다는 걸, 0.3%라는 숫자가 알려줬다.

3주간의 일기#

지금도 생생하게 기억나는 게 있다. 첫 주에 필터 트리 구조를 설계하면서 화이트보드에 그린 다이어그램. 재귀적으로 중첩 가능한 필터 그룹과 조건 노드를 그리면서 나는 진심으로 신이 났었다. "이 구조 되게 멋지지 않아?" 옆 자리 동료한테 보여줬다. 그 동료는 "오 뭔가 복잡하네"라고 했다. 지금 생각하면 그게 경고였는데, 그때는 칭찬으로 들었다.

둘째 주에는 드래그 앤 드롭으로 필터 조건의 순서를 바꾸는 기능을 넣을까 고민했다. 기획서에는 없었는데, "이왕 만드는 거 이것도 있으면 좋지 않나" 싶었다. 다행히 이건 스스로 브레이크를 걸었다. 스코프를 늘리면 일정이 밀리니까. 하지만 그 유혹이 들었다는 것 자체가 이미 문제의 신호였다. 사용자가 원하는 게 아니라 내가 만들고 싶은 것에 집중하고 있었다는 증거다.

셋째 주, 마무리 단계에서 QA를 하면서 온갖 엣지 케이스를 잡았다. 필터를 20개 이상 추가하면 스크롤이 이상하게 되는 문제, AND와 OR를 번갈아 바꾸면 결과가 꼬이는 문제, 저장된 필터를 불러왔는데 이미 삭제된 카테고리가 포함되어 있으면 에러가 나는 문제. 이런 것들을 하나하나 고치면서 "역시 복잡한 기능은 엣지 케이스가 많구나"라고 생각했다. 지금 생각하면 이렇게 엣지 케이스가 많다는 것 자체가 과도한 복잡도의 신호였다.

사라지지 않은 코드#

그 기능은 아직 프로덕션에 있다. 삭제되지 않았다. 사용률이 0.3%인 기능을 삭제하는 건 또 다른 의사결정이고, 거기에 들어가는 리소스도 있으니까. 삭제하면서 생길 수 있는 사이드 이펙트를 테스트하고, 혹시 쓰는 소수 사용자에게 공지를 하고, 이런 작업이 필요하다.

그래서 아무도 안 쓰는 코드가 계속 유지 비용을 발생시키고 있다. 의존성 업데이트할 때 이 코드도 같이 수정해야 한다. 디자인 시스템이 바뀌면 이 컴포넌트도 업데이트해야 한다. 테스트 코드도 유지해야 한다. 새로 온 팀원이 "이 컴포넌트 뭐예요?"라고 물으면 설명해줘야 한다. "아, 그건 고급 필터인데... 거의 안 쓰여요." 이 말을 할 때마다 묘한 기분이 든다. 박물관에 전시된 자기 작품을 보는 느낌이랄까. 아무도 안 보는 전시.

팀에서 이 얘기를 꺼냈을 때#

분석 데이터를 본 후에 팀 회고에서 이 얘기를 꺼냈다. 조심스럽게. 내가 3주 동안 만든 기능의 사용률이 0.3%라는 건, 솔직히 내 입으로 말하기 민망한 숫자였으니까.

의외로 팀의 반응은 나를 탓하는 분위기가 아니었다. 기획을 맡은 프로덕트 매니저도 본인의 판단 실수를 인정했다. "고객 피드백을 더 깊이 파봤어야 했다"고. 디자이너도 "사용성 테스트를 한 번이라도 했으면 중간에 방향을 바꿀 수 있었을 것 같다"고 했다.

이건 특정 개인의 잘못이 아니라 프로세스의 문제였다. 기능 요청 → 기획 → 디자인 → 개발 → 런칭. 이 파이프라인 어디에도 "이 기능이 정말 필요한지 검증하는 단계"가 없었다. 피드백이 왔으니 만들었다. 그게 전부였다.

그 이후로 우리 팀에서는 일정 규모 이상의 기능에 대해 간단한 검증 과정을 넣었다. 거창한 건 아니다. 기존 데이터에서 니즈의 규모를 확인하거나, 프로토타입을 먼저 만들어서 소수 사용자에게 보여주는 정도. 이것만으로도 "만들고 나서 아무도 안 쓰는" 상황을 상당 부분 줄일 수 있었다.

이후로 달라진 것#

이 경험 이후로 새 기능 기획 미팅에서 항상 묻는다.

"이 기능을 쓸 사용자가 몇 명이나 될까요?"

정확한 숫자가 아니어도 좋다. 대략적인 규모감이라도 있으면 다르다. 전체 사용자의 50%가 쓸 기능이랑 3%가 쓸 기능은 투자할 리소스가 달라야 한다.

"기존 데이터에서 이 니즈를 확인할 수 있나요?"

추측이 아니라 데이터를 먼저 보자는 거다. "사용자가 원한다"는 말은 너무 모호하다. 어떤 사용자? 몇 명? 얼마나 자주? 이걸 확인하는 데 하루면 충분하다. 기능 개발에 3주 쓰기 전에 검증에 하루를 쓰는 게 훨씬 효율적이다.

"가장 작은 버전은 뭘까요?"

고급 필터 시스템 대신 필터 3개를 추가하는 것. 그걸로 충분한지 먼저 검증하고, 부족하면 그때 확장하는 것. 한 번에 완벽한 걸 만들려는 욕심이 불필요한 복잡도를 만든다.

기술적 성취와 제품적 성취는 다르다#

이게 결론이다.

그 3주 동안 나는 기술적으로 성장했다. 재귀적 컴포넌트 구조, 복잡한 상태 관리, JSON 직렬화/역직렬화. 이런 것들을 경험한 건 분명 도움이 됐고, 이후에 다른 곳에서 써먹기도 했다.

하지만 제품적으로는 실패했다. 3주의 개발 리소스와 기획/디자인 리소스를 들여서 거의 아무도 쓰지 않는 기능을 만들었다. 그 시간에 사용자 80%가 매일 쓰는 기존 기능을 개선했으면 임팩트가 훨씬 컸을 거다.

개발자로서 기술적으로 뛰어난 걸 만들고 싶은 욕구가 있다. 자연스러운 거다. 그 욕구 자체가 나쁜 건 아니다. 다만 그 욕구가 "이걸 만들어야 하는가?"라는 질문을 가려서는 안 된다.

0.3%라는 숫자는 불편했다. 하지만 그 불편함이 가르쳐준 게 있다. 좋은 개발자는 뛰어난 코드를 짜는 사람이 아니라, 짜야 할 코드를 구분하는 사람이다.

그 이후로 화려한 기능 요구사항을 보면 설레기 전에 먼저 의심한다. 이전의 나였으면 키보드부터 잡았을 거다. 지금은 질문부터 한다.

나는 이걸 0.3%의 교훈이라고 부른다. 싸게 배운 건 아니었지만, 비싸게 배운 만큼 잘 기억하고 있다.