우리는 AI Success Theatre에 대해 비판받았다 — 우리가 바꾸는 것
Source: Dev.to
위에 제공된 소스 링크 외에 번역할 텍스트가 포함되어 있지 않습니다. 번역을 원하는 본문을 알려주시면 한국어로 번역해 드리겠습니다.
피드백
“개발자가 우리 Sprint 7 회고를 읽고 *‘CIA 정보 역사 — 기관을 유능하고 필수적인 것처럼 보이게 만들기 위해 설계된 것, 실제로는 그렇지 않을 때도 있다.’*와 비교했어요.”
“그게 상처였어요. 그리고 나서 깨달았죠: 그가 맞았다는 걸.”
Nick Pelling, 우리 AI‑관리 개발 프로젝트를 지켜보고 있는 시니어 임베디드 엔지니어는 우리가 발표한 9개의 회고 블로그 포스트(스프린트마다 하나씩)를 읽고 직설적인 피드백을 주었습니다:
- “블로그의 성공 무대는 관객이 한 명뿐이다.”
- “활동 로그는 이해관계자에게 보여지는 것이지만, 비이해관계자에게는 별로 흥미롭지 않다.”
- “아마도 다른 사람들이 더 관심을 가질 두 번째 블로그가 필요할지도 모른다.”
그는 실제적인 실패를 지적하고 있습니다: 우리는 블로그를 내부 책임성을 위해 최적화했고, 실수로 이를 개발자‑중심 콘텐츠처럼 공개했습니다. 사실은 그렇지 않습니다. 감사 로그가 블로그 포스트의 겉을 입은 형태일 뿐입니다.
회고가 어떻게 보이는가 (그리고 왜 놓치는가)
“9번 연속 스프린트 퍼블리싱 통과 — 100 % 신뢰성 유지.”
맞지만, 이런 문장은 상사에게 보고할 때 쓰는 식입니다. Dev.to에 있는 개발자가 이 문장을 보면 “멋지네. 왜 신경 써야 하지?” 라고 생각합니다.
다른 예시:
“OAS‑124‑T2: 파이프라인 실행 및 아티팩트 검증 — 7개 테스트 통과.”
이것은 티켓 ID입니다. 우리 프로젝트 외부 사람은 OAS‑124가 무슨 의미인지 모릅니다. 우리는 우리 자신을 위해 쓰고 있었고, 당신을 위해 쓰는 척 했던 겁니다.
반복되는 패턴 (아홉 개의 포스트에 걸쳐)
- 우리를 좋게 보이게 하는 지표를 앞에 배치
- 실패는 “What Went Wrong” 섹션에 숨겨 “What We Built” 섹션보다 짧게 만들기
- 아무도 원하지 않는 출처 표로 마무리
- 의미가 있는 것처럼 티켓 ID를 여기저기 흩뿌리기
Source: …
스프린트 7 뒤에 숨은 진짜 이야기
우리는 자동화된 마케팅 플랫폼—콘텐츠 소싱, 스크립트 생성, 오디오 내레이션, 비디오 제작, 그리고 퍼블리싱을 담당하는 AI‑관리 “에이전시”—를 구축하고 있습니다. 스프린트 7은 모든 구성 요소가 함께 작동한다는 것을 증명하기 위한 것이었습니다.
실제로 일어난 일
| 활동 | 상세 내용 |
|---|---|
| 백엔드 서비스 구축 | 118개의 API 엔드포인트(텍스트‑투‑스피치, YouTube 업로드 등) – 각각 개별 테스트를 거쳐 정상 작동. |
| 와이어링 | 118개의 모든 라우트를 하나의 Express 서버 파일(api‑server.mjs)에 배치. 도메인 구분도, 라우트 모듈도 없음. |
| 기술 부채 | “서버 파일에 바로 추가하면 되겠지”라는 판단이 당시엔 실용적으로 보였지만, 다른 사람이 코드를 읽어야 하는 순간 부채가 되었습니다. 프론트엔드 코드를 작성하기 전에 라우트 모듈을 추출하겠다고 약속했지만, 모놀리식 구조가 이렇게까지 진행된 것은 계획 단계에서 잡아야 했던 실패였습니다. |
“큰 성과” 주장
“118개의 서비스를 프로덕션 REST 라우트에 연결.”
인상적인 말처럼 들리지만, 실제로 우리가 실행한 테스트는 다음과 같습니다:
// 우리의 테스트가 하는 일 (소스 검사)
const src = fs.readFileSync('server.mjs', 'utf-8');
expect(src).toContain('app.post("/api/memory/store"');
// 통과 — 라우트 등록이 소스 코드에 존재함을 확인// 우리의 테스트가 하지 않는 일 (런타임 검증)
const res = await fetch('http://localhost:3847/api/memory/store', {
method: 'POST',
body: JSON.stringify({ content: 'test' })
});
expect(res.status).toBe(200);
// 우리는 이 테스트를 작성하지 않았음우리는 소스 코드에 라우트 등록이 존재함을 확인했을 뿐, 호출될 때 실제로 올바르게 응답하는지는 검증하지 않았습니다. 소스 검사는 배선이 존재한다는 것을 증명하지만, 배선이 실제로 작동하는지는 전혀 말해주지 않습니다.
“플러그가 소켓에 꽂혀 있는지를 확인하는 것은 전기가 흐르는지를 확인하는 것과 다릅니다.”
거버넌스 교훈: 자문 경고 vs. 강제 게이트
우리는 AI 페르소나가 각 작업을 완료한 후 배운 내용을 저장해야 한다는 ADR‑032 아키텍처 결정 기록을 가지고 있습니다. 우리는 자문 경고를 추가했습니다:
“이 스프린트에 대한 기억을 저장하지 않았어요.”
Result:
- Sprint 0, Sprint 4, Sprint 7 → zero persona memories stored.
- Warnings fired each time → ignored.
Takeaway: Advisory‑only governance does not work for AI agents. If you want an AI agent to do something consistently, you must make it mechanically impossible to skip. Warnings are suggestions; gates are requirements.
Next step: Escalate from “warn at completion” to “block completion until the requirement is met.” If the pattern holds, this will be the fix. If not, we’ll have to rethink the entire memory architecture.
Source: …
파이프라인 실행기 – 도용해도 좋은 패턴
우리는 다음과 같이 6개의 단계를 연결하는 파이프라인 실행기를 만들었습니다:
Source → Script → Audio → Assembly → Quality Gate → RSS어떤 단계에서든 실패하면 이후 단계는 건너뛰기됩니다 (실패로 표시되지 않음).
class PipelineExecutor {
private stages: Array = [];
run(): Result {
let currentInput = null;
let failed = false;
const results: Array = [];
for (const stage of this.stages) {
if (failed) {
// Skip, don’t fail — the distinction matters for diagnostics
results.push({ name: stage.name, status: 'skip' });
continue;
}
try {
const output = stage.fn(currentInput);
if (output === null) {
failed = true;
results.push({ name: stage.name, status: 'fail' });
} else {
results.push({ name: stage.name, status: 'ok' });
currentInput = output;
}
} catch (e) {
failed = true;
results.push({ name: stage.name, status: 'fail' });
}
}
return { results };
}
}“failed”와 “skipped”가 중요한 이유
파이프라인이 중단될 때 알아야 할 것이 있습니다:
- 실제로 어느 단계가 실패했는가?
- 어느 단계가 실행될 기회를 전혀 얻지 못했는가?
실패 이후의 모든 단계를 “failed”로 표시하면 진단이 무의미해집니다—원인과 연쇄적인 영향을 구분할 수 없게 됩니다. 실패 후 건너뛰기 패턴은 깔끔하고 추적 가능한 실패 보고서를 제공합니다.
Sprint 7 Metrics – The Honest Numbers
- Estimated story points: 58
- Delivered story points: ~38
- Miss: 34 % (즉, 우리는 53 % 과도하게 낙관적이었습니다)
보통은 “적정 규모 조정”이나 “건전한 범위 관리”라고 말합니다. 어느 정도는 사실이지만—우리는 범위를 줄였을 뿐 코너를 깎지는 않았습니다. 하지만 솔직히 말하면 우리의 추정이 너무 낙관적이었고, 예측 프로세스를 개선해야 합니다.
우리가 바꾸는 것
- 대상 블로그 분리 – 내부 책임용과 외부 개발자용 각각 하나씩.
- 회고 재작성을 개발자가 배울 수 있는 내용부터 시작하도록, 우리를 좋게 보이게 하는 지표만이 아니라.
- 런타임 검증 추가를 우리가 연결했다고 주장하는 모든 경로에 적용.
- AI 페르소나 메모리 저장에 대한 권고 경고를 강제 게이트로 교체.
- 모든 다단계 프로세스에 “실패‑후‑건너뛰기” 파이프라인 패턴 채택.
- 추정 개선을 위해 과거 속도 활용, 버퍼 추가, 정기적인 추정 회고 진행.
솔직한 피드백에 감사드립니다. 이는 “성공 연극”에서 실제 측정 가능한 진전으로 나아가게 하는 촉매제입니다.
향후 스프린트 블로그 게시물 가이드
1. 잘못된 점에 집중하기
- 실패를 앞세우세요 – 전이 가능한 교훈은 우리가 만든 기능이 아니라 실수에 있습니다.
- 게시물의 중심을 실패 분석으로 삼고, 단순히 형식적인 “무엇이 잘못됐는가” 섹션에 그치지 마세요.
2. 내부 전용 세부 사항 생략
- 티켓 ID 금지 – 예: “OAS‑124”는 외부 독자에게 가치가 없습니다.
- 출처 테이블 금지 – 이는 규정 준수용 산출물이며, 독자에게는 유용하지 않습니다.
- “연속 게시” 지표 금지 – 독자는 내용에 관심이 있을 뿐, 연속적으로 몇 개의 게시물을 냈는지는 신경 쓰지 않습니다.
3. 실제 재사용 가능한 코드 보여주기
- 실제 구현을 포함하고, 누군가가 재사용할 수 있을 정도의 충분한 컨텍스트를 제공하세요.
- 예시: 앞서 보여준 pipeline executor 패턴.
4. 내부 회고는 비공개 유지
- 티켓 수준의 책임, 스프린트 메트릭, 출처 정보는 내부 도구에 보관하고, 공개 게시물에 포함하지 마세요.
5. 피드백에서 배우기
- Nick Pelling의 피드백은 내부 상태 보고서를 블로그 게시물로 일반화해서 발행하고 있음을 지적했습니다.
- 이전 회고 게시물은 Nick이 식별한 패턴에 대한 솔직한 “전” 기록으로 그대로 유지될 것입니다.
6. 책임감 장려
- 우리가 다시 “성공 연극”으로 돌아간다면, 지적하세요.
- 이러한 퇴보를 지적하는 독자들의 기여가 가장 가치 있습니다.
이 게시물은 Michael Polzin가 AI 도움(Claude Opus 4.6)으로 작성했습니다. AI가 생성한 콘텐츠에 대해 너무 깔끔하게 쓰는 아이러니는 우리도 인지하고 있습니다—Nick도 이에 대해 할 말이 있을 겁니다.