경계 강제 패턴
경계 강제 패턴
개별 강제 문서들이 각각의 문제를 다룬다. 이 문서는 그 강제들이 공유하는 구현 패턴을 정리한다.
강제를 구현할 때 반복해서 나타나는 패턴이 있다. 빌드 타임이든 런타임이든, Atlas든 Glif든 — 경계를 강제하는 방식은 수렴한다.
이 문서는 각 패턴이 어떤 문제를 해결하는지, 그리고 어떤 강제 문서와 연결되는지를 보여준다.
패턴 1 — Import 제한 (Access Restriction)
가장 간단하고 효과가 큰 패턴이다. 허용되지 않은 모듈을 import하면 빌드가 실패한다.
// ESLint (Glif)
{
"no-restricted-imports": ["error", {
"patterns": [{
"group": ["@/infra/*"],
"message": "UI must not access infrastructure directly."
}]
}]
}<!-- Roslyn (Atlas) - .editorconfig -->
dotnet_diagnostic.ATL001.severity = error적용 위치: 빌드 타임 강제 — 레이어 경계, 컴포넌트 직접 import
패턴 2 — 내부 숨기기 (Encapsulation)
구현체를 외부에서 볼 수 없게 만들어 접근 자체를 차단한다.
// Atlas: internal 키워드로 레이어 외부 접근 차단
internal sealed class FileDocumentRepository : IDocumentRepository { }// Glif: 모듈 외부에 노출하지 않음
const db = createDatabase(); // export 없음
export function query(sql: string) { // wrapper만 노출
return db.query(sql);
}적용 위치: 백엔드 레이어 우회, 컴포넌트 레지스트리 우회
패턴 3 — Global 제거 (Global Elimination)
Global singleton과 default fallback은 항상 우회 경로가 된다.
// 위반
export const globalStore = createStore(); // global 노출
// 합법
export function createAppStore() { // factory만 노출
return createStore();
}// 위반: global fallback
return useContext(StoreContext) ?? globalStore;
// 합법: 명시적 실패
const store = useContext(StoreContext);
if (!store) throw new Error("StoreProvider required");패턴 4 — 타입으로 경로 고정 (Type-Level Path Enforcement)
타입 시스템을 이용해 특정 상태를 거치지 않은 값이 다음 단계로 넘어가지 못하게 만든다.
// Atlas: validated type만 다음 단계로
public sealed record ValidDocId(string Value);
public interface IDocumentRepository
{
Task<Document> LoadAsync(ValidDocId id, CancellationToken ct);
// string이 아니라 ValidDocId만 받음
}// Glif: 상태를 타입으로 분리
type DraftTask = { state: "draft"; title: string };
type ValidatedTask = { state: "validated"; title: string; validatedAt: Date };
function runTask(task: ValidatedTask): void {
// ValidatedTask만 받음. DraftTask는 컴파일 오류.
}패턴 5 — 단일 진입점 강제 (Single Entry Point)
여러 경로로 접근 가능한 것을 하나의 경로로 수렴시킨다.
// 위반: 여러 진입점
export function saveDocument(doc) { ... }
export function quickSave(doc) { ... }
export function autosave(doc) { ... }
// 합법: 하나의 진입점
export function dispatch(command: DocumentCommand) {
// 내부에서 라우팅
}적용 위치: Planner 통제, 실행 흐름 우회
패턴 6 — 테스트 Helper 강제 (Test Helper Enforcement)
테스트도 같은 경계를 통과하게 만드는 wrapper를 강제한다.
// 위반: raw render
render(<Component />);
// 합법: wrapper 강제
renderWithAppProviders(<Component />, config);{
"no-restricted-imports": ["error", {
"patterns": [{
"group": ["@testing-library/react"],
"message": "Use renderWithAppProviders instead of raw render."
}]
}]
}적용 위치: 테스트 하네스 강제
패턴 조합
패턴들은 함께 작동할 때 효과적이다. 하나만 적용하면 다른 경로가 열린다.
| 목적 | 필요한 패턴 조합 |
|---|---|
| 레이어 경계 잠그기 | Import 제한 + 내부 숨기기 + 타입 고정 |
| 상태 전이 통제 | 타입 고정 + 단일 진입점 + Runtime Guard |
| AI 실행 흐름 통제 | 단일 진입점(Planner) + Runtime Guard + Planner 통제 |
| 테스트 환경 정렬 | 테스트 Helper 강제 + Import 제한 |