AIArchitectureCI/CDBackend

에이전틱 AI 시대, 백엔드 개발자로서 달라진 것들

AI 에이전트가 코드 작성부터 테스트, 배포까지 자동화하는 시대에 백엔드 개발자의 역할이 어떻게 변하고 있는지, 실무 경험을 기반으로 회고합니다.

Srue2026년 4월 17일
에이전틱 AI 시대, 백엔드 개발자로서 달라진 것들

올해 초, 반복적으로 작성하던 CRUD API 보일러플레이트를 AI 에이전트에게 맡겨본 적이 있습니다. 엔티티 설계부터 Repository, Service, Controller, 심지어 통합 테스트 코드까지 한 번의 프롬프트로 뚝딱 나왔습니다. 처음에는 "이거면 나 없어도 되는 거 아닌가"라는 생각이 스쳤습니다.

그런데 막상 생성된 코드를 운영 환경에 올리려 하자 이야기가 달라졌습니다. 트랜잭션 경계가 어설프고, 예외 처리 전략이 프로젝트 컨벤션과 맞지 않았으며, 캐시 무효화 타이밍이 비즈니스 로직과 동떨어져 있었습니다. AI가 만든 코드는 '돌아가는 코드'였지, '운영할 수 있는 코드'는 아니었습니다.

이 경험을 계기로, AI 에이전트와 함께 일하는 방식에 대해 진지하게 고민하기 시작했습니다.

에이전틱 AI, 뭐가 달라졌나

에이전틱(Agentic) AI라는 말이 요즘 자주 들립니다. 기존의 AI 코딩 어시스턴트가 "이 함수 완성해 줘" 수준이었다면, 에이전틱 AI는 목표를 주면 스스로 계획을 세우고, 파일을 탐색하고, 코드를 작성하고, 테스트를 돌리고, 실패하면 수정까지 하는 자율적 에이전트(Autonomous Agent) 입니다.

실제로 제가 경험한 흐름은 이랬습니다.

  1. "주문 도메인에 쿠폰 적용 기능을 추가해 줘"라고 요청
  2. 에이전트가 기존 코드베이스를 탐색하여 OrderService, CouponEntity 구조 파악
  3. 서비스 로직 작성 + 단위 테스트 생성
  4. 테스트 실행 후 실패하면 스스로 원인 분석 및 수정
  5. 최종 커밋 메시지까지 작성

여기까지만 보면, 개발자가 할 일이 정말 없어 보입니다. 하지만 실무에서 부딪혀 보니 그렇게 단순하지 않았습니다.

AI가 잘하는 것, 못하는 것

몇 달간 에이전틱 AI와 협업하면서 패턴이 보이기 시작했습니다.

항목AI가 잘하는 영역사람이 여전히 필요한 영역
코드 작성CRUD, 보일러플레이트, 패턴 반복도메인 특화 비즈니스 로직 설계
테스트단위 테스트 케이스 생성통합 테스트 시나리오 설계, 경계값 판단
리팩토링네이밍 개선, 중복 제거아키텍처 레벨의 모듈 분리 판단
디버깅스택트레이스 기반 원인 추적운영 환경 특수 상황 (트래픽, 데이터 편향)
배포CI/CD 스크립트 작성배포 타이밍, 롤백 판단, 장애 대응

이전에 배포 전 체크리스트를 정리하면서 느꼈던 것과 비슷했습니다. 자동화할 수 있는 영역은 확실히 자동화해야 하지만, "이번 배포를 지금 해도 되는가"라는 판단은 컨텍스트를 이해하는 사람의 몫이었습니다.

결국 AI가 커버하지 못하는 영역은 **맥락(Context)**이 필요한 부분이었습니다. "왜 이 서비스는 Redis 캐시 TTL을 5분이 아니라 30초로 잡았는가", "왜 이 API는 동기 호출 대신 이벤트 기반으로 처리하는가" 같은 의사결정의 배경은 코드만 봐서는 알 수 없는 것들이었습니다.

달라진 일상: 코드 작성자에서 리뷰어로

가장 체감이 큰 변화는 하루 일과의 비중이었습니다.

Before: 코드를 직접 치는 시간이 80%

예전에는 하루의 대부분을 IDE에서 보냈습니다. 엔티티 만들고, DTO 변환 로직 짜고, 컨트롤러 매핑하고, 테스트 코드 작성하고. 이 과정 자체가 곧 '일'이었습니다.

After: 설계하고 검증하는 시간이 70%

지금은 많이 달라졌습니다. AI에게 작업을 지시하기 전에 어떤 구조로 만들어야 하는지 먼저 정리하는 시간이 훨씬 길어졌습니다. 그리고 AI가 만든 결과물을 우리 프로젝트의 컨벤션에 맞게 조정하고, 예외 케이스를 보완하는 리뷰 작업이 핵심이 됐습니다.

AI가 생성한 초기 코드
@Transactional
public OrderResponse applyDiscount(Long orderId, Long couponId) {
    Order order = orderRepository.findById(orderId)
            .orElseThrow(() -> new RuntimeException("주문을 찾을 수 없습니다"));
    Coupon coupon = couponRepository.findById(couponId)
            .orElseThrow(() -> new RuntimeException("쿠폰을 찾을 수 없습니다"));
    
    order.applyDiscount(coupon.getDiscountAmount());
    return OrderResponse.from(order);
}
리뷰 후 수정된 코드
@Transactional
public OrderResponse applyDiscount(Long orderId, Long couponId) {
    Order order = orderRepository.findById(orderId)
            .orElseThrow(() -> new EntityNotFoundException(ORDER_NOT_FOUND));
    Coupon coupon = couponRepository.findById(couponId)
            .orElseThrow(() -> new EntityNotFoundException(COUPON_NOT_FOUND));
 
    coupon.validateUsable(LocalDateTime.now());
    coupon.validateApplicable(order.getTotalAmount());
 
    order.applyDiscount(coupon.calculate(order.getTotalAmount()));
    coupon.markUsed();
 
    return OrderResponse.from(order);
}

차이가 보이시나요? AI는 "할인을 적용한다"라는 목표는 달성했지만, 쿠폰의 유효성 검증, 최소 주문금액 체크, 사용 처리 같은 비즈니스 규칙은 빠져 있었습니다. 이전에 예외 처리 전략에서 정리했던 커스텀 예외 체계 대신 RuntimeException을 그대로 던지고 있었고요.

이런 부분을 잡아내는 것이 지금 제가 하는 일의 핵심입니다.

프롬프트가 곧 설계서가 됐다

재미있는 변화 중 하나는, AI에게 지시하는 프롬프트 자체가 일종의 설계 문서 역할을 하게 됐다는 점입니다.

처음에는 이렇게 요청했습니다.

"쿠폰 적용 API 만들어 줘"

결과물이 엉성하길래 점점 프롬프트가 구체적으로 바뀌었습니다.

"OrderService에 쿠폰 적용 메서드를 추가해 줘. 쿠폰은 만료일과 최소 주문금액 조건이 있고, 한 번 사용하면 재사용 불가야. 할인 계산은 Coupon 엔티티 내부에서 처리하고, 예외는 프로젝트의 EntityNotFoundException을 사용해. 트랜잭션 안에서 쿠폰 사용 처리까지 같이 해 줘."

이 프롬프트를 보면, 사실상 기능 명세서나 다름없습니다. 결국 AI와 잘 협업하려면, 내가 원하는 것을 정확히 설명할 수 있어야 했습니다. 그리고 정확히 설명하려면 도메인을 깊이 이해하고 있어야 했습니다.

역설적이지만, AI 덕분에 설계 능력의 중요성이 오히려 더 커진 셈입니다.

CI/CD 파이프라인에서의 AI 활용

GitHub Actions로 배포 자동화를 구축할 때도 AI 에이전트의 도움을 받았습니다. 다만 여기서도 같은 패턴이 반복됐습니다.

AI는 워크플로우 YAML의 문법과 구조를 빠르게 잡아줬지만, 우리 프로젝트만의 특수한 요구사항은 제가 직접 설계해야 했습니다.

AI가 제안한 기본 구조
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build
        run: ./gradlew build
      - name: Deploy
        run: ./deploy.sh
실제 운영에 반영된 구조
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build
        run: ./gradlew build -x test
      - name: Integration Test
        run: ./gradlew integrationTest
      - name: Health Check (Pre-deploy)
        run: curl -f ${{ secrets.SERVER_URL }}/actuator/health
      - name: Deploy with Zero-downtime
        run: ./scripts/rolling-deploy.sh
      - name: Health Check (Post-deploy)
        run: ./scripts/health-check-with-retry.sh
      - name: Notify Slack
        if: failure()
        run: ./scripts/slack-notify.sh "Deploy Failed"

헬스체크, 무중단 배포, 실패 시 슬랙 알림 같은 운영 관점의 장치는 AI가 먼저 제안하지 않았습니다. 이런 것들은 직접 장애를 겪어보고 나서야 "이게 필요하구나"를 알게 되는 영역이기 때문입니다.

새로운 역할: AI + 사람의 협업 설계자

이 모든 경험을 종합하면서, 저는 백엔드 개발자의 역할이 단순히 "코드를 작성하는 사람"에서 "AI와 사람의 협업을 설계하는 사람" 으로 변하고 있다고 느꼈습니다.

구체적으로 제가 요즘 신경 쓰는 것들은 이렇습니다.

1. 컨벤션을 코드로 남기기

AI가 우리 프로젝트의 규칙을 따르게 하려면, 그 규칙이 명시적으로 존재해야 합니다. 예외 처리 방식, 응답 구조, 네이밍 규칙 같은 것들을 문서나 설정 파일로 남겨두면 AI가 참조할 수 있습니다.

.cursorrules 또는 CLAUDE.md 예시
## 예외 처리 규칙
- RuntimeException 직접 사용 금지
- 도메인별 커스텀 예외 사용 (EntityNotFoundException, BusinessException 등)
- 에러 메시지는 ErrorCode enum에서 관리
 
## 응답 구조
- 모든 API는 ApiResponse<T> 래핑
- 페이징은 PageResponse<T> 사용

이전에 멀티 모듈 아키텍처를 구성할 때 모듈 간 의존성 규칙을 명확히 정의했던 것처럼, AI와의 협업에서도 규칙의 명시화가 품질을 좌우했습니다.

2. 검증 자동화에 더 투자하기

AI가 코드를 많이 생성할수록, 그 코드를 검증하는 장치가 더 중요해졌습니다. Testcontainers 기반 통합 테스트를 구축해 둔 것이 이 시점에서 큰 힘이 됐습니다.

AI가 만든 코드든 사람이 만든 코드든, 통합 테스트를 통과해야 머지할 수 있다는 규칙 하나만으로도 상당한 안전망이 됩니다.

3. 의사결정의 근거를 기록하기

"왜 이렇게 했는가"를 ADR(Architecture Decision Record)이나 커밋 메시지에 남기는 습관이 생겼습니다. AI는 코드를 읽을 수 있지만, 그 코드가 왜 그런 형태인지는 기록이 없으면 알 수 없기 때문입니다.

불안함에서 균형으로

솔직히 말하면, 처음 AI 에이전트의 코드 생성 속도를 봤을 때 불안했습니다. "내가 하루 종일 짜던 코드를 30초 만에 만들어 내는데, 내 가치는 어디에 있는 거지?"라는 생각이 들었습니다.

하지만 몇 달간 실무에서 부딪히면서 생각이 바뀌었습니다. AI가 빠르게 만들어 낸 코드가 실제 운영 환경에서 문제없이 돌아가기까지는, 도메인 이해, 아키텍처 판단, 운영 경험이라는 사람의 역량이 반드시 필요했습니다.

비유하자면, AI는 엄청나게 빠른 주니어 개발자와 비슷합니다. 시키면 금방 해오는데, 뭘 시켜야 하는지, 결과물이 괜찮은지 판단하는 건 시니어의 역할입니다. 그리고 그 시니어의 판단력은 결국 직접 코드를 짜고, 장애를 겪고, 시스템을 운영해 본 경험에서 나옵니다.

마무리

에이전틱 AI 시대에 개발자의 역할이 사라진다고 생각하지 않습니다. 다만, 역할의 무게 중심이 확실히 이동하고 있다고 느낍니다.

코드를 타이핑하는 시간은 줄었지만, 무엇을 만들지 결정하는 시간은 오히려 늘었습니다. 보일러플레이트를 찍어내는 능력보다 도메인을 깊이 이해하고 시스템 전체를 조망하는 능력이 더 중요해졌습니다.

결국 제가 배운 건 이런 것이었습니다. AI와 잘 협업하려면, 역설적으로 기본기가 더 탄탄해야 한다는 것. 예외 처리를 어떻게 설계해야 하는지 모르면 AI가 만든 코드의 문제점도 못 잡습니다. 배포 파이프라인을 이해하지 못하면 AI가 생성한 워크플로우가 운영에 적합한지 판단할 수 없습니다.

처음에는 "AI가 다 해주니까 편하겠다"라고 생각했습니다. 결국 배운 건 "AI가 다 해줄수록, 내가 알아야 할 게 더 많아진다"는 것이었습니다.

단순 코더에서 AI와 사람의 협업을 설계하는 사람으로. 이 변화가 두렵기보다는, 오히려 개발이라는 일이 더 재미있어지는 방향이라고 느끼고 있습니다.