경계 강제 패턴

경계 강제 패턴

개별 강제 문서들이 각각의 문제를 다룬다. 이 문서는 그 강제들이 공유하는 구현 패턴을 정리한다.


강제를 구현할 때 반복해서 나타나는 패턴이 있다. 빌드 타임이든 런타임이든, 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 제한