LLM 시대의 개발자 감각(Taste): 코드를 생성하는 것과 판단하는 것은 다르다
TL;DR
LLM 시대의 개발자 감각(Taste)은 “무엇을 만들지 결정하는 능력”으로, 코드 생성 자동화가 가속될수록 오히려 희소해지는 역량이다. AI가 코드를 작성하는 속도가 빨라질수록, 그 결과물을 평가하고 방향을 설정하는 판단력이 엔지니어의 핵심 차별점이 된다. 이 글은 그 감각이 무엇이며, 어떻게 체계화할 수 있는지를 다룬다.
배경: 생성 속도와 판단 속도의 비대칭
GitHub Copilot, Cursor, Claude Code 같은 도구들이 일반화되면서, 코드 생성의 단위 비용은 급격히 낮아졌다 [추정]. 함수 하나를 작성하는 데 걸리는 시간이 수십 분에서 수십 초로 줄었다 [추정].
그런데 이 속도 향상이 가져온 부작용이 있다. 생성 속도는 빨라졌지만, 판단 속도는 그대로다 [추정]. “이 코드가 우리 시스템에 적합한가?”, “이 추상화 수준이 팀의 맥락에 맞는가?”, “이 설계가 6개월 후에도 유지보수 가능한가?” 같은 질문에 답하는 능력은 LLM이 대신해주지 않는다.
카카오, 네이버, 토스처럼 대규모 트래픽과 복잡한 도메인 로직을 다루는 환경에서는 이 비대칭이 더 두드러진다. LLM이 생성한 코드가 단위 테스트를 통과하더라도, 그것이 결제 정합성이나 메시지 순서 보장 같은 도메인 제약을 만족하는지는 별개의 문제다.
핵심 메커니즘: Taste란 무엇인가
원문 저자 Rajnandan Barmecha는 Taste를 다음과 같이 정의한다.
“Taste is the ability to recognize what is good, what fits, and what should not exist.”
이를 개발 맥락에 적용하면 세 가지 판단 능력으로 분해할 수 있다.
Taste = f(Context, Constraints, Consequence)
| 구성 요소 | 질문 | 예시 |
|---|---|---|
| Context | 이 코드가 놓인 시스템 맥락은? | 모놀리스 vs 마이크로서비스 |
| Constraints | 어떤 제약이 존재하는가? | 레이턴시, 팀 역량, 기술 부채 |
| Consequence | 이 결정의 장기 결과는? | 확장성, 유지보수 비용 |
LLM은 이 세 가지 중 Context를 프롬프트로 주입받을 수는 있지만, 조직의 암묵적 제약과 장기 결과에 대한 감각은 학습 데이터에 존재하지 않는다.

위 흐름에서 C 노드(개발자 Taste)가 병목이자 핵심 가치 생성 지점이다. LLM 도구가 발전할수록 A→B 구간의 속도는 빨라지지만, C 노드의 품질은 엔지니어 개인의 역량에 종속된다.
Taste를 조직에서 체계화하는 방법: ADR
Taste는 개인의 직관에 머물면 조직에 전이되지 않는다. 이를 팀 수준의 자산으로 만드는 가장 실용적인 도구가 ADR(Architecture Decision Record)이다. ADR은 “왜 이 결정을 내렸는가”를 맥락·제약·결과 중심으로 기록하는 경량 문서다.
다음은 캐시 전략 결정을 기록한 ADR 템플릿 예시다.
# ADR-0023: 유저 조회 캐시 전략으로 Redlock 기반 분산 락 채택
## 상태
승인됨 (2025-01-15)
## 맥락 (Context)
유저 조회 API의 캐시 미스 시 DB 부하가 피크 트래픽에서 임계치를 초과함.
단순 TTL 캐시만으로는 Cache Stampede 문제를 해결하지 못함.
서비스는 3개 이상의 애플리케이션 서버와 Redis Cluster 환경에서 운영됨.
## 결정 (Decision)
Redlock 알고리즘(또는 Redis 공식 클라이언트의 분산 락 구현)을 사용하여
다중 서버 환경에서도 안전한 캐시 갱신을 보장한다.
단일 Redis 인스턴스의 SET NX는 사용하지 않는다.
## 제약 (Constraints)
- Redis Cluster 환경에서 단일 노드 SET NX는 race condition을 완전히 방지하지 못함 [추정]
- 락 획득 실패 시 stale 데이터 반환을 허용하는 수준의 정합성 요구사항 확인 필요
- 팀 내 Redlock 운영 경험 부재 → 초기 도입 비용 존재
## 결과 (Consequence)
- 긍정: 다중 서버 환경에서 Cache Stampede 방지 보장
- 부정: 락 획득 실패 시 fallback 로직 추가 필요, 운영 복잡도 증가
- 재검토 시점: Redis Cluster 노드 수 변경 시
이 템플릿의 핵심은 결정 자체가 아니라 결정의 이유와 트레이드오프를 기록한다는 점이다. 6개월 후 새로운 팀원이 LLM에게 “캐시 코드를 개선해줘”라고 요청했을 때, ADR이 없으면 LLM은 단순 SET NX 패턴을 다시 제안할 것이다. ADR이 있으면 그 결정의 맥락을 프롬프트에 포함시킬 수 있다.
코드로 보는 Taste의 차이
다음은 같은 요구사항(“유저 ID로 캐시에서 데이터를 조회하고, 없으면 DB에서 가져온다”)에 대해 LLM이 생성한 코드와, Taste가 적용된 코드를 비교한 예시다.
LLM 초안 (기능은 동작하지만 맥락이 없음)
def get_user(user_id: str) -> dict:
cached = redis_client.get(user_id)
if cached:
return json.loads(cached)
user = db.query(f"SELECT * FROM users WHERE id = '{user_id}'")
redis_client.set(user_id, json.dumps(user))
return user
문제점:
– SQL 인젝션 취약점
– 캐시 TTL 부재 → 메모리 누수 가능성
– 캐시 미스 시 DB 부하 집중(Cache Stampede) 미처리
– 반환 타입 불명확
Taste가 적용된 버전 (Redlock 기반 분산 락)
from typing import Optional
import json
from redis import Redis
from redlock import Redlock # pip install python-redlock
CACHE_TTL_SECONDS = 300
LOCK_TTL_MS = 5000 # 락 TTL (밀리초)
LOCK_RETRY_DELAY_MS = 100
# Redlock은 여러 독립 Redis 노드를 사용해 분산 환경에서 안전한 락을 보장한다.
# 단일 Redis 인스턴스의 SET NX는 네트워크 파티션이나 다중 앱 서버 환경에서
# race condition을 완전히 방지하지 못하므로 사용하지 않는다.
dlm = Redlock([
{"host": "redis-node-1", "port": 6379},
{"host": "redis-node-2", "port": 6379},
{"host": "redis-node-3", "port": 6379},
])
def get_user(user_id: str) -> Optional[dict]:
cache_key = f"user:{user_id}"
cached = redis_client.get(cache_key)
if cached:
return json.loads(cached)
# Cache Stampede 방지: Redlock으로 분산 환경에서 안전한 락 획득
lock = dlm.lock(f"lock:{cache_key}", LOCK_TTL_MS)
if not lock:
# 락 획득 실패 → 다른 프로세스가 DB 조회 중
# stale 캐시가 없으면 None 반환 (호출부에서 fallback 처리)
cached = redis_client.get(cache_key)
return json.loads(cached) if cached else None
try:
# 락 획득 후 캐시 재확인 (double-checked locking)
cached = redis_client.get(cache_key)
if cached:
return json.loads(cached)
user = db.query(
"SELECT id, name, email FROM users WHERE id = %s",
(user_id,) # 파라미터 바인딩으로 SQL 인젝션 방지
)
if user:
redis_client.setex(cache_key, CACHE_TTL_SECONDS, json.dumps(user))
return user
finally:
dlm.unlock(lock)
두 버전의 차이는 LLM의 능력 차이가 아니라, 리뷰어의 Taste 차이다. “이 코드가 단일 Redis 인스턴스 기준인가, 클러스터 기준인가”를 묻는 것 자체가 Taste다. LLM에게 “Redlock을 적용하고, 분산 환경에서의 race condition을 고려해서 다시 작성해줘”라고 지시할 수 있는 것도 Taste다.
한국 개발 문화에서의 Taste 충돌: 빠른 배포 압력과의 긴장
카카오, 네이버, 토스를 예시로 든 것은 단순한 규모 언급이 아니다. 한국 스타트업과 IT 기업의 개발 문화에는 Taste와 정면으로 충돌하는 구조적 압력이 존재한다.
대표적인 패턴이 “일단 붙이고 나중에 고친다” 식의 빠른 배포 문화다. 실제로 국내 여러 스타트업에서 반복적으로 나타나는 시나리오가 있다.
시리즈 A 단계의 커머스 스타트업 A사는 LLM 도구를 도입한 이후 기능 배포 속도가 2배로 빨라졌다. 그런데 6개월 후, 주문 상태 관리 로직이 서로 다른 마이크로서비스에 중복 구현되어 있었고, 각각의 상태 전이 규칙이 미묘하게 달랐다. LLM이 각 서비스마다 “그 서비스의 맥락에서 합리적인” 코드를 생성했지만, 전체 도메인 모델의 일관성을 판단하는 주체가 없었다. 결국 환불 처리 버그가 발생했고, 수습에 배포 속도 향상으로 절약한 시간보다 훨씬 많은 공수가 들었다.
이 사례에서 부재했던 것이 Taste다. 구체적으로는 “이 결정이 도메인 전체에서 일관성을 유지하는가”를 묻는 Consequence 판단이었다.
한국 개발 문화의 특수성은 여기서 더 두드러진다. 빠른 시장 검증을 요구하는 투자 사이클, 소수 인원이 대규모 트래픽을 감당해야 하는 팀 구조, 그리고 “동작하면 된다”는 암묵적 기준이 결합될 때, LLM은 기술 부채 생성 속도를 가속하는 도구가 될 수 있다. Taste 없이 생성 속도만 높이면, 부채의 단위 비용도 함께 낮아지기 때문이다.
한계: Taste는 측정하기 어렵다
Taste의 가장 큰 문제는 정량화가 어렵다는 점이다.
코드 커버리지, 응답 시간, 에러율은 측정 가능하다. 그러나 “이 설계가 팀의 인지 부하를 줄이는가”나 “이 추상화가 도메인 언어와 일치하는가”는 수치로 표현되지 않는다.
이는 몇 가지 조직적 문제를 낳는다.
- 채용 기준 모호성: LLM 도구 활용 능력은 측정 가능하지만, Taste는 코딩 테스트로 검증하기 어렵다.
- 성과 평가 왜곡: 빠르게 많은 코드를 병합하는 엔지니어가 높은 평가를 받는 구조에서, 신중하게 적은 코드를 작성하는 엔지니어의 가치는 저평가될 수 있다.
- 도제 구조의 약화: Taste는 코드 리뷰와 페어 프로그래밍 같은 직접적 상호작용을 통해 전이된다. 원격 근무와 LLM 의존도 증가로 이 채널이 약해지고 있다.
결론: AI 시대에 엔지니어가 훈련해야 할 것
LLM은 코드 생성 비용을 낮추었지만, 판단 비용은 낮추지 못했다. 오히려 생성 속도가 빨라질수록 판단의 빈도가 높아지고, 판단의 질이 시스템 품질을 결정하는 비중이 커진다.
LLM 시대의 개발자 감각을 키우기 위한 실천적 방향은 다음과 같다.
- LLM 결과물에 “왜 이렇게 생성했는가”를 역으로 질문하는 습관 — 생성된 코드의 전제를 파악하는 훈련
- 도메인 제약을 명문화 — 팀의 암묵적 판단 기준을 ADR로 기록하고, LLM 프롬프트의 컨텍스트로 활용
- 코드 리뷰를 Taste 훈련의 장으로 — 기능 동작 여부보다 맥락 적합성 중심의 리뷰 문화
코드를 생성하는 능력과 코드를 판단하는 능력은 다른 근육이다. 전자는 도구가 대신할 수 있지만, 후자는 여전히 엔지니어의 몫이다.
참고 자료
– 원문: Taste in the age of AI and LLMs — Rajnandan Barmecha
– Redlock 알고리즘: Distributed locks with Redis — Redis 공식 문서