Featured Post

20년 차 개발자가 직접 써본 Cline 자율 코딩, 실제 업무에서 겪은 삽질과 써먹을 만한 팁

Cline - 자율 코딩 관련 이미지

왜 갑자기 Cline을 써보게 됐냐면요

사실 이 글은 제가 요즘 개발하면서 살짝 충격받은 경험을 친구한테 얘기하듯 남겨보고 싶어서 쓰게 됐어요. 20년 넘게 개발 일을 하다 보면, 새로운 도구가 나와도 막 설레기보다는 먼저 의심부터 하게 되거든요. 뭐랄까, 예전에도 “이제 개발자가 필요 없어집니다” 같은 말은 꽤 많이 들었잖아요. 그런데 결국 현장에 가져와 보면 레거시 코드, 이상한 테이블 관계, 운영 중인 장애, 팀마다 다른 코딩 규칙 앞에서 조용히 힘을 잃는 경우가 많았고요.

저도 그랬어요. AI가 코딩을 대신해준다는 말을 들었을 때도 처음엔 별 감흥이 없었습니다. “그래, 간단한 Todo 앱 정도는 만들겠지. 그런데 우리 회사 서비스 코드 보면 정신 못 차릴걸?” 이런 마음이었죠. 그런데 얼마 전에 사이드 프로젝트로 작은 API 서버를 빠르게 만들어야 할 일이 생겼어요. 평소 같으면 익숙한 Django + DRF로 후다닥 만들었을 텐데, 요즘 주변에서 FastAPI 이야기가 자꾸 들리더라고요. 마침 배워볼 핑계도 필요했고요.

그래서 이번엔 조금 다르게 해봤습니다. VS Code에 Cline을 설치하고, Claude 3.5 Sonnet 모델을 붙여서 “어디 한번 네가 얼마나 하는지 보자” 하는 마음으로 시작했어요. 솔직히 기대 반, 의심 반이었는데요. 써보고 나니 생각이 꽤 바뀌었습니다. 이건 그냥 코드 자동 완성 수준이 아니더라고요. 프로젝트 구조를 만들고, 파일을 생성하고, 에러 로그를 읽고, 수정까지 시도하는 걸 보면서 “아, 이제 개발 방식이 진짜 조금씩 바뀌고 있구나” 싶었습니다.

처음부터 느낌이 좀 달랐던 Cline 자율 코딩

프로젝트 초기 세팅을 맡겨봤습니다

처음에는 아주 단순하게 시작했어요. 빈 폴더 하나 만들고 Cline에게 이렇게 말했습니다.

FastAPI 프로젝트를 위한 기본 폴더 구조를 만들어줘.
컨트롤러, 서비스, 레포지토리 레이어로 나누고,
SQLAlchemy 비동기 세팅도 포함해줘.

저는 사실 여기서 대충 app 폴더 만들고, main.py 하나 만들고, requirements.txt 정도 생성해줄 줄 알았어요. 그런데 Cline이 생각보다 훨씬 적극적으로 움직이더라고요. 폴더 구조를 만들고, 각 레이어별 파일을 생성하고, pyproject.toml까지 구성했습니다. 심지어 비동기 SQLAlchemy 세팅까지 어느 정도 잡아줬고요.

그때 좀 놀랐습니다. 제가 평소에 새 프로젝트 시작할 때 손으로 만들던 구조와 꽤 비슷했거든요. 대충 이런 느낌이었습니다.

my_fastapi_project/
├── app/
│   ├── api/
│   │   └── v1/
│   │       └── users.py
│   ├── core/
│   │   ├── config.py
│   │   └── middleware.py
│   ├── db/
│   │   ├── database.py
│   │   └── base.py
│   ├── models/
│   │   └── user.py
│   ├── repositories/
│   │   └── user_repository.py
│   ├── services/
│   │   └── user_service.py
│   └── main.py
├── tests/
├── pyproject.toml
└── README.md

물론 처음부터 완벽하진 않았어요. 이건 좀 중요합니다. Cline이 똑똑하긴 한데, 제 머릿속에만 있는 회사 스타일이나 개인적인 개발 습관까지 알아서 맞춰주진 못하거든요.

예를 들어 저는 API 서버 만들 때 요청 본문을 로깅하는 커스텀 미들웨어를 자주 넣습니다. 운영 중 장애가 났을 때 요청 데이터 흐름을 봐야 하는 경우가 많아서요. 그런데 Cline은 기본적으로 CORS랑 Gzip 정도만 넣어줬습니다. 틀린 건 아닌데, 제가 원하는 방향은 아니었죠.

항목 제가 원한 설정 Cline이 처음 제안한 설정 느낀 점
미들웨어 요청 본문 로깅 + CORS CORS + Gzip 내부 운영 습관은 따로 알려줘야 했습니다
DB 세션 관리 비동기 세션, 커밋과 롤백 자동 처리 기본 비동기 세션 구성 세션 정책은 조금 더 구체적으로 지시해야 했어요
API 응답 포맷 {status, data, message} 기본 JSON 응답 팀 규칙이 있다면 반드시 미리 알려줘야 합니다

여기서 제가 얻은 첫 번째 감각은 이거였어요. Cline 자율 코딩은 아무 말 없이 맡기면 평균적인 코드를 만들고, 규칙을 잘 알려주면 꽤 괜찮은 동료처럼 움직인다는 겁니다. AI라고 해서 제 마음을 읽지는 못해요. 이건 사람도 마찬가지잖아요. 주니어 개발자에게도 “우리 팀은 이렇게 해”라고 알려줘야 좋은 결과가 나오듯이, Cline도 기준을 줘야 합니다.

에러를 만났을 때 진짜 실력이 보이더라고요

제가 Cline을 쓰면서 가장 인상 깊었던 순간은 에러가 났을 때였습니다. 사실 개발자는 평소 코딩하는 시간보다 에러 로그 보면서 멍하니 커피 마시는 시간이 더 길 때도 있잖아요. 저만 그런 거 아니죠?

FastAPI API를 만들고 DB 연결 테스트를 하던 중에 이런 에러가 터졌습니다.

sqlalchemy.exc.TimeoutError: QueuePool limit of size 10 overflow 10 reached, connection timed out

이 에러를 보면 보통은 pool_size를 늘려야 하나, max_overflow를 조정해야 하나, 아니면 커넥션을 제대로 반환하지 않는 코드가 있나 싶어서 여기저기 뒤지게 됩니다. 저도 습관적으로 database.py부터 열어보려던 참이었어요.

그런데 Cline이 터미널 로그를 읽더니 이런 식으로 반응했습니다. “DB URL이 잘못되었거나, 연결 풀이 고갈되었을 가능성이 있습니다. 설정 파일을 확인해보겠습니다.” 그리고는 database.py를 열더니 pool_pre_ping=True 옵션을 추가하더라고요.

실제 변경은 이렇게 단순했습니다.

# 변경 전
engine = create_async_engine(
    DATABASE_URL,
    pool_size=10,
    max_overflow=10
)

# Cline이 수정한 후
engine = create_async_engine(
    DATABASE_URL,
    pool_size=10,
    max_overflow=10,
    pool_pre_ping=True
)

딱 한 줄이었어요. 그런데 이 한 줄이 꽤 의미 있었습니다. pool_pre_ping=True는 커넥션을 가져오기 전에 살아있는 연결인지 확인하는 옵션입니다. 죽어 있는 커넥션을 재사용하다가 생기는 애매한 문제를 줄이는 데 도움이 되죠. 제가 바로 떠올리지 못했던 부분이라 조금 뜨끔했습니다. “아, 나보다 낫네?”까지는 아니고요. 그래도 “오, 이 녀석 제법인데?” 정도는 됐습니다.

물론 이걸로 모든 커넥션 문제가 해결된다고 말하면 그건 또 과장입니다. 실제 운영 환경에서는 세션이 닫히는지, 트랜잭션 범위가 적절한지, API 호출 패턴이 어떤지 같이 봐야 해요. 하지만 적어도 이 상황에서는 Cline이 꽤 현실적인 수정안을 냈고, 저는 그 덕분에 시간을 아꼈습니다. 예전 같으면 로그 보고, 검색하고, 문서 보고, 테스트하고 하면서 30분은 썼을 텐데 10분 안쪽으로 정리됐거든요.

Cline을 제대로 쓰려면 규칙을 먼저 알려줘야 합니다

.clinerules 파일은 생각보다 훨씬 중요했어요

처음에는 매번 채팅창에 “응답 포맷은 이렇게 해줘”, “비동기 함수니까 await 빼먹지 마”, “에러는 try-except로 감싸줘” 이런 말을 계속 했습니다. 한두 번은 괜찮은데, 반복되니까 슬슬 귀찮아지더라고요. 사람이든 도구든 같은 말을 계속해야 하면 피곤합니다.

그러다가 프로젝트 루트에 .clinerules 파일을 두면 Cline이 그 규칙을 읽고 따라간다는 걸 알게 됐습니다. 그때부터 작업 방식이 훨씬 편해졌어요. 저는 이런 내용을 넣어뒀습니다.

모든 API 응답은 {status, data, message} 형식을 따른다.
비동기 함수에서는 await 누락 여부를 반드시 확인한다.
모든 DB 모델은 Base 모델을 상속하고 __tablename__을 명시한다.
주석은 영어로 작성하되, 복잡한 비즈니스 로직에만 제한적으로 사용한다.
에러 발생 가능성이 있는 외부 연동, DB 작업은 try-except로 감싸고 로그를 남긴다.
서비스 레이어에는 비즈니스 로직을 두고, 라우터에는 요청/응답 처리만 둔다.
레포지토리 레이어에서는 DB 접근 코드만 작성한다.

이걸 넣고 나니 확실히 달라졌습니다. 특히 비동기 함수에서 await를 빼먹는 문제가 줄었어요. 사실 FastAPI랑 async SQLAlchemy 조합을 쓰다 보면 이 부분에서 은근히 실수가 나옵니다. 로컬에서는 어찌어찌 넘어가는 것처럼 보이다가, 실제 요청이 몰리거나 테스트 코드에서 이상한 경고가 터지기도 하고요.

개인적으로는 .clinerules를 그냥 옵션 정도로 보면 안 된다고 생각합니다. Cline을 실무에 가까운 방식으로 쓰려면 거의 필수에 가깝습니다. 팀에서 쓴다면 더더욱 그렇고요. 사람에게 온보딩 문서가 필요하듯, Cline에게도 프로젝트 온보딩 문서가 필요합니다.

제가 쓰면서 정리한 Cline 지시 방식

Cline에게 일을 시킬 때도 말투가 중요하더라고요. 그냥 “회원가입 API 만들어줘”라고 하면 만들긴 만듭니다. 그런데 그 결과물이 제가 원하는 수준일지는 별개의 문제예요. 그래서 저는 요즘 이렇게 말합니다.

    • 무엇을 만들지만 말하지 않고, 왜 필요한지도 같이 설명합니다.
    • 변경 범위를 지정합니다. 예를 들면 “기존 인증 로직은 건드리지 말고” 같은 식으로요.
    • 파일 구조를 먼저 제안하게 한 뒤, 제가 확인하고 구현을 맡깁니다.
    • 한 번에 너무 큰 작업을 맡기지 않습니다. 큰 기능은 작은 단위로 나눕니다.
    • 수정 후에는 테스트 방법이나 확인 명령어도 같이 요청합니다.

예를 들어 이런 지시는 결과가 조금 애매했습니다.

주문 생성 API 만들어줘.

반면에 이렇게 말하면 훨씬 나았습니다.

주문 생성 API를 만들어줘.
이 API는 users, orders, order_items 테이블을 함께 수정해야 해.
중간에 하나라도 실패하면 전체가 롤백되어야 하고,
서비스 레이어에서 트랜잭션을 관리했으면 좋겠어.
기존 응답 포맷 {status, data, message}는 유지해줘.

이 차이가 꽤 큽니다. Cline에게는 “무엇”보다 “맥락”이 중요하더라고요. 그냥 기능 이름만 던지는 것보다, 왜 그렇게 해야 하는지 설명하면 훨씬 덜 엉뚱한 코드를 냅니다. 이건 사람과 일할 때도 똑같아요. “이거 해주세요”보다 “이런 이유 때문에 이렇게 해주세요”가 훨씬 좋은 결과를 만들잖아요.

물론 Cline이 늘 정답을 주는 건 아닙니다

가끔은 아주 자신 있게 틀립니다

여기서 너무 칭찬만 하면 꼭 광고 같으니까, 솔직한 얘기도 해야겠죠. Cline이 항상 잘하는 건 아닙니다. 가끔은 정말 자신감 넘치는 표정으로 틀린 코드를 만듭니다. 물론 표정은 없지만요. 이상하게 그런 느낌이 있어요.

한번은 Mock 데이터를 만들어달라고 했는데, 실제 API 응답 구조와 전혀 다른 형태로 만들어줬습니다. 저는 분명히 응답 포맷을 알려줬다고 생각했는데, 중간에 자기 방식대로 단순화해버린 거죠. 이런 식이었습니다.

# 제가 기대한 형태
{
    "status": "success",
    "data": {
        "user_id": 1,
        "email": "test@example.com"
    },
    "message": "OK"
}

# Cline이 만든 형태
{
    "id": 1,
    "name": "test"
}

이런 걸 보면 살짝 한숨이 나옵니다. 그래도 화낼 필요는 없어요. 그냥 에러 메시지나 기대한 구조를 다시 알려주면 됩니다. 저는 이렇게 말했습니다.

지금 Mock 응답 구조가 실제 API 응답 포맷과 달라.
우리 프로젝트는 항상 {status, data, message} 형식을 사용해.
이 기준에 맞춰 테스트 데이터와 테스트 코드를 다시 수정해줘.

그러면 대부분 잘 고칩니다. 이 과정이 마치 주니어 개발자 코드 리뷰하는 느낌이에요. “왜 이렇게 했어?”라고 묻고, 기준을 다시 알려주고, 수정하게 하는 흐름이죠. 다만 사람과 다른 점은 삐지지 않는다는 겁니다. 이건 꽤 큰 장점입니다.

리팩토링은 반드시 범위를 정해줘야 합니다

제가 Cline을 쓰면서 조금 조심하게 된 부분이 리팩토링입니다. Cline은 가끔 “더 좋은 구조”를 만들겠다는 마음으로 예상보다 넓은 범위를 건드립니다. 물론 의도는 좋습니다. 그런데 실무에서는 좋은 의도보다 안전한 변경이 더 중요할 때가 많거든요.

특히 운영 중인 코드라면 더 그렇습니다. 내가 고치라고 한 건 user_service.py의 작은 함수 하나인데, 갑자기 repository 구조를 바꾸고 import 경로를 정리하고 테스트 코드까지 손대면 부담스럽습니다. 그래서 저는 리팩토링을 요청할 때 이렇게 말합니다.

이번 작업에서는 user_service.py의 create_user 함수만 수정해줘.
함수 시그니처는 바꾸지 말고,
다른 파일은 꼭 필요한 경우에만 변경해.
변경이 필요하면 먼저 이유를 설명해줘.

이렇게 말해두면 훨씬 안정적입니다. AI 자율 코딩이라고 해서 모든 자율성을 다 주면 안 됩니다. 이건 제 주관이 좀 강한데요. 실무 개발에서 자율성은 항상 책임과 같이 가야 합니다. Cline은 책임을 지지 않아요. 책임은 결국 우리 개발자가 집니다. 그래서 범위 지정은 생각보다 중요합니다.

모델 선택도 은근히 체감 차이가 납니다

저는 주로 Claude 3.5 Sonnet을 붙여서 사용했습니다. 코드 구조를 이해하는 능력이나, 기존 파일을 읽고 수정하는 흐름이 꽤 안정적이었어요. 특히 여러 파일에 걸친 변경을 할 때 덜 산만했습니다.

다른 모델들도 몇 개 써봤는데, 어떤 모델은 설명은 아주 친절한데 코드가 장황했고, 어떤 모델은 빠르긴 한데 디테일을 자주 놓쳤습니다. 이건 취향 문제도 있지만, 프로젝트 성격에 따라 맞는 모델이 조금씩 다르겠더라고요.

작업 유형 제가 느낀 적합한 모델 성향 주의할 점
초기 프로젝트 구조 생성 구조 이해가 좋은 모델 폴더 구조와 레이어 규칙을 먼저 설명해야 합니다
CRUD 코드 반복 생성 속도가 빠르고 일관성이 좋은 모델 응답 포맷과 네이밍 규칙을 고정해야 합니다
디버깅 로그 해석과 추론이 좋은 모델 터미널 출력 전체를 보여주는 편이 좋습니다
리팩토링 맥락 유지가 좋은 모델 변경 범위를 아주 좁게 잡아야 합니다

제 기준으로는 아직까지 Claude 3.5 Sonnet 조합이 제일 편했습니다. 물론 이건 시간이 지나면 또 바뀔 수 있어요. AI 도구 쪽은 워낙 변화가 빠르니까요. 작년에 좋았던 조합이 올해는 평범해질 수도 있고, 이번 달에 애매했던 모델이 다음 달엔 확 좋아질 수도 있습니다. 개발자 입장에서는 귀찮지만, 또 재미있는 부분이기도 합니다.

제가 실제로 쓰는 Cline 작업 흐름

요즘 저는 Cline을 쓸 때 대충 이런 흐름으로 갑니다. 이 방식이 정답은 아니지만, 적어도 제가 삽질하면서 찾은 꽤 안전한 방식입니다.

    • 작업 전에 .clinerules를 먼저 정리합니다.
    • Cline에게 바로 구현시키지 않고, 먼저 작업 계획을 물어봅니다.
    • 계획을 보고 변경 범위가 너무 넓으면 줄입니다.
    • 구현 후에는 diff를 확인합니다.
    • 테스트 명령어를 실행하게 하거나, 제가 직접 실행합니다.
    • 에러가 나면 로그를 그대로 넘기고 다시 수정시킵니다.
    • 최종 커밋 전에는 반드시 제가 코드를 읽습니다.

여기서 제일 중요한 건 마지막입니다. 최종 커밋 전에는 반드시 사람이 읽어야 합니다. 이건 정말 강조하고 싶어요. Cline이 아무리 잘해도, 운영 장애가 나면 Cline이 새벽에 일어나서 대응해주진 않거든요. 슬프지만 현실입니다.

그래도 반복 작업에서는 확실히 도움이 됩니다. 예를 들어 모델 하나 만들고, 그에 맞는 repository, service, router, schema, test까지 이어지는 작업은 사람이 하면 은근히 피곤합니다. 이름만 조금씩 바꾸면서 비슷한 코드를 계속 쓰게 되니까요. 이런 건 Cline에게 맡기면 꽤 효율이 좋습니다.

대신 복잡한 비즈니스 로직은 아직 제가 주도권을 잡는 편입니다. 할인 정책, 포인트 적립, 정산, 권한 처리 같은 건 한 줄 잘못 짜면 나중에 돈 문제로 이어질 수 있거든요. 이런 부분은 Cline에게 초안을 받더라도 제가 꼼꼼히 봅니다. 아니, 사실 두 번 봅니다.

Cline 자율 코딩, 저는 이렇게 보고 있습니다

Cline 자율 코딩은 단순한 코드 생성 도구라기보다는, 옆자리에 앉아 있는 꽤 빠른 페어 프로그래머에 가깝습니다. 특히 초기 세팅, 반복적인 CRUD, 테스트 코드 초안, 에러 로그 기반 디버깅에서는 확실히 빛을 봤습니다. 제가 직접 써보니 “이 정도면 실무에서도 충분히 쓸 수 있겠다”는 생각이 들었어요.

그렇다고 개발자를 대체한다고 보진 않습니다. 적어도 지금 제 기준에서는요. 오히려 개발자가 더 개발자다운 일에 집중하게 해주는 도구에 가깝습니다. 아키텍처를 어떻게 잡을지, 장애가 났을 때 어디를 의심할지, 비즈니스 규칙을 코드로 어떻게 녹일지, 이런 판단은 여전히 사람이 해야 합니다.

초보 개발자라면 Cline을 쓰면서 다양한 코드 패턴을 빠르게 접할 수 있을 겁니다. 다만 나온 코드를 그냥 붙여넣고 끝내면 위험해요. 왜 이렇게 작성됐는지 꼭 따라가 봐야 합니다. 그래야 실력이 늡니다.

시니어 개발자라면 반복 작업을 줄이는 용도로 꽤 만족할 가능성이 큽니다. 저도 그랬고요. 특히 “이거 또 만들어야 해?” 싶은 코드들을 맡겨두면 손이 많이 편해집니다. 대신 규칙 파일과 변경 범위 지정은 꼭 챙기셔야 합니다.

프리랜서나 스타트업처럼 속도가 중요한 환경에서도 도움이 될 것 같습니다. 프로토타입을 빠르게 만들고, API 구조를 잡고, 테스트 코드 초안을 만드는 데 시간을 꽤 줄일 수 있거든요. 물론 빠르게 만든 만큼 리뷰도 빠르게, 하지만 꼼꼼하게 해야 합니다.

솔직히 지금은 Cline을 안 써볼 이유가 별로 없다고 느낍니다. 다만 한 가지는 분명해요. 자율 코딩이라고 해서 내가 생각을 멈춰도 된다는 뜻은 아닙니다. 좋은 도구는 손을 빠르게 해줄 뿐이지, 내 판단까지 대신해주진 않습니다. 저는 오히려 이 점이 마음에 들어요. 개발자의 역할이 사라지는 게 아니라, 조금 더 높은 곳으로 옮겨가는 느낌이랄까요.

그래서 이 글은 이런 분들이 읽으면 특히 좋겠습니다. Cline을 써볼까 말까 망설이는 개발자, AI 코딩 도구가 실무에 쓸 만한지 궁금한 시니어 개발자, 반복 작업에 지친 백엔드 개발자, 그리고 빠르게 프로토타입을 만들어야 하는 프리랜서나 스타트업 개발자요. 너무 겁먹을 필요도 없고, 너무 맹신할 필요도 없습니다. 딱 좋은 동료 하나 들인다는 느낌으로 시작해보면 꽤 재미있을 겁니다.

댓글