고통 기반 개발 (Pain-Driven Development)
요약
중복된 로직을 단순히 추출하는 AI 방식의 해결책과 아키텍처적 통찰력을 바탕으로 한 구조적 개선의 차이를 다룹니다. AI는 기능적 구현에 집중하지만, 개발자는 미래의 유지보수와 코드 구조를 고려하여 근본적인 설계 문제를 해결해야 함을 강조합니다.
핵심 포인트
- AI는 기능적으로 작동하지만 구조적으로 잘못된 코드를 생성할 수 있음
- 단순한 코드 추출(DRY)보다 명명과 계층화가 더 중요한 문제일 수 있음
- 좋은 아키텍처는 AI 에이전트가 이해하기 쉬운 작은 컨텍스트를 제공함
- 개발자의 역할은 단순 구현을 넘어 고통을 통해 구조적 통찰력을 얻는 것
문제 상황
오늘 저는 GitHub 이슈 하나를 할당받았습니다. 거의 동일한 두 개의 Laravel 이벤트 리스너(event listeners)가 있었는데, 각각 130줄에 달하며 동일한 오케스트레이션(orchestration) 로직을 중복해서 수행하고 있었습니다. 엔티티(entity)를 로드하고, 몇몇 외부 API에 걸쳐 동기화 라이프사이클(sync lifecycle)을 관리하며, 다섯 개의 UseCase 클래스를 순차적으로 호출하고, 에러를 처리하는 로직이었습니다.
"괜찮은" 해결책
해당 이슈에서 제안된 해결책(괜찮고 작동은 하지만, 아마도 절반은 AI가 생성했을 법한 방식)은 공유된 로직을 SyncUseCase로 추출하고, 두 리스너가 모두 이를 호출하도록 만드는 것이었습니다.
그것은 작동하는 해결책이었을 것이고, 저는 1시간 안에 끝낼 수 있었을 것입니다. AI라면 10분 만에 해냈을 것입니다.
하지만 저는 그렇게 하지 않았습니다.
갈증
뇌 한구석에서 가려움이 느껴졌습니다. 제 뇌는 이렇게 말하고 있었습니다. "이봐, 그러면 유스케이스(use cases)가 서비스를 호출하고, 그 서비스가 다시 유스케이스를 호출하는 상황이 생길 거야."
물론 코드는 감정이 없기 때문에 프로덕션(production) 환경에서는 문제없이 작동할 것입니다.
하지만 우리는 N단계로 중첩된 유스케이스(N-level nested UseCases)를 갖게 되었을 것입니다. 불리언(boolean) 플래그를 뒤집고, 아마도 수많은 매치 케이스(match cases)가 포함된 채로 말이죠.
그리고 여전히 그 거대한 100줄짜리 명령형 코드(imperative code)가 남아있었을 것입니다.
저는 우리의 문제가 리스너 자체의 중복이 아니라는 것을 깨달았습니다.
문제는 명명(naming)과 계층화(layering)였습니다.
그 "갓 클래스(God-class)\
뒤쪽에서 사람들이 "너무 과도한 설계(over-engineering)! 불필요한 복잡성을 추가하고 있어!"라고 소리치는 것이 들립니다.
AI가 했다면
만약 누군가 그 GitHub 이슈를 AI 에이전트에게 던졌다면, 그 에이전트는 올바른 무언가를 만들어냈을 것입니다. 어쩌면 처음 보기에는 "과도하게 복잡하지 않은" 것처럼 보일 수도 있습니다.
그것은 공유 로직을 GigaChadSyncUseCase로 추출하고, 리스너(Listeners)를 간소화하며, 검토를 통과시켰을 겁니다. DRY(Don't Repeat Yourself), 일관성 있고, 완료된 상태입니다.
작동합니다.
하지만 그것은 또한 틀렸을 것입니다. "논리적으로" 틀린 것이 아니라, "기능적으로" 틀린 것도 아닙니다. 오히려 "구조적으로" 틀렸거나, 혹은 "미래 대비(future-proofing)" 측면에서 잘못된 것일 겁니다.
우리는 단지 더 많은 코드, 즉 서로를 호출하는 더 많은 "서비스(Services)"와 "유즈케이스(UseCases)\
그리고 _"오, 하지만 우리는 아키텍처적 통찰력(architectural insight)이 필요 없어요. AI가 코드베이스를 이해하고 상관없이 코드를 생성할 수 있으니까요"_라고 말할 분들에게, 저는 오직 한 가지 질문으로만 답하겠습니다. "토큰(tokens)을 얼마나 쓰고 싶으신가요?"
저는 그러한 통찰력이 미래의 AI 에이전트(AI-agents)에게도 도움이 된다고 믿습니다. 컨텍스트(context)가 더 작고, 더 논리적이며, 더 선언적(declarative)이고 구조화되기 때문입니다.
직관에 어긋나는 것처럼 보일 수도 있지만, 더 나은 아키텍처적 통찰력은 당신의 코드베이스를 "caveman"의 코드 버전으로 만들어 줍니다.
차이점
결국 그 차이는 '감정'입니다.
개발자는 작업의 고통을 느낍니다.
에이전트는 그저 밀어붙일 뿐입니다. 6개의 파일을 건드리고, 티켓(ticket)을 닫습니다. 불평도 없고, 마찰도 없으며, 패턴 인식(pattern recognition)도 작동하지 않습니다.
당신이 원하는 만큼 '메모리(memory)'와 '기술(skills)'에 대해 이야기할 수 있겠지만, 에이전트는 세션 사이에 초기화됩니다.
에이전트는 우리가 가진 '고통-메모리-반응(pain-memory-response)' 루프를 가지고 있지 않습니다.
"이렇게까지 어렵지는 않아야 하는데."
적어도 이것이 저로 하여금 더 나은 코드를 작성하게(또는 제 에이전트들에게 그렇게 하는 법을 알려주게) 만드는 원동력입니다.
우리는 무엇을 해야 하는가?
명확히 해두자면, 제 요점은 "에이전트를 사용하지 마라"가 아닙니다. 왜냐하면 저도 항상 에이전트를 사용하니까요.
다만 저는 작업을 에이전트에게 던져놓고, 테스트와 리뷰를 통과하는 무언가를 뱉어낼 때까지 기다렸다가, 코드를 직접 조금 살펴보고 그냥 넘어가는 식의 작업은 하지 않습니다.
직접 해보세요. 의문을 제기하세요. 테스트하세요. 당신의 티켓 뒤에 무언가 숨겨져 있는 것은 아닌지 생각해보려 노력하세요.
항상 그렇다는 말은 아닙니다. 때로는 버그 수정(bugfix)이 그냥 버그 수정일 뿐이며, AI가 60초 안에 해결하도록 두어야 할 때도 있습니다.
하지만 때로는, 멈춰서 생각해야 합니다.
결국: 하루 단위로 보면, 저는 아마 다른 개발자들보다 조금 더 느리게 움직일지도 모릅니다.
하지만 장기적으로 복리로 쌓였을 때, 저는 다음 개발자가 인간이든 AI이든 상관없이 코드베이스를 더 유지보수하기 쉽고 저렴하게 만들고 있다고 확신합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기