
리팩토링 주간?
원래는 부스트캠프가 12월에 수료를 마치고, 공식적인 일정이 더 이상 없다.
네이버 부스트캠프 9기 웹 풀스택 과정 후기
네이버 부스트캠프 9기가 드디어 끝났다. 2024년 올해 가장 큰 이벤트였던 대외활동이자 부트캠프가 성황리에 마무리되었다. 올해 6월부터 계속 이 과정 하나에만 매달릴 정도로 정신 없었고 할
laurent.tistory.com
하지만 올해는 리팩토링 주간이라고 해서, 프로젝트를 했던거를 더 이어서 나갈 수 있도록 리팩토링을 하는 기간을 만들어주셨다. 정확한 기간은 CS 리팩토링 3주 (25.01.06 ~ 25.01.24), 인공지능 리팩토링 3주 (25.02.03 ~ 25.02.21) 이다.
CS 리팩토링 기간
CS 리팩토링 기간에는 CS 지식을 활용해 기존 서비스를 리팩토링하는 시간이었다. 시간에 쫓겨 성능을 생각하지 못해 구현한 코드들을 다듬어나가는 시간이었다.
테스트 도입
어떤 CS 지식을 활용해서 리팩토링을 할지 고민해보다가, CS 지식 중 소프트웨어공학과 관련된 테스트를 한 번 해볼까 라는 생각을 가지고 있었다. 조금 더 고민해보니, 컴포넌트 변경을 했을 때 원하는 동작이 일어나는지 확인하는 과정이 반복적이고 시간 소모적이라는 점을 깨달았다. 코드를 수정할 때마다 의도치 않은 부작용이 생기지 않았는지 확인하는 작업이 개발 속도를 늦출 수 있다 생각했다. 물론 테스트 코드 자체도 컴포넌트가 변경될 때마다 테스트도 함께 수정해야 해서 유지보수가 필요하다는 딜레마가 있다.
그럼에도 테스트를 도입한 이유는 React Testing Library가 컴포넌트의 내부 구현보다 사용자가 어떻게 컴포넌트를 보는지를 테스트하는 데 집중할 수 있기 떄문이다.
The more your tests resemble the way your software is used, the more confidence they can give you.
Kent C. Dodds, React Testing Library 창시자
예를 들어 render
메서드로 컴포넌트를 렌더링한 후 getByRole
이나 getByText
같은 쿼리로 DOM 요소를 선택하는 방식은 querySelector
로 특정 클래스나 ID를 직접 찾는 것보다 구현 변경에 덜 취약하다. 이렇게 접근성 속성을 기반으로 요소를 찾는 방식은 내부 스타일이나 클래스가 바뀌어도 사용자 관점의 기능이 유지된다면 테스트는 여전히 유효하다.
이러면 코드 내부를 리팩토링하더라도 사용자 관점의 기능이 그대로일 때 테스트가 깨지지 않는 장점이 있다. 자주 재사용되는 컴포넌트라면 초기 테스트 작성 비용을 감수하더라도 장기적으로 반복적인 수동 테스트 시간을 절약할 수 있다고 봤다. 이런 측면을 고려했을 때 선별적으로 테스트 대상을 정하고, 3주 동안 테스트 시나리오 작성과 코드 구현에 집중했다.
테스트 코드의 필요성은 리팩토링 기간 이전부터 느끼고 있었다. 그룹 프로젝트 단계에서 이미 일관된 동작을 보장해야 하는 컴포넌트들이 여러 개 존재했기 때문이다. 특히 우리 서비스의 특성상 컴포넌트 동작을 확인하려면 블로그 글을 작성하고 포스트를 확인하는 번거로운 과정을 반복해야 했다. 이런 수동 테스트의 비효율성이 테스트 코드 도입의 결정적 계기가 되었다. 단순히 테스트 스크립트를 실행하는 것만으로 컴포넌트가 올바르게 동작하는지 빠르게 확인할 수 있게 되었고, CS 리팩토링 기간 동안에는 이 테스트 프로세스를 고도화하는 데 집중했다.
테스트를 본격적으로 도입해보고자 테스트 시나리오를 작성했었다. 각 컴포넌트별로 테스트해야 할 기능과 상황, 그리고 기대 결과를 세부적으로 정의했다. FormInput 컴포넌트의 경우 label과 input의 연결 상태, value prop 반영, onChange 이벤트 처리 등을 검증하는 시나리오를 작성했다. RssRegistrationModal 같은 컴포넌트는 폼 상태 관리부터 API 요청, 성공/실패 시나리오까지의 상황을 고려했다. 아이콘, 버튼, 모달 등의 UI 요소들을 제대로 구현했는지 검증하는 테스트까지 포함시켰다.
테스트 시나리오를 작성하고, 테스트 코드를 작성해나갔다. React Testing Library의 API를 활용해 각 컴포넌트의 렌더링, 상태 변화가 어떻게 이루어지는지 검증하는 테스트 스위트를 작성했다. 하지만 3주 내내 테스트 코드를 작성하면서 시간을 오래 쓰게 되었다. 가장 큰 이유는 테스트 작성 과정에서 서비스의 코드 설계 자체를 돌아보게 되었기 때문이다.
아쉬웠던 점
테스트 코드를 구현하면서 알아낸 사실인데, 지금까지 구현한 코드들은 대부분 테스트하기가 어려웠다. 처음에는 그냥 ‘테스트 코드가 원래 짜기 어려운가보다..’ 하고 넘어갔지만, 점점 테스트 코드를 작성하면서 이상한 점을 느꼈다. 어떤 컴포넌트는 쉽게 테스트 코드를 작성할 수 있는 반면, 어떤 컴포넌트는 어떻게 접근해도 테스트 코드가 잘 작동하지 않는 어려움이 있었다.
테스트 코드를 작성하면서 복잡하게 얽혀있던 컴포넌트들을 책임에 따라 분리하고 재사용 가능하게 바꿔야 함을 알게 되었다. 많은 컴포넌트에 책임이 과도하게 집중되어 있거나 의존성이 복잡한 경우가 많았다. 3주라는 제한된 시간 내에 많은 개선을 이루기는 어려웠고, 그렇다고 짧은 기간에 설계를 완전히 다시 하는 것도 맞지 않았다. 프론트 팀원과 FSD 도입에 관해 이야기를 나누어봤지만 아무래도 지금까지 만들어놓은 컴포넌트들을 모두 마이그레이션해야 하는 대규모 작업이 될 것 같아 나중에 도입해보기로 결정했다.
돌이켜보면 '컴퓨터 과학'이라는 단어에 너무 매몰되어 리팩토링 범위를 나 혼자서 제한한 것 같아 아쉬웠다. 그냥 서비스 리팩토링이라고 생각했으면 조금 나았을까? 성능 최적화 측면에서 이번 기간에 특별히 향상시킨 것이 없다. 물론 서비스 특성상 프론트엔드에서 성능이 요구될만한 작업이 없긴 하다. 그래도 기회가 된다면 데이터 캐싱 부분을 조금 깊게 파보면서 다량의 포스팅을 효율적으로 관리하고 불필요한 네트워크 요청을 줄이는 최적화 작업을 해보고 싶다. 결론적으로 CS 리팩토링은 전체 리팩토링 중 일부일 뿐이라는 것을 나중에야 깨달았다.
테스트 같은 경우에는 사실 컴포넌트가 정말 많이 사용되고 이런 코드에 대한 테스트를 선별적으로 한 것이 맞긴 하지만, 테스트 코드를 작성하다 보니 어느 순간부터 커버리지를 채우기 위한 테스트 코드 작성을 수행하고 있었다. 또한 기능 구현이 더 이루어질 여지가 있는 컴포넌트들의 경우에는 테스트가 어긋나버려 테스트 코드를 고치지 않으면 배포가 돌지 않게 되는 불상사도 여러 번 있었다. 이로 인해서 테스트 코드 유지 보수에 시간을 더 투자하는 상황도 여러 번 겪게 되었다.
인공지능 리팩토링 기간
우리 팀은 인공지능 리팩토링 기간 동안 블로그 게시글 태그 분류 기능 구현에 집중했다. 이 과정에서 프롬프트 엔지니어링, 데이터 전처리, 모델 선정과 튜닝 등 그 동안 경험해보지 못한 인사이트를 얻을 수 있었다.
인공지능을 사용하면서도 사용자들에게 도움이 될 기능이 어떤 것이 있을지 고민해보았다. 그 결과 아래 기능들이 떠올랐다.
- 블로그 게시글 태그 분류
- 다국어 지원
- 비속어 차단 기능
인공지능 리팩토링 주간에 제한적인 시간이나 꼭 인공지능을 사용하지 않아도 해결이 될 수 있을법한 문제들은 제외하기로 해 최종적으로 3주 동안 블로그 게시글 태그 분류를 구현하기로 했다.
사실 태그 분류는 유저들의 유입과 관련이 그렇게 크지 않을 수 있다. 그렇지만 팀 내에서 프로젝트 재방문율을 높이는 부분들을 그룹 프로젝트 기간부터 계속 고민했기 때문에 인과관계 없이 단순히 급조한 기능은 아니다. 결론부터 이야기하면, 우리 프로젝트에는 개인화 기능(회원가입, 로그인) 구현이 선행되어야 본격적인 재방문을 유도할 수 있는 기능을 만들 수 있다고 판단했다.
현재 운영 중인 RSS 등록을 예로 들어보자. RSS를 등록하는 사람들의 메일을 받고 있기 때문에 이 주소를 통해 재방문율을 높일 수 있는 뉴스 레터를 돌릴 수 있다. 뉴스 레터에 들어갈 내용은 ‘이번 주 인기있는 포스트’, ‘오늘 올라은 포스트’ 등이 있을 것이다. 하지만 뉴스 레터를 보기 위해 메일을 우리에게 준 것이 아니므로 등록자 입장에서 원하지 않은 메일을 받는다 생각할 수 있다. 또한 RSS 폼을 통해 수집한 정보의 목적이 개인 정보를 수집하기 위한 목적이 아니었다. 따라서 현재 구현된 기능을 바탕으로 인공지능을 탑재한 기능을 구체화할 수 없었다.
인공지능 모델이 필요한 기능 또한 기획 단계에 머물러있다. 우리가 벤치마킹으로 두고 있는 daily.dev에서 쉽게 찾아볼 수 있는 기능인데, 바로 블로그 게시글에 대한 요약을 미리 알려주는 것이다. 우리 서비스에서는 포스팅을 클릭하면 바로 그 블로그로 넘어가지만, daily.dev와 같은 서비스에서는 글에 대한 요약본을 살펴볼 수 있는 중간 단계가 하나 있다. 이런 요약본을 만드는 데 모델이 필요하다.
사진을 보면 알 수 있다시피 이러한 요약본에도 태그가 들어가게 된다. 즉 모델이 적용된 가장 먼저 빨리 필요한 기능으로 태그를 선택했다. 태그만으로는 당연히 재방문율을 높일 수 없다. 하지만 이런 기능들 이외에도 기획한 내용들이 더 있기 때문에 태그가 시작점이 되어 다양한 기능을 만들 수 있는 기반을 쌓는다고 보면 될 것 같다.
모델 비교
기능 구현을 위해 초기에는 CLOVA Studio의 HCX-003 모델을 선택했다. Playground에서 프롬프트를 작성해보면서 태그를 생성해보았지만 일관된 결과를 얻기 힘들었다. 팀원 모두가 다양한 프롬프트들로 시도를 해보았지만 성공하기 쉽지 않았다. 태그 정확도도 그렇게 좋은 편이 아니었다. 게시글과 연관 없는 태그를 생성하거나, 사전에 제공한 태그 목록을 무시하고 임의의 태그를 생성하는 문제가 반복되었다.
튜닝을 통해 모델 성능을 개선하려 했지만 NCLOUD에서 권장하는 태그당 ‘최소 200개의 데이터가 필요하고 최대 태그 개수가 15개로 제한되어 있다’는 부분에서 현실적으로 불가능함을 느꼈다. 아직 서비스의 사용자가 많지 않아 최소 200개의 데이터를 태그 별로 모으는 것도 힘들고, 태그 개수도 15개로는 부족했다. 그래서 1주차에 최대한 프롬프트 최적화를 해보되 한계를 느끼면 다른 모델로 전환하기로 결정했다.
대안 모델 검토
여러가지 대안을 검토했다.
- `Ollama` 로컬 환경에서 동작해 API 호출 비용을 절감할 수 있다는 장점이 있었다. 하지만 클라우드 환경에서 GPU 없이 CPU로 모델을 돌려야 하는 제약과 성능 저하(응답 시간 5~10초 이상), 인프라 비용 증가 등의 문제로 제외했다.
- `ChatGPT` 동일한 영문 프롬프트를 적용했을 때 Clova보다 나은 결과를 보여주었다. 하지만 가끔 지정된 태그 목록 외의 태그를 생성하는 문제가 있었고 비용 측면에서도 다른 대안이 더 효율적이었다.
- `Claude` 최종적으로 선택한 모델이다. Claude 3.5 Sonnet은 GPT-4o보다 비용이 저렴하면서도 성능이 뛰어났다. 특히 Haiku 모델은 문서 분류에 적합하고 사전에 제공한 태그 목록 내에서만 태그를 생성했다. 무엇보다 한국어 요약 능력이 우수했다.
비용과 성능 측면을 종합적으로 고려했을 때, Claude Haiku 모델이 가장 적합하다고 판단했다. GPT-3.5 Turbo보다는 약간 비싸지만 성능이 훨씬 좋았고, JSON 형식으로 출력하면 토큰 사용량을 최소화할 수 있어 비용 효율성도 확보할 수 있었다.
최종적인 결과물이다. 사용자들은 이제 태그를 통해 관심 주제를 보고, 요약문을 통해 전체 내용을 미리 파악한 후 클릭해서 볼지 말지를 결정할 수 있게 되었다. 사용자들이 더 효율적으로 원하는 정보를 찾을 수 있어 나름 의미 있는 개선이었다고 생각한다. 앞으로 회원 시스템과 연계해 개인화된 태그 기반 추천 시스템으로 확장해볼 수 있는 발판을 만든 것에 큰 의의를 두고 있다.
느낀 점
인공지능 리팩토링 기간을 진행하면서, 우리 서비스에 실제로 어떤 인공지능 기능이 필요한지와 사용자에게 어떤 가치를 제공할 수 있을지 판단하는 것이 생각보다 어려웠다. 나와 팀원들이 생각하기에 태그 분류와 요약 기능이 도움이 될 것이라 판단했지만 실제 유저 피드백 없이 이런 판단을 내리는 것은 항상 불확실하다.
또한 우리 서비스의 품질이 블로그 등록자 수에 따라 크게 좌우된다는 점도 아쉬움으로 남는다. 아무리 AI 태그 분류가 정확해도 등록된 블로그 자체가 적다면 그렇게 효과가 크지 않기 때문이다. 이런 부분에서 팀원들 간 사용자들을 많이 유치하기 위한 별도의 기능을 추가로 개발해야 하는지에 대한 의견 차이도 있었다. 결국 우리 서비스의 핵심 목적은 등록된 블로그 글을 효과적으로 탐색할 수 있게 하는 것이므로, 이 범위 안에서 최대한의 가치를 제공하는 방향으로 결정했다.
시작은 인공지능 리팩토링이었지만 기술적 구현 생각 외에도 깊은 고민을 하게 된 시간이었다. 우리 서비스에 AI 서비스들을 어떻게 접목시킬지, 그것이 사용자들에게 어떤 가치를 제공해줄 수 있는지, 그리고 더 근본적으로는 서비스 방향성을 어떻게 잡아나가야 할지에 대해 생각해보았다.
우리 팀은 이 프로젝트를 시작할 때 어느 정도 기간을 길게 두고 구현해보고자 했다. 지금까지 그러한 마음가짐으로 참여해왔고 (물론 취준이나 학업 병행으로 바쁘겠지만) 각자의 자리에서 최대한 프로젝트를 앞으로도 이어 나갈 예정이다. 그러기 위해서 이번 리팩토링 기간에 느낀 인사이트와 경험들을 통해 앞으로 서비스의 방향성을 견고하게 다지는 데 중요한 방향성이 될 것이라 생각한다. 팀원들과 함께 느낀 점들을 바탕으로 같이 이야기해보면서 서비스의 미래를 정해 나갈 계획이다.
진짜 끝!
이제 부스트캠프 9기로서 진행하는 일정은 마무리되었다. 회고를 다 적다 보니 개강이 하루 앞으로 다가와 있다. 부스트캠프에서 배웠던 CS 지식들과 사고방식을 마스터 분들께 배웠으니 이제 잘 활용해볼 예정이다. 부스트캠프를 하면서 스터디의 중요성도 깨달았고, 여기서 만난 분들과 프론트엔드 면접 스터디도 함께 진행할 계획이다. 어쩌다 학술 동아리 운영진도 맡게 되었다. 교내 창업 동아리를 통해 스타트업을 시작하신 대표님과 잘 연결되어 작지만 일도 병행하게 되었다(아직 학기가 시작도 안 했는데 일을 좀 많이 벌려놓았다..). 스타트업 업무에 대한 이야기는 3월 회고록에서 해볼 수 있으면 좋겠다.
'Life > 네이버 부스트캠프' 카테고리의 다른 글
네이버 부스트캠프 9기 웹 풀스택 과정 후기 (2) | 2024.12.16 |
---|---|
[부스트캠프 9기 멤버십] 8주차 회고록 (5) | 2024.10.23 |
[부스트캠프 9기 멤버십] 7주차 회고록 (0) | 2024.10.13 |
[부스트캠프 9기 멤버십] 6주차 회고록 (4) | 2024.10.06 |
[부스트캠프 9기 멤버십] 5주차 회고록 (1) | 2024.09.29 |
컴퓨터 전공 관련, 프론트엔드 개발 지식들을 공유합니다. React, Javascript를 다룰 줄 알며 요즘에는 Typescript에도 관심이 생겨 공부하고 있습니다. 서로 소통하면서 프로젝트 하는 것을 즐기며 많은 대외활동으로 개발 능력과 소프트 스킬을 다듬어나가고 있습니다.
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!