
꿀팁 — 이것만 알면 시킬 수 있다
코드를 구조화했고(8강), 시스템을 구조화했다(9강). 남은 것은 데이터다. 데이터가 가장 위험하다. 코드가 틀리면 테스트가 잡고, 시스템이 틀리면 /health가 잡는다. 데이터는 틀려도 아무도 모른다. 3개월 뒤 분기 리포트에서 발견한다.
에이전트에게: “JSONB 말고 명시적인 컬럼과 제약조건으로 스키마를 만들어. amount는 0보다 커야 하고, status는 정해진 값만 허용해.”
JSONB에 아무거나 넣으면 6개월 뒤 100가지 형식의 데이터가 뒤섞인다. 명시적 컬럼과 제약조건이 데이터의 법이다. 제약을 위반하면 DB가 즉시 거부한다.
에이전트에게: “이 엑셀을 DB에 넣어. DDL의 제약조건을 지켜야 해. 제약 위반하는 행은 별도 파일로 빼서 보고해.”
에이전트는 변환을 실행하고, DB의 제약조건이 검증한다. 거부된 행은 이유와 함께 보고된다. 당신은 거부된 데이터만 확인하면 된다.
에이전트에게: “DDL을 수정하고 yongol validate 통과시켜. 마이그레이션 파일 생성하고, 실패하면 롤백해.”
스키마가 바뀔 때도 래칫이 작동한다. 통과하면 다음 단계, 실패하면 되돌린다.
DB를 모르는 당신이 할 일은 “무엇을 저장할 것인가"를 결정하는 것뿐이다. “전화번호는 010으로 시작해야 해”, “이메일은 유니크해야 해” — 이 결정을 자연어로 말하면 에이전트가 DDL로 옮긴다.
찍먹 체험
DB 없이 체험할 수 있다. Claude Code에서:
“아래 CSV 데이터를 만들어: 고객 10명의 이름, 이메일, 전화번호, 가입일. 단, 일부러 문제를 섞어: 이메일 형식이 틀린 것 2개, 전화번호가 빈 것 1개, 가입일이 미래인 것 1개.”
CSV가 생기면:
“이 CSV에서 문제 있는 행을 찾아.”
AI가 몇 개를 찾는지 보라. 대부분 전부 찾지 못한다 — “괜찮아 보입니다"로 넘어가는 행이 있다.
이제:
“이 CSV의 스키마를 먼저 정의해. 이메일은 @ 포함 필수, 전화번호는 NOT NULL, 가입일은 오늘 이전. 그 스키마로 다시 검증해.”
스키마를 먼저 선언하면 AI가 기계적으로 전부 잡는다. 의견을 물으면 놓치고, 규칙을 주면 잡는다 — 7강에서 배운 원리가 데이터에도 동일하게 적용된다.
왜 이렇게 시켜야 하는가
도입: 코드보다 데이터가 먼저 부패한다
코드를 구조화했다(8강). 시스템을 구조화했다(9강). 남은 것은 데이터다.
그런데 데이터는 코드나 시스템과 근본적으로 다르다.
코드가 틀리면 테스트가 잡는다. go test를 돌리면 1초 안에 “여기 깨졌다"라고 나온다. 시스템이 틀리면 모니터링이 잡는다. /health가 500을 반환하면 즉시 알람이 울린다.
데이터는 틀려도 아무도 모른다.
고객 전화번호가 010으로 시작해야 하는데 누군가 02로 시작하는 번호를 넣었다. 주문 금액이 음수다. 배송 상태가 “배송중"인데 배송일이 null이다. 이런 오류는 테스트가 잡지 못한다. 모니터링도 잡지 못한다. 3개월 뒤 분기 리포트에서 “왜 매출이 마이너스지?” 할 때 발견한다.
바이브 코딩으로 앱을 만든다고 해보자. “주문 관리 앱 만들어"라고 시키면 코드는 빠르게 나온다. 유저가 데이터를 입력한다. 에이전트가 기능을 추가하면서 데이터 형식이 바뀐다. 마이그레이션이 제대로 안 되어서 옛 데이터와 새 데이터가 뒤섞인다. 코드는 멀쩡한데 데이터가 부패해 있다.
코드의 드리프트는 눈에 보인다. 데이터의 드리프트는 보이지 않는다.
이것이 데이터가 코드보다 위험한 이유다.
데이터 부패의 세 가지 유형
바이브 코딩에서 흔히 발생하는 데이터 부패를 분류하면 세 가지다.
1. 스키마 부재 — 계약 없는 거래
에이전트에게 “주문 테이블 만들어"라고만 시키면 이렇게 된다:
-- 이렇게 만들면
CREATE TABLE orders (
id SERIAL,
data JSONB -- 여기에 뭐든 들어간다
);
이 세 줄이 6개월 뒤 100가지 형식의 데이터가 뒤섞이는 원흉이다.
JSONB 컬럼에 뭐든 넣을 수 있다. 처음에는 편리하다. 6개월 뒤에는 100가지 다른 형식의 데이터가 섞여 있다. 어떤 주문에는 amount가 있고 어떤 주문에는 price가 있다. 어떤 것은 숫자고 어떤 것은 문자열이다. 에이전트가 이 데이터를 다루려면 100가지 형식을 전부 추측해야 한다.
2. 마이그레이션 실패 — 과거와 현재의 충돌
에이전트에게 “유저 테이블에 이메일 필드 추가해"라고 시킨다. 에이전트가 DDL을 수정하고 마이그레이션을 실행한다. 새 유저는 이메일이 있다. 기존 10만 명의 유저는 이메일이 null이다. 코드는 이메일이 반드시 있다고 가정한다. 기존 유저가 로그인하면 500 에러.
3. 비즈니스 규칙 위반 — 허용되면 안 되는 데이터
“할인율은 0~50% 사이여야 한다.” 이 규칙이 코드에만 있으면 에이전트가 리팩토링하면서 사라질 수 있다. DB에 CHECK (discount >= 0 AND discount <= 50) 제약이 없으면 200% 할인이 들어가도 아무도 모른다. 3개월 뒤 정산할 때 발견한다.
Agent Operable Data의 4가지 조건
에이전트가 데이터를 안전하게 다루려면 네 가지 조건이 필요하다.
조건 1. 스키마가 선언되어 있다 — DDL이 데이터의 계약이다
아래는 데이터베이스 설계도(DDL)다. 프로그래밍 언어처럼 보이지만, 각 줄이 규칙 하나다. 읽지 못해도 된다. 바로 아래에서 한 줄씩 풀어 설명한다.
CREATE TABLE orders (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
customer_id BIGINT NOT NULL REFERENCES customers(id),
amount DECIMAL(12,2) NOT NULL CHECK (amount > 0),
status TEXT NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending', 'confirmed', 'shipped', 'delivered', 'cancelled')),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
shipped_at TIMESTAMPTZ,
CONSTRAINT shipped_requires_date
CHECK (status != 'shipped' OR shipped_at IS NOT NULL)
);
이 DDL을 읽어보자. 에이전트가 아니어도 읽을 수 있다.
amount는 0보다 커야 한다 — 음수 주문은 불가능status는 5가지 중 하나 — “processing” 같은 임의 값은 거부shipped_at은 status가 ‘shipped’일 때 반드시 있어야 한다 — “배송중인데 배송일 없음” 방지customer_id는 customers 테이블에 존재해야 한다 — 유령 고객 방지
DDL이 데이터의 계약이다. 타입, 제약, 관계가 명시적이다. 에이전트가 해석을 추측할 필요가 없다. 규칙이 DB에 선언되어 있으니까.
JSONB에 뭐든 넣는 것과 비교해보자:
| JSONB (스키마 없음) | DDL (스키마 있음) | |
|---|---|---|
| 유효성 검증 | 없음 — 뭐든 들어감 | DB가 자동 검증 |
| 에이전트 이해 | 추측해야 함 | 선언을 읽으면 됨 |
| 데이터 품질 | 시간이 지날수록 부패 | 제약이 품질을 강제 |
| 마이그레이션 | 무엇을 바꿔야 하는지 모름 | diff가 명확 |
스키마가 있으면 에이전트는 DDL을 읽고 데이터 구조를 완벽하게 이해한다. 스키마가 없으면 에이전트는 데이터 샘플을 읽고 구조를 추측한다. 추측은 틀린다.
조건 2. 변환이 검증 가능하다
데이터는 변환된다. CSV에서 DB로. 한 테이블에서 다른 테이블로. 원시 데이터에서 리포트로.
변환 규칙이 선언적이고, 결과를 기계적으로 확인할 수 있어야 한다.
# 검증 불가능한 변환
에이전트에게: "이 엑셀을 DB에 넣어"
→ 에이전트가 알아서 컬럼을 매핑함
→ 10만 행 중 3,000행이 잘못 매핑됨
→ 아무도 모름
# 검증 가능한 변환
에이전트에게: "이 엑셀을 DB에 넣어.
매핑 규칙은 transform.yaml 참조.
넣은 후 row count 비교하고,
amount 합계가 원본과 일치하는지 확인해."
변환 규칙을 선언 파일에 적고, 변환 전후의 불변식을 검증한다. 이것이 검증 가능한 변환이다.
yongol의 DDL → sqlc 체이닝이 이 원리의 예시다. DDL에 스키마를 선언하면, sqlc가 타입-안전한 Go 코드를 생성한다. DDL과 sqlc 사이에 드리프트가 발생하면 yongol validate가 잡는다. 스키마에서 코드까지 단절 없이 검증된다.
조건 3. 출처와 시점이 추적된다
“이 데이터가 언제, 어디서, 왜 생성되었는가?”
이 질문에 기계가 답할 수 있어야 한다.
CREATE TABLE orders (
...
source TEXT NOT NULL, -- 'web', 'api', 'import', 'migration'
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by BIGINT REFERENCES members(id),
updated_at TIMESTAMPTZ,
updated_by BIGINT REFERENCES members(id)
);
출처(source), 시점(created_at, updated_at), 행위자(created_by, updated_by)가 DB에 기록된다. 에이전트가 “이 주문은 왜 음수인가?“를 추적할 때:
SELECT source, created_at, created_by FROM orders WHERE amount < 0;
-- source: 'import', created_at: 2026-02-15, created_by: NULL
“2월 15일에 import로 들어온 데이터에서 음수가 발생했고, 행위자가 기록되지 않았다.” 이 정보가 있으면 원인을 추적할 수 있다. 없으면 미궁이다.
whyso가 코드의 “왜"를 추적하듯, 데이터의 “왜"도 추적해야 한다. 코드에는 whyso가 있다. 데이터에는 출처·시점 컬럼이 그 역할을 한다.
조건 4. 데이터 변경도 래칫이 적용된다
6강에서 배운 Ratchet Pattern이 코드에만 적용되는 것이 아니다. 데이터에도 적용된다.
마이그레이션 래칫:
스키마 변경 요청
→ DDL 수정
→ yongol validate (교차 검증 통과)
→ 마이그레이션 파일 자동 생성 (up + down)
→ staging DB에 적용
→ 기존 데이터 정합성 검증
→ 통과 → production 적용 (승인 게이트)
→ 실패 → down 파일로 롤백
yongol이 이미 이것을 구현하고 있다. yongol generate는 DDL 변경을 감지하여 마이그레이션 파일을 자동 생성한다. up 파일과 down 파일이 쌍으로 나온다. 되돌릴 수 없는 마이그레이션은 없다.
specs/db/
└── users.sql # SSOT — 여기서 편집
artifacts/db/
├── .latest_schema.sql # 베이스라인 스냅샷
└── migrations/
├── 0001_initial.up.sql
├── 0001_initial.down.sql
├── 0002_add_users_email.up.sql
└── 0002_add_users_email.down.sql
모호한 변경(컬럼 이름 변경, 타입 캐스팅, NOT NULL 백필)은 DDL 주석 힌트(-- @rename, -- @cast, -- @backfill)로 에이전트에게 의도를 명시한다.
래칫이 보장하는 것: 마이그레이션이 성공하면 다음 단계로 진행한다. 실패하면 이전 상태로 되돌린다. 중간에 멈추지 않는다. 코드의 래칫과 동일한 원리다.
스키마는 내가 세우는 법이다
여기서 이 과정 전체를 관통하는 철학이 등장한다.
5강에서 우리는 “제약은 계약이다"를 배웠다. 법치주의의 세 조건 — 검증 가능하고, 위반이 정의되어 있고, 강제할 수 있다 — 이 코드에도 동일하게 적용된다는 것을.
데이터에서는 이 원리가 더 직접적으로 나타난다.
데이터베이스에는 스키마가 있다.
스키마는 무엇이 유효한 데이터이고 무엇이 아닌지를 **정의(定義)**한다. NOT NULL, FOREIGN KEY, CHECK — 이 제약을 통과해야 데이터가 저장된다. 누가 데이터를 넣는지는 상관없다. 인간이 넣든, 프로그램이 넣든, AI가 넣든 — 스키마를 만족하면 들어가고, 아니면 거부된다. 1970년부터 작동한 패턴이다.
스키마는 법이다. 내가 세우는 법이다.
법치주의의 원리를 다시 대입해보자:
| 법치주의 | 데이터 스키마 |
|---|---|
| 검증 가능하다 | CHECK (amount > 0) — DB가 자동 검증 |
| 위반이 정의되어 있다 | NOT NULL 위반, FOREIGN KEY 위반 — 이산적 |
| 강제할 수 있다 | 위반하면 INSERT가 거부된다 |
이것은 필자의 세계관과 연결된다:
법은 正義(justice)가 아니라 定義(definition)다.
법이 정의(正義)를 보장하지는 않는다. 스키마도 데이터의 “진실"을 보장하지는 않는다. 하지만 법은 정의(定義)를 보장한다. 스키마도 유효성을 보장한다.
이 최소한의 보장 — 사전에 알 수 있고, 기계적으로 검증 가능하고, 위반이 거부된다는 보장 — 이 인류가 수천 년에 걸쳐 피로 쟁취한 것이고, 데이터베이스가 50년에 걸쳐 증명한 것이다.
스키마 없는 데이터는 법 없는 사회다. 누구든 아무 데이터나 넣을 수 있다. 틀려도 모른다. 3개월 뒤에 발견한다.
스키마가 있는 데이터는 법치 사회다. 규칙을 어기면 즉시 거부된다. 이유가 명시된다. 수정하고 다시 시도할 수 있다.
비정형 데이터를 정형으로
현실의 데이터는 대부분 비정형이다.
- 엑셀 파일 — 시트마다 형식이 다르다
- 통화 녹음 — 음성 파일
- 회의록 — 자유 형식 텍스트
- PDF 문서 — 반정형
- 이메일 — 자연어
에이전트가 이 데이터를 다루려면 정형화가 선행되어야 한다.
비정형 데이터 → 스키마 결정 → 변환 → DB
엑셀 → DDL 선언 → import → PostgreSQL
통화 녹음 → STT → 구조화 → 요약 DB
회의록 → 파싱 → 액션 아이템 추출 → 태스크 DB
PDF → OCR + 파싱 → 필드 추출 → 문서 DB
핵심을 주목하라: 사람이 스키마(구조)를 결정하고, 에이전트가 변환을 실행한다.
5강에서 배운 “결정과 구현의 분리"가 여기서도 동일하게 적용된다.
- 결정 (사람): “고객 정보에는 이름, 전화번호, 이메일, 가입일이 있어야 한다. 전화번호는 01로 시작해야 한다.”
- 구현 (에이전트): 엑셀을 읽고, 컬럼을 매핑하고, 제약에 맞는 데이터를 DB에 넣는다.
에이전트는 변환을 실행하고, DB의 제약조건이 검증한다. 제약 위반 데이터는 거부되고 이유가 보고된다. 사람은 거부된 데이터를 확인하고 결정한다: 수정해서 다시 넣을 것인가, 버릴 것인가.
데이터 검증 패턴: 3단 방어선
데이터 검증은 하나의 레이어가 아니라 세 단계의 방어선으로 구성된다.
1차 방어선 — DB 제약 (가장 강력)
NOT NULL -- 빈 값 방지
UNIQUE -- 중복 방지
CHECK (amount > 0) -- 범위 제한
FOREIGN KEY -- 참조 무결성
DEFAULT -- 기본값 보장
DB 제약은 우회 불가능하다. 어떤 코드를 짜든, 어떤 에이전트를 쓰든, 제약을 위반하는 데이터는 들어가지 않는다. 이것이 1차 방어선인 이유다. 가장 중요한 규칙은 반드시 DB 제약으로 선언해야 한다.
2차 방어선 — 비즈니스 규칙 (Rego)
DB 제약으로 표현할 수 없는 규칙이 있다. “할인율이 30%를 넘으면 매니저 승인이 필요하다”, “같은 고객에게 하루 3회 이상 주문은 의심 거래다”. 이런 규칙은 Rego로 선언한다.
이것도 읽을 줄 몰라도 된다. 규칙을 자연어로 말하면 에이전트가 Rego로 옮긴다:
# 주문 검증 규칙
deny[msg] {
input.order.discount > 30
not input.approver.role == "manager"
msg := "30% 초과 할인은 매니저 승인 필요"
}
warn[msg] {
count(input.customer.orders_today) >= 3
msg := "동일 고객 하루 3회 이상 주문 — 의심 거래 확인 필요"
}
자연어로 풀면:
- “할인율 30% 초과인데 매니저가 승인 안 했으면 거부” = 첫 번째 규칙
- “같은 고객이 오늘 3번 이상 주문하면 경고” = 두 번째 규칙
Rego 규칙은 yongol의 SSOT 중 하나다. 4강에서 배운 교차 검증이 여기서도 작동한다: SSaC에서 @auth를 선언했으면 Rego에 해당 규칙이 있어야 한다. 없으면 yongol validate가 잡는다.
3차 방어선 — 마이그레이션 래칫
스키마가 바뀔 때 기존 데이터가 새 스키마와 호환되는지 검증한다.
1. DDL 수정 (SSOT)
2. yongol validate → 교차 검증 통과
3. 마이그레이션 파일 생성 (up + down)
4. staging DB에 적용
5. 기존 데이터 검증:
- NULL 값이 NOT NULL 컬럼에 있으면? → 백필 후 적용
- 참조 무결성이 깨지면? → 고아 데이터 처리 후 적용
6. 통과 → production 적용 (승인 게이트)
세 방어선의 역할 분담:
| 방어선 | 담당 | 위반 시 |
|---|---|---|
| 1차: DB 제약 | 데이터 무결성 | INSERT/UPDATE 거부 |
| 2차: Rego 규칙 | 비즈니스 로직 | 경고 또는 차단 |
| 3차: 마이그레이션 래칫 | 스키마 진화 | 롤백 또는 백필 |
같은 패턴, 다른 도메인
8강, 9강, 10강을 가로지르는 공통 패턴이 보이는가?
| 8강: 코드 | 9강: 시스템 | 10강: 데이터 | |
|---|---|---|---|
| 읽을 수 있는가 | filefunc (1파일 1개념) | /health (구조화 JSON) | DDL (선언적 스키마) |
| 검증할 수 있는가 | go test + tsma | CI/CD + 헬스체크 | DB 제약 + Rego |
| 되돌릴 수 있는가 | git revert | 이전 이미지 롤백 | migration down |
| 진행이 영속하는가 | session.json (tsma) | Terraform state | migration 히스토리 |
| 결정과 구현이 분리되는가 | SSOT → 코드 생성 | 선언적 설정 → 실행 | 스키마 → 데이터 |
전부 같은 구조다:
선언하고, 검증하고, 잠그고, 영속한다.
코드에서 작동하는 원리가 시스템에서도, 데이터에서도 동일하게 작동한다. 새로운 발명이 아니다. 같은 원리를 새로운 도메인에 적용하는 것이다.
5강에서 배운 “제약은 계약이다"의 원리가 세 도메인 모두에 관통한다:
- 코드의 계약: filefunc 22개 룰, yongol 287개 교차 검증 규칙
- 시스템의 계약: Docker Compose, Terraform, CI/CD 파이프라인
- 데이터의 계약: DDL 제약, Rego 규칙, 마이그레이션 래칫
합리적 제약이 검증 가능하고, 위반이 정의되어 있고, 강제할 수 있으면 — 어떤 도메인이든 수렴한다.
DDL → sqlc → 코드: 단절 없는 체이닝
yongol에서 데이터의 체이닝이 어떻게 작동하는지 구체적으로 보자.
이 코드들도 읽을 줄 몰라도 된다. DDL에서 시작해서 코드까지 자동으로 이어진다는 흐름만 이해하면 충분하다.
1. DDL에 스키마를 선언한다
CREATE TABLE orders (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
customer_id BIGINT NOT NULL REFERENCES customers(id),
amount DECIMAL(12,2) NOT NULL CHECK (amount > 0),
status TEXT NOT NULL CHECK (status IN ('pending','confirmed','shipped'))
);
2. sqlc에 쿼리를 선언한다
-- name: GetOrder :one
SELECT * FROM orders WHERE id = $1;
-- name: ListOrdersByCustomer :many
SELECT * FROM orders WHERE customer_id = $1 ORDER BY created_at DESC;
3. yongol validate가 교차 검증한다
- DDL의 컬럼과 sqlc의 쿼리 파라미터가 일치하는가?
- OpenAPI의 응답 필드와 DDL의 컬럼이 일치하는가?
- SSaC에서 @get으로 참조하는 쿼리가 sqlc에 존재하는가?
4. yongol generate가 타입-안전한 Go 코드를 생성한다
- sqlc → Go struct + query 함수
- 컴파일 타임에 타입 불일치를 잡는다
스키마(DDL)에서 시작해서 코드 생성까지, 중간에 사람의 해석이 끼어들 틈이 없다. DDL이 변하면 sqlc가 변하고, sqlc가 변하면 생성 코드가 변하고, 코드가 변하면 테스트가 잡는다.
이것이 데이터 주도 개발에서 드리프트가 발생하지 않는 구조다.
바이브 코더의 데이터 실천
“나는 DB를 모르는데 어떻게 하나?”
모르면 된다. 에이전트가 DDL을 작성한다. 당신이 할 일은 무엇을 저장할 것인가를 결정하는 것이다.
에이전트에게: "고객 관리 테이블을 만들어.
- 이름, 전화번호, 이메일, 가입일이 필요해
- 전화번호는 010으로 시작해야 해
- 이메일은 유니크해야 해
- 가입일은 자동으로 넣어줘
DDL로 만들고, 제약조건도 넣어."
에이전트가 DDL을 작성한다. yongol validate가 다른 SSOT와 교차 검증한다. 통과하면 마이그레이션이 생성된다. 당신은 DDL을 읽지 못해도, 결정(“전화번호는 010으로 시작해야 해”)은 할 수 있다.
결정은 자연어로 한다. 결정의 실현은 DDL로 한다. DDL의 검증은 기계가 한다.
진실은 빛의 속도로 사라진다
여기서 이 과정의 마지막 철학을 하나 더 꺼낸다.
물리학은 냉혹한 사실을 말해준다. 사건이 일어나는 순간, 그 진실은 빛의 속도로 사라진다. 1초 전의 달은 1.3초 전의 달이다. 100억 광년 거리의 은하는 100억 년 전의 모습이다.
진실은 물리적으로 사라진다. 남는 것은 진실의 파편인 주장뿐이다.
“나는 이것을 보았다.” “이 측정값은 이러했다.” “이 출처는 이렇게 말했다.” — 전부 주장이다. 출처가 있고, 시점이 있고, 신뢰도가 있는 주장.
데이터도 마찬가지다. DB에 있는 “주문 금액 50,000원"은 진실이 아니다. 주장이다. 누군가가 어느 시점에 어떤 경로로 넣은 주장이다. 그래서 출처와 시점이 중요하다. 출처 없는 데이터는 근거 없는 주장이다. 시점 없는 데이터는 날짜 없는 신문이다.
스키마가 하는 일은 주장에 구조를 부여하는 것이다. “이 주장은 이런 형태여야 하고, 이런 제약을 만족해야 하고, 이 출처에서 왔어야 한다.” 이 구조가 데이터의 법이다.
출처 없는 것은 내 데이터가 아니다. 시점 없는 것은 내 기록이 아니다. 스키마 없는 것은 내 시스템의 데이터가 아니다.
실습 (DB)
준비물: 9강에서 Docker로 PostgreSQL을 띄웠다면 그대로 사용. 아직이라면 에이전트에게: “PostgreSQL을 Docker로 띄워줘”
목표: 비정형 데이터를 Agent Operable Data로 전환한다.
단계 1 — 스키마 설계
에이전트에게: "이 CSV 파일을 분석해서 DDL을 만들어.
- 각 컬럼의 타입을 추론해
- NOT NULL, UNIQUE 등 적절한 제약조건을 추가해
- CHECK 제약으로 비즈니스 규칙도 넣어
(예: amount > 0, status IN ('active','inactive'))
- 출처와 시점 추적용 컬럼도 추가해
(source, created_at, created_by)"
단계 2 — 데이터 임포트
에이전트에게: "이 CSV를 만든 DDL에 맞게 DB에 넣어.
- 제약 위반하는 행은 rejected.csv로 빼서 보고해
- 총 행 수와 성공/실패 수를 알려줘
- 금액 합계가 원본 CSV와 일치하는지 확인해"
단계 3 — 제약 위반 감지
- rejected.csv의 행들을 확인: 왜 거부되었는가?
- DB 제약이 실제로 잘못된 데이터를 걸러내는지 확인
- 의도적으로 잘못된 데이터를 INSERT 시도 → 거부되는지 확인
단계 4 — Rego 비즈니스 규칙 (선택)
에이전트에게: “OPA를 설치하고 이 Rego 규칙을 실행해”
에이전트에게: "주문 데이터에 대한 Rego 검증 규칙을 만들어.
- 할인율이 50%를 넘으면 deny
- 같은 고객의 하루 주문 3회 이상이면 warn
- 배송 상태가 'shipped'인데 배송일이 없으면 deny"
- Rego 규칙이 실제 데이터에서 위반을 찾는지 확인
- 에이전트에게 “이 데이터에서 규칙 위반을 찾아"라고 시키고, 기계적으로 결과를 확인
단계 5 — 마이그레이션 래칫
yongol이 설치되어 있지 않다면 에이전트에게: “yongol 설치해줘”
에이전트에게: "orders 테이블에 delivery_estimate 컬럼을 추가해.
- DDL을 수정해
- yongol validate 통과시켜
- 마이그레이션 파일(up + down) 생성해
- 기존 데이터에 적용해
- 문제 생기면 down 파일로 롤백해"
확인할 것:
- DDL 제약이 잘못된 데이터를 실제로 거부하는가?
- Rego 규칙이 비즈니스 위반을 감지하는가?
- 마이그레이션 실패 시 롤백이 작동하는가?
- 전체 과정에서 에이전트가 “추측"하는 순간이 있었는가, 아니면 모두 “선언"에 기반했는가?
10강 비전: 말로 시키면 만들어준다 — 코드, 시스템, 데이터
1강에서 우리는 여기서 시작했다.
“할 일 목록 앱 만들어.”
코드가 나왔다. 3개 기능까지 작동했다. 5개에서 무너졌다.
10강의 끝에서 우리가 서 있는 곳:
1강의 세계:
"앱 만들어" → 코드가 나온다 → 5개 기능에서 무너진다
10강의 세계:
"주문 관리 SaaS 만들어"
→ 결정: 스키마를 정의하고, 기능을 선언하고, 규칙을 선언한다
→ 코드: yongol이 SSOT에서 생성한다 (8강)
→ 시스템: CI/CD가 빌드-배포-모니터링을 자동화한다 (9강)
→ 데이터: DDL이 스키마를 강제하고, Rego가 규칙을 검증한다 (10강)
→ 승인: 사람은 "승인" 버튼만 누른다
→ 200 엔드포인트에서도 무너지지 않는다
| 강 | 무엇을 배웠는가 | 결과 |
|---|---|---|
| 1강 | 바이브 코딩의 현재 | “말로 시키면 코드가 나온다” |
| 2강 | 왜 무너지는가 | 드리프트, 컨텍스트 소멸, 아첨 편향 |
| 3강 | 어떻게 막는가 | Hurl, Git, CI/CD |
| 4강 | 200 엔드포인트의 벽 | yongol — 선언적 SSOT |
| 5강 | 고삐 있는 AI | Reins Engineering 3기둥 |
| 6강 | 잠그고 진행한다 | Ratchet Pattern — 단방향 래칫 |
| 7강 | 아첨을 역이용한다 | IFEval — 피드백이 수렴을 만든다 |
| 8강 | 코드를 구조화한다 | filefunc + tsma — Agent Operable Codebase |
| 9강 | 시스템을 구조화한다 | 4가지 조건 — Agent Operable System |
| 10강 | 데이터를 구조화한다 | 스키마는 법 — Agent Operable Data |
코드 → 시스템 → 데이터. 세 도메인 모두에서 같은 원리가 작동한다.
선언하고, 검증하고, 잠그고, 영속한다. 결정은 사람이, 구현과 검증은 기계가. 인치주의가 아니라 법치주의.
1강의 “할 일 목록 앱 만들어"에서 10강의 “주문 관리 SaaS 만들어"까지 — 달라진 것은 모델의 크기가 아니다. 구조다. 에이전트에게 고삐를 채우고, 선로를 깔고, 법을 세운 것이다.
말로 시키면 만들어준다. 코드만이 아니라, 시스템과 데이터까지. 그것이 가능하려면, 고삐가 있어야 하고, 선로가 있어야 하고, 법이 있어야 한다. 그 고삐와 선로와 법을 설계하는 것이 Reins Engineering이다.
당신은 코드를 한 줄도 읽지 못하는 상태에서 이 과정을 시작했다. 10강을 마친 지금, 달라진 것은 코드를 읽게 된 게 아니다. 에이전트에게 뭘 시켜야 하는지, 왜 시켜야 하는지, 에이전트의 보고를 어떻게 검증하는지를 알게 된 것이다. 이것이 결정자의 능력이다.
연관 글
Reins Engineering 전체 강의
| 강 | 제목 |
|---|---|
| 제 1강 | AI에게 시키는 법 |
| 제 2강 | AI를 못 믿는 법 |
| 제 3강 | 깨지지 않는 앱 |
| 제 4강 | 결정을 코드 밖으로 |
| 제 5강 | 고삐 있는 AI |
| 제 6강 | 통과하면 잠근다 |
| 제 7강 | 아첨을 뒤집는 법 |
| 제 8강 | 에이전트의 공장 |
| 제 9강 | 코드 너머의 자동화 |
| 제 10강 | 데이터의 법 |
근거 자료 출처
- Stanford, “Lost in the Middle: How Language Models Use Long Contexts” (2024) — 관련 정보가 컨텍스트 중간에 묻히면 30%+ 성능 하락 (8강 재참조)
- Amazon, “Context Length Alone Hurts LLM Performance” (2025) — 불필요한 토큰이 공백이어도 13.9~85% 성능 하락 (8강 재참조)
- E.F. Codd, “A Relational Model of Data for Large Shared Data Banks” (1970) — 관계형 데이터베이스 모델, 스키마 기반 데이터 무결성의 이론적 기초
- OPA (Open Policy Agent) / Rego — 선언적 정책 언어로 비즈니스 규칙을 코드 외부에서 검증
- yongol DDL → sqlc 체이닝 — 스키마에서 타입 안전 코드까지 단절 없는 교차 검증 구조
- 법치주의 (Rule of Law) 원리 — 검증 가능성, 위반의 정의, 강제 가능성의 세 조건이 코드/시스템/데이터에 동일하게 적용
- “법은 正義(justice)가 아니라 定義(definition)다” — 디지털 법치주의 철학, 스키마를 법의 아날로그로 제시
- “진실은 빛의 속도로 사라진다” — 물리적 관측의 한계에서 출발하는 데이터 출처/시점 추적의 근거