
신입 시절에 사수들을 보면서 대단하다는 생각을 했다. 복잡한 기능도 거뜬하게 완성하는 모습도 본받고 싶었다. 하지만 그보다 더 인상 깊었던 건, B2B 광고/CRM/MMP처럼 이해하기 어려운 도메인임에도 불구하고 깊이 있는 이해도를 바탕으로 여러 사람들과 커뮤니케이션하는 모습이었다. 이제 나도 합류한지 만 3년이 넘었다. 자연스럽게 실력도 붙었고, 서비스에 대한 이해도 역시 높아지면서 원하던 모습이 되었다.
지금 시점에서 사수들에 대해 다시 한 번 생각해보았다. 과거와는 다른 의미로 여전히 대단해보인다. 한 회사에 오래 근무하고 있다는 사실도 놀랍지만, 서비스에 대해 애정을 가진 채로 업무에 임한다는 사실이 대단했다. 사수들은 이 글을 보게 되면 애정이 없다고 말하겠지만, 그냥 내 눈에는 그래 보였다.

사실 2년 정도 근무했을 때까지는 회사나 서비스에 대해 애정을 가질만한 여유가 없었다. 그 나름의 이유는 아래와 같다.
물론 더 좋은 UI/UX 등을 고민하면서 기획 및 디자인 파트와 커뮤니케이션은 많이 했지만, 그 당시 내가 가진 대부분의 고민은 어떻게 하면 지금 만들고 있는 기능들을 완벽하게 구현할 수 있을지였다.
3년차가 되는 시점부터는 달랐다. 여전히 촉박한 스케줄이었지만, 나름 연차가 쌓였다고 노하우와 여유들이 생기기 시작했다. 유지보수 하기 좋은 코드나 설계 방법론 등에 대해서 고민했던 과거와는 다르게, 이제는 서비스를 발전시키기 위한 고민들도 함께 하게 되었다. 예를 들어,
등의 고민들을 하고 있다. 지금 생각해보면, 이렇게 자연스러운 고민의 흐름을 통해 애정을 가지기 시작한 것 같다. 원래도 재미 있었던 코딩이었는데, 이제는 묘하게 다른 재미도 추가된 기분이다.
올해는 정말 다양한 일들이 있었다. 예상 밖의 일을 담당하게 되기도 했고, 꾸준하게 원했던 일을 하면서 즐겁고도 힘든 시간을 보내기도 했다. 이 중심에는 조직 체계의 변화도 한 몫을 했다.
보통은 프론트/백엔드/기획/디자인/운영/사업 등 특정 서비스에 맞는 한 묶음의 서비스 기반 그룹이 존재한다. 기업에 여러 서비스가 존재하는 경우에는 서비스별로 이 그룹들이 생성되는 것이다. 대부분의 공고를 확인해보면, 'xx팀의 oo 서비스' 와 같은 포지션으로 채용하는 것처럼 말이다.
우리도 기존 조직 체계는 일반적인 회사와 다를바 없었다. 하지만 올해에는 스쿼드라는 체계를 도입하기 시작했다. 쉽게 말하자면 서비스마다 팀들이 존재하는 것이 아니고, 직무별로 하나의 챕터라는 조직으로 뭉쳐진다. 특정 서비스에 기능이 추가되거나 새로운 프로젝트를 하게 되면, 각각의 챕터에서 직무별로 인원들을 모집하여 하나의 스쿼드 조직으로 구성되는 형태이다.
A, B, C 3개의 서비스가 있다고 가정해보자. A 서비스에는 프론트엔드 개발자가 1명, B 서비스에는 3명, C에는 4명이 있다. 각각의 서비스에 배치되었던 프론트엔드 개발자를 합한 8명이 1개의 챕터로 묶인다. 이제는 각자 담당했던 서비스만 개발하는 환경이 아니다. A 서비스를 설계하던 개발자의 리소스가 비어있다면, 상황에 따라 B 혹은 C 서비스에 투입될 수 있다. 이처럼 스쿼드 조직 체계의 목적은 리소스를 조금 더 효율적으로 사용하기 위함이다.
프론트엔드 뿐만이 아니라 직무별로 챕터라는 조직으로 합쳐지는 개념이다. 토스 스쿼드 조직 영상을 보면, 어떤 느낌인지 이해하기 쉽다.

스쿼드 조직의 의의는 분명 합리적이다. 다만, 동시에 이상적인 구조이기도 하다. A 서비스에서는 PHP를 사용하고, B 서비스에서는 Vue2, C 서비스에서는 Next를 쓰고 있다고 생각해보자. 짧은 스프린트 주기를 가진 기능 개발 요청이 들어왔을 때, A 서비스를 개발하던 사람이 C 서비스를 감당할 수 있을까? 아니면 반대로 촉박한 일정속에서 Next만 사용했던 개발자가 갑자기 PHP를 사용하면서 살아남을 수 있을까? 솔직히 말해서 쉽지 않다.
그래서 우리는 기존에 만들었던 서비스는 유지보수 스쿼드로 남겨 두었다. 해당 서비스를 설계했던 사람들이 각각 알맞는 유지보수 스쿼드 조직에 들어가며, 이 조직 체계에서도 어느 정도 타협점을 찾은 것이다. 물론 추후에는 유지보수 스쿼드 마저도 기존의 개발자가 아닌, 챕터의 누구라도 소화할 수 있게끔 하는것이 목표이다.
그렇다면 유지보수 외의 건들은 어떻게 하는게 좋을까? 이제부터 만들어지는 새로운 서비스들이라도 스쿼드라는 핏에 맞도록 하는 것이 최선일 것이다. 그러기 위해서는 챕터에 소속된 사람의 리소스 상황에 맞게, 다양한 서비스에 투입될 수 있는 체계를 만들어야 한다. 프론트엔드에서는 이것의 첫 걸음을 프레임워크 통합이라고 보았다.
이 섹션에서는 스쿼드 조직 도입 이후, 기술 스택을 통합하게 된 이유를 정리한다.
스쿼드 조직으로 변하려는 과도기에 새롭게 만들어야 하는 서비스가 나타났다. Vue3 기반으로 설계되어 있던 기존의 광고 서비스를, 새로운 UI/UX로 업그레이드하고, 기존의 핵심적인 구조들을 마이그레이션 하면서, 여러가지 기능들을 추가 개발해야 하는 프로젝트가 등장한 것이다. 사실 내가 있던 팀에서 담당하던 서비스는 아니었지만, 챕터 리드는 평소에 다양한 것들을 시도하고 싶어했던 나의 모습을 보며, 이 서비스에 투입시켜주었다. 원래 이 서비스를 담당하던 프론트엔드 개발자와 함께 새로운 광고 서비스를 만들게 되었다.
이 프로젝트에 투입되고, 바로 한 가지 고민이 생겼다. 기존의 팀에서는 Vue3 위주로 프로그래밍을 했었는데, 이 프로젝트를 나에게 익숙한 Vue3를 사용할지, 아니면 새로운 기술 스택을 사용할지에 대한 고민이었다. 그러다 문득 스쿼드 조직의 챕터라는 체계를 다시 한 번 떠올렸다.
챕터 조직의 이상적인 모습이지만, 지금 당장 모두가 뷰, 리엑트, 넥스트 등 모든 기술 스택에 만능이 되는 것은 불가능하다. 그래서 우리는 모든 서비스의 기술 스택을 맞추는것이 유지보수하는데 있어 현실적이라고 판단했다.

이 서비스는 챕터 조직이 만들어 지고, 처음으로 설계하는 프로젝트이다. 지금 다시 만드는 프로젝트의 기술 스택이 앞으로 프론트 챕터에서 모든 개발자가 사용하게 될 가능성이 높았다. 나는 비교적 짧은 고민 끝에 리엑트 기반 프레임워크인 Next.js를 사용하기로 결정했다. 이유는 아래와 같다.
1. 넥스트는 뷰보다 사용자가 많다.
넥스트(혹은 리엑트)는 뷰보다 레퍼런스가 압도적으로 많다. 또한, 커뮤니티도 활발하며 지속적으로 유지보수 되는 프레임워크이다. 기업 입장에서도 추후 인력 자원을 충원하는 경우에도 유리할 것이다.
2. 더 좋은 사용자 경험을 제공하고 싶다.
뷰 혹은 리엑트만으로는 제공하기 어려운 UX들을 Next를 통해 채워나가고 싶었다. 서비스를 사용하게 만드는 방법에 좋은 기능을 제공하는 것도 있겠지만, 조금이라도 더 피로감이 덜하고 매끄러운 사용자 경험이라고 생각했기 때문이다.
3. 우리가 넥스트를 학습하는 편이 더 낫다고 판단했다.
챕터로 합쳐지는 팀 중에는 이미 Next를 사용하고 있는 팀도 있었다. 결국에 Next를 사용하던 팀과 우리 팀중에서 한 팀은 새로운 스킬에 익숙해져야 하는 것이다. 다른 팀이 뷰에 대해 학습하며 익숙해지는 것보다, 우리 팀에서 넥스트를 사용하는 것이 더 합리적이라고 생각했다.
4. 후회를 반복하고 싶지 않았다.
이미 과거에 비슷한 상황에서 뷰를 선택했었다. 여러 가지의 이유로 내린 합리적 결정이었지만, 프론트 팀 내부에서는 아직까지도 아쉬운 판단이었다고 회자되고 있다. 그래서 이번만큼은 같은 선택을 반복하고 싶지 않았다.

이렇게 결정된 넥스트 기반으로 프로젝트를 설계해야 하는 상황에서, 여러 고민들이 생기기 시작햇다. 프론트엔드 챕터가 효율적으로 운영되기 위해서는 무엇을 해야하는지 말이다. 고민 끝의 결론은 역시 유지보수 하기 좋은 구조였다. 남이 작성한 코드는 내가 이어서 개발하기 쉬워야하고, 내가 작성한 코드도 남이 개발하기 쉬워야 한다. 그래야 챕터라는 조직을 운영하는 의미가 있다고 생각했다.
이와 같이, 유지보수 하기 좋은 구조 및 체계를 잡기 위해서는 선발 주자의 역할이 중요하다. 처음에 설계된 구조들은 이후의 서비스에도 영향을 미칠것이 분명하기 때문이다. 또한, 이후에 따라오는 동료 합리적으로 수긍할 수 있는 구조를 설계해두어야, 동료들도 서비스 설계에 100% 집중할 수 있다. 물론 처음부터 완벽한 형태를 가질 수는 없지만, 안티패턴은 피할 수 있고, 우리의 환경과 업무 스타일에 맞는 구조를 먼저 고려해볼 수도 있다.
아래에서 가장 기본이라고 생각되는 4가지에 대해서 다루어 보겠다.
보통 남이 짠 코드보다, 내가 짠 코드가 유지보수 하기 좋은 이유는 친숙하기 때문이다. 그렇다면 남이 짠 코드를 어떻게 나한테도 친숙하게 만들 수 있을까? 바로 컨벤션을 정하고, 린트/프리티어/스타일린트 등을 통일하는 것이다. 어느 정도 코드 스타일만 통일해도, 코드를 읽는 것이 훨씬 수월해진다. 나는 컨벤션이라는 것이 들어가는 비용 대비 얻는 효과가 크다고 생각한다.
유지보수성을 크게 높이기 위해 할 수 있는게 하나 더 있다. 모든 서비스에서는 동일한 컴포넌트를 사용하는 것이다. 만약에 서비스마다 사용하는 Select 컴포넌트가 따로 존재하고, 이 안의 UX로직이 전부 다르다고 가정해보자.
prop을 가지고 있었는지 전부 기억하기가 어렵다.이와 같은 문제점들을 해결하기 위해, 디자인팀과 협의하여 디자인 시스템 기반으로 공통 컴포넌트들을 설계했다. 물론 이 컴포넌트의 기능은 동일하다. 예를 들어, 셀렉트의 레퍼런스 부분들 클릭하면, 드롭다운 형태의 옵션 리스트가 나오는 것은 똑같다. 하지만 서비스별로 UI는 달라질 수 있다. A 서비스에서는 셀렉트의 contained 타입의 variant 색상들이 진한 컬러였는데, B 서비스에서는 파스텔 톤이라던가 말이다. 이것을 가능하게 해주는것이 디자인 토큰 기반 디자인 시스템이다.
디자인 시스템 관련 기술 블로그
컴포넌트에는 컴포넌트 토큰이 적용되어 있다. 그리고 이 컴포넌트 토큰은 시스템 토큰으로 연결되어 있고, 시스템 토큰은 레퍼런스 토큰으로 연결된다. 위와 같이 서비스마다 다른 UI를 가질 수 있는 것은 바로 이 구조이다. 각 서비스에 맞게 컴포넌트 토큰에 바인딩된 시스템 토큰만 변경해 준다면, 컴포넌트 코드를 변경하지 않고, 서비스에 맞는 UI를 적용시킬 수 있는 것이다.
<Dialog.Root>
<Dialog.Trigger className={styles.Button}>Trigger</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Backdrop className={styles.Backdrop} />
<Dialog.Popup className={styles.Popup}>
<Dialog.Title className={styles.Title}>Title</Dialog.Title>
<Dialog.Description className={styles.Description}>
Description
</Dialog.Description>
<div className={styles.Actions}>
<Dialog.Close className={styles.Button}>Close</Dialog.Close>
</div>
</Dialog.Popup>
</Dialog.Portal>
</Dialog.Root>
또한, 컴파운드 컴포넌트 패턴으로 설계하여 커스텀 되는 상황도 고려했다. 셀렉트의 레퍼런스 버튼을 누르면 나오는 드롭다운에 검색 인풋을 넣고 싶다거나, 옵션 아이템 하나 하나의 스타일을 다르게 하고 싶다는 등의 요구사항을 충족시킬 수 있도록 커스텀 하기 좋은 구조를 설계한 것이다. 이렇게 서비스마다 매번 컴포넌트를 만드는 작업을 제거할 수 있었고, 실제로 새로운 서비스를 만드는 경우에 엄청난 시간 절약을 할 수 있게 되었다.
monorepo/
├── apps/
│ ├── 서비스1/
│ ├── 서비스2/
│ └── 서비스3/
│
├── packages/
│ ├── 공통-컴포넌트/
│ └── 공통-유틸-훅/
│
└── config/
├── eslint/ # 공통 ES린트
├── prettier/ # 공통 프리티어
├── stylelint/ # 공통 스타일린트
└── tsconfig/ # 공통 tsconfig
우리는 모노레포 구조를 선택했다. 물론 브랜치 전략이나 CI/CD 에 대해서는 일반적인 방식보다 조금 더 고민해야겠지만, 모노레포는 여러 라이브러리의 버전을 맞추기도 쉽고, 결정한 컨벤션이나 린트들을 지키기 수월하며, 디자인 시스템 기반으로 설계한 공통 컴포넌트를 가져다 사용하기에도 좋은 구조였다.
공통 컴포넌트 뿐만 아니라, 헬퍼 함수, 커스텀 훅, 모델 등 모든 서비스에서 사용할 수 있는 공통 요소들도 분리해서 사용하고 있다. 지금은 서비스별 배포 방식도 통일되어 있어, 여러가지 측면에서 유지보수성이 올라갔다.
서비스를 만들기 위해서는 데이터 패칭이 필수이다. 서비스별로 API와 통신하는 부분이 상이하고, 통신 이후에 인터셉터나 에러 핸들링하는 부분들이 다르다면 적응하기 어려울 것이다. 나는 이것을 통일하기 위한 노력들을 했었다. 이에 대한 것은 나도 드디어 Next.js 쓰는건가?! 글에서 만나볼 수 있다. API 통신 체계를 잡아가면서, 베스트 케이스를 찾아가는 과정을 담았다. 서버 액션, SSR, 클라이언트 사이드 요청과 같은 Next의 특성과 Tanstack Query와의 조합을 구성했다.
기존에는 로딩이나 에러 상황에 맞는 화면을 보여주기 위해 isLoading, isError와 같은 상태를 직접 관리했다. 이 방식은 데이터 패칭이 이루어지는 페이지나 컴포넌트마다 로딩·에러 처리 로직이 반복적으로 작성되는 구조라는 한계를 가지고 있었다.
이 문제를 개선하기 위해 Suspense와 Error Boundary를 도입했다.
로딩과 에러 처리를 컴포넌트 외부 레이어로 분리함으로써, 개별 컴포넌트는 항상 데이터가 존재한다는 전제하에 설계할 수 있었고, 그 결과 불필요한 조건 분기와 실수 가능성을 크게 줄일 수 있었다.

또한 로딩 및 에러를 처리하는 책임과 실제 UI 로직이 명확히 분리되면서, 컴포넌트의 역할과 구조가 더 또렷해졌다. 특히 SSR 환경에서 Suspense를 활용할 경우, 하이드레이션 이전에 서버에서 바로 스켈레톤 UI를 제공할 수 있어 UX 측면에서도 긍정적인 효과를 얻을 수 있었다.
하지만 실제로 사용해보니, 모든 상황을 서스펜스로 해결할 수 있는 것은 아니었다. 예를 들어, 특정 상황에서만 데이터 패칭이 필요해 useQuery의 enabled 옵션을 사용해야 하는 경우도 있었고, 부모와 자식 컴포넌트가 동일한 데이터를 사용하지만 로딩 UI는 자식 컴포넌트에만 노출되어야 하는 구조도 존재했다. 이런 다양한 케이스들을 마주치면서, 서비스에서는 하나의 방식만 고집하는 것이 아니라, 상황에 맞는 방법을 사용하는 것이 적합하다는 것을 다시 한 번 배웠다.
이와 같이, 컨벤션, 공통 컴포넌트 및 유틸, 모노레포 구조, 데이터 패칭, 서스펜스/에러 바운더리 등 여러 구조들을 만들었다. 이는 유지보수성만 높인것이 아니라, 새로운 기능이나 서비스가 등장했을 경우에 더 빠르게 적응하고 개발할 수 있게 되었다.
서스펜스와 에러 바운더리, 그리고 Tanstack Query와의 조합은 추후에 새로운 글로 정리할 예정이다.
이 섹션에서는 Web SDK를 담당하며, 서비스 전반이 어떻게 유기적으로 연결되는지 체감했던 경험을 정리한다.
기존에 Web SDK를 담당하던 개발자분이 다른 직무를 맡게 되면서, 프론트엔드 개발자중 한 명이 유지보수 해야 하는 상황이 왔다. Web SDK 세계로 초대받다. 글에서 자세하게 다루고 있는데, 결국 내가 담당하게 되었다. 지금 생각해보면 이 또한 견문을 넓힐 수 있는 기회였던 것 같다. SDK라는 것이 어떤식으로 흘러가는지 알게 되었고, 우리의 서비스를 더욱 깊게 이해할 수 있는 계기가 되었다.
버그 픽스나 여러 가지의 유지보수를 진행했었는데, 가장 기억에 남는것은 '멀티 인앱 메시지' 였다.

인앱 메시지는 앱 위에 띄우는 팝업을 말한다. 쇼핑몰 앱에 진입하는 경우, 특가 세일을 위한 팝업을 보여준다고 가정해보자. 이를 위해, 쇼핑몰 개발자가 직접 모달과 같은 컴포넌트를 만들수도 있다. 하지만 이것은 다른 광고를 보여주기 위해서는 다시 앱을 배포해야 한다는 단점이 존재한다. 그래서 대부분의 기업들은 쉽게 광고 캠페인을 관리하고, 여러 방식의 추적을 통해 리포트를 산출하여, 다양한 마케팅으로 충성 고객 혹은 신규 고객을 모집할 수 있는 CRM 서비스를 이용한다.
CRM 서비스를 사용하면 매우 효과적으로 광고를 집행할 수 있다. 앱이나 웹에 CRM을 위한 SDK를 연결하고, CRM 콘솔에서 집행하고 싶은 광고 캠페인을 생성하면 된다. 이렇게 하면, '장바구니를 클릭하는 순간, 20분안에 구매하면 할인을 더 해준다는 광고 팝업을 띄우기' 와 같은 마케팅들을 쉽게 관리할 수 있다.
CRM 콘솔 웹 서비스에서는 폼 설정을 통해 광고 캠페인 팝업을 만들 수 있다. 그리고 여기에는 설정값 기반으로 어떤 화면이 구성되고 있는지 실시간으로 확인할 수 있는 미리보기 UI가 존재한다. 이것이 미리보기 화면일지라도, 실제로 디바이스에 띄워지는 인앱메시지의 UI/UX와 일치해야 할 것이다.
이를 위해 콘솔의 미리보기에서도 실제 유저의 디바이스에 나오는 템플릿을 사용하면 된다. 이런 부분들을 고민하면서 인앱 메시지 템플릿을 설계해야 한다. 하나의 템플릿으로 다양한 디바이스에서 동일한 UI/UX를 제공하고, 미리보기 화면과 실제 노출된 광고의 갭 차이가 발생하는 것을 방지시킨 것이다.
멀티 인앱 메시지는 보통 인앱 메시지와 다르게 다수의 이미지를 첨부할 수 있다. 이는 캐러셀 UI/UX 기반으로 설계 되었고, 자동 캐러셀, 무한 캐러셀, 마우스 및 터치 등 여러 케이스가 고려되었다.
기존에 존재하던 템플릿들은 인터렉션이 없었고, 멀티 인앱 메시지의 템플릿에서는 캐러셀의 인터렉션이 존재한다. 비록 콘솔의 미리보기 화면이 디바이스 모양처럼 생기고, 그 안에 실제 템플릿이 떠있을지라도, 사용자가 미리보기 화면에서 드래그를 하는 등의 행위를 하지 않을 수 있겠다는 생각이 들었다. 그래서 우리는 더 좋은 사용자 경험을 제공하기위해 미리보기 UI 하단에 템플릿의 캐러셀을 좌우로 넘길 수 있는 버튼을 만들었다.

사실 비개발자 입장에서는 좌우 버튼 하나였지만, 나의 고민은 깊어져만 갔다. 지금 템플릿은 모두 같은 동작을 하도록 만들어져 있는데, 미리보기에서만 다른 버튼에 의해 템플릿의 캐러셀이 동작한다던가, 두 번째 캐러셀부터 템플릿이 렌더링 된다던가의 동작이 필요해진 것이다. 혹은 요구사항에 따라 미리보기에서 사용하는 템플릿에서는 드래그 동작을 막을수도 있다.
이를 위해서 SDK에서는 다양한 인터페이스를 제공하고, 미리보기를 위한 레포도 만들어지고, 이후에는 콘솔과 preview가 iframe 통신을 하는 구조가 되었다.
SDK의 역할 중 하나는 이벤트를 전송하고 감지하는 것이다. 고객이 서비스에 진입 한다던가, 로그인을 성공했다던가, 상품을 구매했다는 등의 이벤트를 기다린다. 그리고 콘솔에서 만들었던 캠페인들 중에 '로그인 성공'하면 띄워줄 광고 팝업이 있었다면, 그 캠페인을 해당 시점에 노출시켜주는 것이다.
멀티 인앱메시지에서 가장 재미있었던 부분은 API, Console, SDK, 템플릿 등 다양한 것들이 합쳐져서 단 하나의 동작을 하게 만드는 것이었다. 이 부분들을 자세하게 알아보면서, 서비스를 더욱 깊게 알게 된 것도 사실이지만, 개발자로서의 견문도 확실히 넓어진 기분이었다. 조금 힘들었던 부분도 있었다. 같은 템플릿이어도 Web에서는 화면이 깨지지 않고 캐러셀도 정상적으로 동작했지만, 안드로이드 혹은 IOS에서는 이상하게 보이거나 캐러셀 동작 자체가 안하는 경우들이었다. 여러 디바이스를 연결해서 실제로 디버깅해보며 하나하나 해결해나간 결과 무사히 기능을 완성하긴 했지만, 정말 너무 힘든 시간이었던거 같다.
나는 업무를 하면서 GPT, 재미나이, 웍스 AI, 클로드, Amazon Q 등 다양한 AI 서비스를 이용했다. 우리 서비스에서도 이와 같은 AI 기능을 제공하기 위한 피쳐가 생겼고, 나는 서브 개발자로 참여하여 서포팅을 수행했다. 목적은 누구나 쉽게 데이터 분석할 수 있게 도와주는 것이다. CRM을 통해 얻은 데이터를 기반으로 다양한 분석을 할 수 있다. 숙련된 마케터는 여러 방식으로 분석을 진행할 수 있지만, 사실 초보 마케터에게는 쉽지 않은 영역일 수 있다. 우리가 만든 AI Agent는 마케터 옆에 붙어서 다양한 분석을 할 수 있게 도와주는 전문가로써 사용할 수 있도록 개발되었다.

AI와 대화할 수 있는 인풋에 원하는 데이터 분석 방식을 입력하면, 내부적으로 다양한 AI Agent들이 데이터 분석 및 검증을 수행하고, 결과를 도출하여 텍스트와 차트로 보여준다. 이 기능은 프론트엔드 입장에서도 할게 많다. 차트를 잘 뽑아내기 위한 프롬프트를 설계한다던가, 타이핑치는 것처럼 UI/UX를 보여준다던가, 첫 대화가 완성되는 시점에 대화 목록 갱신 및 대화 제목 결정을 한다던가 말이다.
또한, SSE로 오는 데이터를 잘 핸들링 해야한다. 예를 들어, 4글자씩 온다고 가정해보자. <sect 이 오면, 아직 화면에 그리면 안된다. ion> 처럼 태그가 닫히는 경우에만 어떤 태그인지 판단할 수 있기 때문이다. 심지어 닫히는 태그가 올때까지 기다리는것도 좋지 않다. 태그의 댑스가 깊어질수록 유저는 오랫동안 빈 화면을 볼 수 있기 때문이다. 이런 부분들을 고민하면서, AI Agent 기능을 완성해나갔다.
항상 그래왔지만, 올해 역시 많은 성장을 이룬거 같다. 넥스트를 효율적으로 사용하기 위한 고민도 많이 해보고, SDK 영역에도 들어가 보고, 요즘 가장 핫한 주제인 AI 관련 서비스도 만들기도 했지만, 개인적으로 약하다고 생각했던 인프라 부분도 여러 서비스들을 배포해본것이 좋았다. CI/CD 개선도 해보며 다양한 경험을 쌓아 나갔고, 지금은 나머지 부족한 부분들도 책을 통해 조금씩 채워나가고 있다. 이런 부분들이 개발자로서의 재미들을 충족시켜주는 것 같다.
그리고 요즘 확실히 느끼는 부분은 과거에는 매우 어렵게 느껴졌던 것들이 AI를 통해 쉽게 이해할 수 있게 되었다는 것이다. 어떻게 보면 우리의 일자리를 앗아갈 수 있는 AI이지만, 이것을 어떻게 활용하느냐에 따라서 엄청난 개발자를 만들기도 할 것 같다. 그래서 나의 올해 목표는 AI를 극한으로 활용하는 것이다.