2026년 05월 회고
- 월간회고
- 회고

이번 달을 돌아본다면
3주간의 온보딩
서비스와 레포를 파악하며 전체적인 흐름에 익숙해지는 시간이었다. 새로 접하는 기술이 많아 처음에는 허덕이기도 했지만, 서비스와 연결 지어 이해하기 시작하면서 점차 속도가 붙었다. 어떤 어려움이 있을지는 직접 부딪혀봐야 알 수 있는 만큼, 일단 해보면서 하나씩 쌓아가려 한다.
스터디의 방향성 재설계
AI가 발전함에 따라, 머지않아 개발의 다양한 분야가 problem solver라는 하나의 방향으로 수렴할 것이라 생각한다. 단순 구현은 AI가 점점 대체하고, 사람에게는 문제를 발견하고 정의하는 능력이 더욱 중요해질 것이다. 이러한 맥락을 스터디원들과 함께 논의하며, 설계 중심으로 스터디 방향을 재설정했다. 실제 대규모 서비스를 가정하고 발생할 수 있는 문제와 효율적인 구조를 함께 고민해보고자 한다.
AI에 대한 학습 목표
각 분야에서 AI 를 통한 생산성 향상이 두드러지고 있지만, 이를 유기적으로 연결해주는 흐름은 아직 부족하다고 느낀다. Claude, ChatGPT 는 많이 쓰이지만, n8n 같은 자동화 / 연결 도구를 비개발 직군이 직접 학습하고 활용하기에는 여전히 진입 장벽이 존재한다.
전체 생산성을 높이기 위해서는 조직 내에서 AI 를 목적에 맞게 연결하고 활용할 수 있는 구조가 필요하다. 그 중심에는 AI 에이전트 설계와 구축에 대한 고민이 있으며, 특히 어떤 문제에 AI 를 적용할지 명확히 정의해야 도구와 워크플로우를 효과적으로 엮어낼 수 있다. 이에 따라 어떤 문제를 선택하고 어떻게 정의할지 기준을 명확히 세우고, 설계까지 이어가는 것을 3개월 간의 목표로 삼았다.
레거시 코드를 마주하다.
기존까지 레거시 코드에 대한 생각은 어땠는가?
레거시 코드라는 단어를 "과거에 작성된, 개선이 필요한 코드" 정도로 막연하게 생각해왔다. 특정 서비스를 오래 유지보수해본 경험도 없었기에, 나에게 레거시 코드란 기껏해야 몇 주 혹은 몇 달 전에 작성한 코드였다. 레거시를 개선한다는 것도, 더 효율적으로 짤 수 있겠다 싶은 코드를 손보는 정도에 불과했다.
처음 레거시 코드를 마주했을 때 어떤 느낌이었는가?
온보딩 첫 주, 몇 년 전 코드부터 며칠 전 코드까지 한꺼번에 마주했다. 이렇게 오래됐다고? 왜 같은 역할을 하는 컴포넌트가 여러 개지? 처음에는 당황할 수밖에 없었다.
package.json을 열었을 때는 구버전 라이브러리들이 눈에 띄었고, 아무것도 모르는 상황에서 버전 숫자가 주는 위압감이 낯설게 느껴지기도 했다. 그래도 분명한 이유가 있을 거라 생각하며 침착하게 코드를 들여다봤다.
코드를 분석하며 느낀 점은 무엇인가?
맥락을 조금씩 이해해갈수록 코드의 흐름이 납득되기 시작했다. 서비스가 지속될수록 코드는 자연스럽게 오래되고, 버전 업데이트나 급한 이슈 대응 과정에서 과거 코드가 그대로 남기도 한다. 이런 맥락이 보이기 시작하자 시야가 조금씩 넓어졌다.
레거시를 줄이고 버전을 올려가려는 팀의 시도들도 눈에 들어왔다. 이 과정에서 내가 할 수 있는 것은 무엇일지 고민하게 됐다. 최신 버전에 익숙한 만큼 구버전과의 차이를 빠르게 파악하고, 어떤 이유로 바뀌었는지를 이해하는 데 강점이 있을 것이라 생각한다. 이렇게 변화의 이유를 이해하고 개선 방향까지 고민해본다면, 팀에 충분히 기여할 수 있을 것이라 생각한다.
온보딩이 끝난 지금, 레거시 코드를 다시 돌아보면?
최신 버전으로만 구성된 서비스보다, 오히려 지금 이 시점에 합류한 것이 더 큰 기회라는 생각이 든다. 서비스 맥락 안에서 현재 상태가 어떤 문제에서 비롯되었는지, 어떻게 개선해나갈 수 있을지를 직접 고민해볼 수 있기 때문이다. 단순히 완성된 결과를 이해하는 것을 넘어, 그 과정과 의도를 함께 따라가며 이해할 수 있다는 점에서 더욱 의미 있게 느껴진다.
코드 리뷰를 받아보며
코드 리뷰 전, 코드 작성
어떤 방식으로 코드를 작성했는가?
온보딩 중반쯤, 특정 페이지를 따라 만들어보는 클론 코딩을 진행했다. 실제 업무가 주어졌을 때 빠르게 작업할 수 있을지 의문이었고, 내가 인지하지 못하는 빈틈이 무엇인지 파악하기에도 좋을 것 같았다. 이때, 내가 중점을 둔 부분은 두 가지였다.
생각한 대로 코드가 잘 짜였는가?
첫 구현은 정말 최악이었다. AI에게 원하는 내용을 요청해도 빠진 부분이 많아 계속 재요청하는 일이 반복됐다. 단순히 프롬프트를 잘못 쓴 문제가 아니라, 기능 하나하나를 구체적으로 정의하지 못했던 것이다.
예를 들어 캐시 정책의 경우, AI 는 다른 페이지들을 참고해 비슷하게 가져왔겠지만, 각 페이지마다 정책이 다르기 때문에 이런 부분은 직접 설계해서 전달해야 했다. 개념을 먼저 잡아야 AI 에게 제대로 된 방향을 제시할 수 있다는 것을 확실하게 느꼈다.
코드 리뷰를 통해 배운 것들
최적화를 습관처럼 적용하자.
피드백을 받으며 번들 크기 같은 성능 관련 부분을 놓쳤다는 것을 깨달았다. 돌이켜보면 지금까지는 구현을 마친 뒤 리팩토링 단계에서 최적화를 고민했고, 그마저도 건너뛴 경우가 많았다. 최적화를 자연스럽게 떠올리는 습관이 몸에 배어 있지 않았던 것이다.
앞으로는 “이렇게 하면 번들 크기에 영향이 가지 않을까?”라는 생각이 저절로 떠오르는 습관을 들이고자 한다. dynamic import 로 라우트 단위로 코드를 분할하거나, bundle analyzer 로 번들 크기를 분석하는 과정을 구현 단계에서부터 적용해나가야겠다.
깨끗하고 이쁜 코드가 항상 좋은 것은 아니다.
예를 들어 4개의 카드를 나열할 때, 카드 데이터를 객체로 선언하고 배열로 감싼 뒤 map으로 반복했다. 깔끔하고 의도도 명확하다고 생각했다.

const CARDS = [
{ id: 1, icon: '🏠', title: '홈 대시보드', ... },
{ id: 2, icon: '📊', title: '분석 리포트', ... },
{ id: 3, icon: '⚙️', title: '설정', ... },
{ id: 4, icon: '🔔', title: '알림', ... },
]
// BaseCard 선언부
function BaseCard({ ... }) {
return (
<div>
<div>{icon}</div>
<h3>{title}</h3>
<p>{description}</p>
</div>
)
}
// BaseCard 호출부
{CARDS.map((card) => (
<BaseCard key={card.id} {...card} />
))}하나의 카드에만 요구사항이 추가된다면 어떻게 대응할 것인가? 나는 항상 객체에 특정 필드를 추가하는 방식을 택했다.

const CARDS = [
{ id: 1, icon: '🏠', title: '홈 대시보드', ... },
{ id: 2, icon: '📊', title: '분석 리포트', isNew: true, badge: 'NEW', ... }, // ← 예외 필드 추가
{ id: 3, icon: '⚙️', title: '설정', ... },
{ id: 4, icon: '🔔', title: '알림', ... },
]
// BaseCard 선언부
function BaseCard({ ... }) {
return (
<div>
{badge && (<Badge>{badge}</Badge>)}
<div>{icon}</div>
<h3>{title}</h3>
<p>{description}</p>
</div>
)
}
// BaseCard 호출부
{CARDS.map((card) => (
<BaseCard key={card.id} {...card} />
))}만약 알림 개수를 뱃지로 보여달라는 요구사항이 또 추가된다면 어떻게 할 것인가? 새로운 badgeColor 를 props 로 또 추가할 것인가? 이때 BaseCard 의 역할이 명확하게 추측 가능한가?

문제는 이렇게 isNew, badge, badgeColor 같은 필드가 쌓일수록 BaseCard 내부에 분기가 누적되고, 컴포넌트의 역할이 모호해진다는 점이다. 새로운 필드를 추가할 때마다 배열과 컴포넌트를 함께 수정해야 하니 실수하기 쉽고, 의도도 바로 드러나지 않는다.
이런 경우에는 오히려 카드 컴포넌트를 인라인으로 직접 작성하는 편이 나을 수 있다. 코드가 중복되더라도 각각의 역할이 한눈에 들어오고, 변경에도 더 유연하게 대응할 수 있기 때문이다.
// BaseCard 선언부
function BaseCard({ ... }) {
return (
<div>
<div>{icon}</div>
<h3>{title}</h3>
<p>{description}</p>
</div>
)
}
// BadgedCard 선언부
function BadgedCard({ ... }) {
return (
<div>
<Badge>{badge}</Badge>
<div>{icon}</div>
<h3>{title}</h3>
<p>{description}</p>
</div>
)
}
<BaseCard icon="🏠" title="홈 대시보드" description="..." />
<BadgedCard badge="NEW" icon="📊" title="분석 리포트" description="..." />
<BaseCard icon="⚙️" title="설정" description="..." />
<BaseCard icon="🔔" title="알림" description="..." />코드는 함께 읽는 문서다.
의도와 목적이 분명한 코드는 흐름을 예측하며 읽어 내려갈 수 있었다. 반면 내가 작성한 일부 코드는 예측이 어려워 한 줄씩 맥락을 쌓아가며 읽어야 했다. 중간에 의도를 놓치는 순간 다시 처음부터 읽게 되고, 이는 분명한 피로와 비용으로 이어진다.
피드백 중 특히 인상 깊었던 것은 useEffect 안에서 기명 함수를 사용하는 방식이었다. 단순한 이름 하나만으로도 해당 effect의 역할을 바로 예측할 수 있다. 작은 차이지만, 코드의 가독성에 분명한 영향을 준다는 것을 느꼈다.
// Bad: 익명 함수
// effect가 어떤 역할을 하는지 코드를 읽으며 맥락을 쌓아야 함
useEffect(() => {
if (!userId) return
fetch(`/api/users/${userId}`)
.then((res) => res.json())
.then((data) => setUser(data))
}, [userId])// Good: 기명 함수
// 선언부에서 의도를 즉시 예측 가능
useEffect(function fetchUserProfile() {
if (!userId) return
fetch(`/api/users/${userId}`)
.then((res) => res.json())
.then((data) => setUser(data))
}, [userId])항상 순응하지말고 내 생각을 놓치지 말 것.
그동안은 아는 내용 앞에서는 비판적으로 생각하려 했지만, 모르는 내용이 나오면 흐름을 따라 그대로 받아들이는 경우가 많았다. 하지만 서비스가 오래 유지될수록 코드에는 다양한 맥락이 쌓이고, 그로 인해 항상 최선의 상태만 유지되지는 않는다.
이런 이유로 현재의 코드가 반드시 좋은 코드라고 볼 수는 없다. 그렇기 때문에 단순히 받아들이기보다는, 더 나은 방법이 있는지 고민하며 비판적으로 바라볼 필요가 있다. 이를 위해 지식을 쌓고, 다양한 관점에서 문제를 바라볼 수 있는 힘을 키워야겠다.
팀 단위의 개발
프로세스를 개선하려는 자세
팀 차원에서 업무 프로세스를 개선하려는 모습이 인상 깊었다. 단순히 불편함을 공유하는 데 그치지 않고, 어떻게 더 나아질 수 있을지를 함께 고민하고 적극적으로 의견을 나누었다. 이 팀에 합류한 것이 특히 의미 있게 느껴진 순간이었다.
이전에는 비슷한 문제를 마주하더라도 팀 안에서 충분히 논의되거나 실행으로 이어지지 않는 경우가 많았다. 낯섦에서 오는 부담과 익숙함에서 오는 관성이 변화를 막는다고 느꼈다. 하지만 이곳에서는 의견을 더 적극적으로 내고, 문제를 개선으로 이어갈 수 있을 것이라는 기대가 생겼다. 문제를 문제로 남기지 않고, 시도와 변화의 흔적을 남길 수 있도록 계속 고민하고 제안해보고자 한다.
AI 를 더 잘 활용할 수 있도록
입사 후 팀에서 AI 를 목적에 맞게 적극적으로 활용한다는 인상을 받았다. 나 역시 여러 시도를 해왔지만, 실제 업무 맥락에서 활용하는 방식에는 아직 부족함이 많았다.
이처럼 여러 방면에서 AI 가 단순한 편의 도구를 넘어, 목적을 더 빠르고 명확하게 전달하기 위한 수단으로 사용되고 있다는 점이 인상적이었다.
코드 레벨에서의 AI 활용
팀 단위로 AI를 활용할 때는 주의할 점이 있다고 생각한다. 명확한 기준 없이 사용하면 각자 다른 코드가 만들어지기 쉽고, 이는 곧 일관성 저하로 이어진다. AI가 흔들리지 않도록 이끌어줄 팀 차원의 기준과 컨벤션이 필요하다.
특히 개인의 판단이 크게 개입되는 영역일수록 기준이 모호하면 더 큰 차이를 만든다. 코드의 규모가 커질수록 새로운 영역을 마주하는 일은 피할 수 없고, 이를 이해하는 데에는 분명한 비용이 든다. 만약 일정한 구조와 기준이 있다면, 처음 접하는 코드도 익숙한 흐름으로 이해할 수 있다.
AI로 작성과 이해를 보조할 수는 있지만, 최종적인 판단과 책임은 여전히 사람에게 있다. 그렇기 때문에 기준을 세우고 이를 기반으로 점진적으로 개선해나가는 것이 팀의 생산성을 높이는 데 중요하다고 생각한다.
회고를 마무리하며
함께 고민하려면 지식이 필요했다
스크럼, 코드 분석, PR 리뷰를 경험하며 느낀 것은 지식이 있어야 함께 의견을 나누고 고민할 수 있다는 점이었다. 팀원이 특정 부분을 고민할 때 도움이 되고 싶다는 마음은 있었지만, 지식이 뒷받침되지 않으면 그 자리에서 함께 생각하는 것조차 쉽지 않았다.
아직 부족한 점이 많다고 느낀다. 다만 온보딩을 거치며 서비스를 이해하는 속도가 붙었고, 코드를 바라보는 시야도 조금씩 넓어졌다. 몇 달 뒤면 지금과는 또 다른 모습으로 성장해 있을 것이라는 기대가 생겼다.
다음 달에는 어떤 점들을 도전해볼 수 있을까?
사람도 AI 도 결국 시행착오를 거치며 다듬어진다고 생각한다. 그래서 계속 시도하고, 그 과정에서 기준을 만들어가는 것이 중요하다.
AI skill 과 rule 을 만들어 테스트해보며 팀원들과 공유할 계획이다. 어떤 prompt 가 효과적인지, 어떤 상황에서 AI 가 잘 작동하는지 구체적인 사례를 기록하고, 이것이 생산성에 어떻게 기여했는지 측정할 예정이다. 개선이 필요한 지점들을 찾아 문서화하고, 필요하면 수정을 제안하거나 이슈로 남겨둘 것이다.
PR 리뷰에 적극적으로 참여해 팀원들의 코드를 보며 다양한 접근법을 배우고, 피드백을 받으며 시야를 넓혀가려고 한다. 결국 우리가 만든 기준과 AI 활용 방식이 실제 서비스 개선으로 이어지도록 계속 고민해보고자 한다.

