programming
TypeScript, Rust, Python, Go에 동일하게 적용되는 엄격한 규율 — 타입 우선, TDD.
programming 스킬은 LazyCodex(LZX)가 작성하는 모든 코드 한 줄에 적용하는 타입 규율입니다. Codex가 .py, .pyi, .rs, .ts, .tsx, .mts, .cts, .go 파일이나 프로젝트 매니페스트를 건드리는 순간 자동으로 활성화됩니다. 별도 명령은 없으며, LazyCodex가 Codex에 설치하는 OmO(oh-my-openagent) 플러그인 안에 포함되어 있습니다.
한 줄 요약
네 언어에 동일한 하나의 철학: 타입 우선, 스택 우선, async 정확성, 그리고 파일 크기에 대한 아키텍처적 정직함. 엄격한 타입, 최신 툴체인, parse-don't-validate, 완전한(exhaustive) 매칭, 타입이 있는 에러, escape hatch 금지, 250 순수 LOC 상한, TDD. 일회성 스크립트도 동일하게 적용합니다.
언어 게이트
한 줄을 쓰기 전에, 스킬은 먼저 언어를 식별하고 해당 레퍼런스 세트를 로드합니다. 언어별 규칙이 로드되기 전에는 아무것도 작성하지 않습니다.
| 파일 / 언어 | 툴체인 |
|---|---|
.py, .pyi (Python) | uv + basedpyright(typeCheckingMode = "all") + ruff(select = ["ALL"]) + pytest |
.rs, Cargo.toml (Rust) | cargo + clippy(pedantic + nursery) + rustfmt + cargo-nextest + nightly miri |
.ts, .tsx, .mts, .cts (TypeScript) | Bun + Biome + tsc --noEmit(strict + noUncheckedIndexedAccess) |
.go, go.mod (Go) | go modules + gofumpt + golangci-lint v2 + nilaway + go test -race |
공유 철학
모든 레시피가 파생되는 여섯 가지 공리입니다.
- 타입 시스템이 곧 증명 시스템입니다. 버그를 타입 에러로 표현할 수 있다면, 반드시 타입 에러로 표현합니다.
- Parse, don't validate. 신뢰할 수 없는 입력은 경계에서 한 번만 타입 값으로 파싱하고(Pydantic v2 / serde / Zod), 내부에서는 다시 검증하지 않습니다.
- 하나의 이름 = 하나의 개념.
UserId는string이 아닙니다. 의미가 다른 모든 기본형에NewType, newtype 튜플 struct, branded type을 사용합니다. - 항상 완전한 variant 매칭.
match+assert_never(Python),match(Rust),switch+assertNever(TypeScript), sealed interface + exhaustive 린터(Go). 태그된 variant에if/elif/else는 금지입니다. - 프레임워크 보장은 신뢰하고, 경계에서만 검증합니다. 방어적 null 체크나 예외가 날 수 없는 코드에 대한
try/except는 금지입니다. - 테스트 주도. 필요성을 증명한 실패 테스트 없이는 프로덕션 코드를 출시하지 않습니다.
TDD 규율
모든 변경은 red → green → refactor 순서를 따릅니다.
Red
Given / When / Then으로 동작을 명시하는 실패 테스트를 작성합니다. 실행 후, 올바른 이유로 실패하는지 확인합니다 — 오타나 import 누락이 아니라 함수가 아직 없어서 실패해야 합니다.
Green
테스트를 통과시키는 최소한의 코드를 작성합니다. 두 번째 케이스는 다음 red입니다.
Refactor
테스트가 green인 상태에서 가차 없이 구조를 재정비합니다. 테스트가 안전망입니다.
테스트 피라미드는 세 단을 모두 갖춥니다. 빠른 unit 테스트(각 < 10ms) 다수, testcontainers로 실제 다운스트림을 검증하는 integration 테스트 일부, 실제 표면을 구동하는 E2E 시나리오 소수. E2E 커버리지가 0인 기능은 미완성입니다. mock은 최후의 수단으로, 실제 객체 → in-memory fake → testcontainers를 먼저 시도합니다.
250 순수 LOC 상한
순수 LOC(공백·주석 제외)가 250을 넘는 소스 파일은 스타일 취향이 아니라 결함입니다. 250 LOC에서는 리뷰어가 파일 전체를 작업 기억에 담고 횡단 버그를 잡을 수 있습니다.
- 생성 시 250 LOC를 넘길 파일: 첫 커밋 전에 책임별로 분리합니다.
- 편집 시 이미 250 LOC를 넘은 파일에 줄을 추가: 건드리는 단위를 먼저 별도 파일로 추출합니다.
- 읽기 시 250 LOC를 넘긴 파일: smell을 명시하고 구체적인 분리안을 제안한 뒤, 그대로 진행할지 묻습니다.
금지된 회피: 주석을 예산에 포함하기, 토큰 수로 분리(service-2.ts), catch-all 덤프 파일(utils.py, helpers.ts), 230 LOC에서 "거의 다 됐으니" 넘어가기.
언어 공통 철칙
언어별 레퍼런스가 더 엄격하지 않은 한 적용됩니다.
- 기본은 불변(
frozen=True/let/readonly/ 값 타입). - 모든 의미 단위에 branded 기본형.
- escape hatch 금지:
any/Any,unwrap/!,# type: ignore/@ts-ignore, 숫자as좁히기 금지. - bare 에러 문자열 금지 — 타입 예외,
thiserror/anyhow,Error서브클래스, sentinel +%wwrap. - RAII로 리소스 관리(
with/Drop/using/defer). - 필수 async 런타임: anyio(bare asyncio 금지), tokio,
AbortSignal기반 플랫폼 네이티브,context.Context+ errgroup.
작성 후 리뷰 루프
코드 작성·실질 편집을 마칠 때마다 완료 선언 전에 수행합니다.
- 변경된 모든 파일의 순수 LOC를 측정합니다.
- 해석: ≤ 200 양호, 200–250 경고 구간, > 250 결함(즉시 리팩터).
- 단일 책임, 경계 순수성, 완전 매칭, escape hatch, 방어 레이어, 일회성 헬퍼, 테스트 커버리지를 자가 점검합니다.
상한을 넘었거나 이슈가 둘 이상이면 스킬은 refactor 스킬(안전한 codemap 기반 다단계 리팩터) 또는 remove-ai-slops(테스트를 먼저 고정한 분류형 정리)를 로드합니다.