통신 우회

개요

정의된 통신 경로가 있음에도 이를 우회하고 직접 호출하거나 공유 상태를 사용하는 문제는 시스템의 제어 가능성을 제거하며, 이는 하네스를 통해 차단되어야 한다.


이 문서의 질문

이 문서는 하네스 개요에서 정리한 다섯 공통 패턴 중 direct path bypass에 가장 가깝다. 핵심 질문은 다음과 같다.

UI와 Backend 사이의 요청이 Bridge 같은 공식 통신 경로를 반드시 통과하는가

문제

Atlas 구조에서는 UI와 Backend가 분리되어 있고,
그 사이에는 명시적인 통신 계층이 존재한다.

하지만 실제 코드에서는 다음과 같은 우회가 발생한다.

var result = BackendEngine.Instance.Process(data);

또는

GlobalState.SharedData = value;

또는

var engine = new Engine();
engine.Run();

이 코드는 모두 공통된 특징을 가진다.

통신 계층을 거치지 않는다


문제의 본질

이 문제는 단순한 호출 문제가 아니다.

핵심은 다음이다.

흐름이 사라진다


요청 흐름 단절

정상 구조:

UI → Bridge → Backend

우회 구조:

UI → Backend (직접)

이 변화는 작아 보이지만 결과는 치명적이다.


관찰 불가능 상태

Bridge를 통하지 않으면:

  • 요청 기록 없음

  • 추적 불가능

  • 디버깅 불가능

즉 시스템이 “보이지 않게” 된다.


제어 지점 상실

Bridge는 단순 전달 계층이 아니다.

  • 검증

  • 권한 체크

  • 로깅

  • 변환

이 모든 것이 사라진다.


AI의 선택 패턴

사람과 AI는 다음 조건에서 우회를 선택한다.

  • Bridge가 번거로울 때

  • 테스트 코드 작성 시

  • 빠른 결과가 필요할 때

즉:

“지금 당장 동작"을 위해 구조를 제거한다


목표 구조

핵심은 다음이다.

Backend는 직접 접근 가능한 대상이 아니라
통신을 통해서만 접근 가능한 시스템으로 만든다


사례 규칙 요약

  • UI에서 Backend 구현체 직접 접근 금지

  • static/shared 상태 접근 금지

  • Bridge를 통한 호출만 허용

자세한 rule/validator 설계 원칙은 규칙 설계검증기 설계를 따른다. 이 케이스에서는 위 금지 표면과 합법 경로가 바로 검사 대상이다.

하네스 적용 위치

이 케이스의 하네스는 process boundary와 bridge contract에 걸린다.

구조 레벨

UI는 backend 타입을 직접 보지 못하고 IBackendBridge 같은 통신 계약만 본다.

실행 레벨

실제 처리와 상태는 backend 프로세스 안에서만 존재하고 UI는 request/response만 다룬다.

검증 레벨

backend namespace 참조, singleton access, new Engine() 같은 직접 진입을 정적 분석과 프로젝트 참조 차단으로 막는다.

실제 구현

Backend 완전 격리

Backend를 별도 프로세스로 분리한다.

👉 핵심:

  • UI에서 직접 참조 불가능

  • 동일 메모리 공간 공유 금지


IPC 인터페이스 정의

public interface IBackendBridge
{
    Task<ProcessResult> ProcessAsync(ProcessRequest request);
}

WPF 측 구현

public sealed class BackendBridge : IBackendBridge
{
    private readonly HttpClient _http;

    public BackendBridge(HttpClient http)
    {
        _http = http;
    }

    public async Task<ProcessResult> ProcessAsync(ProcessRequest request)
    {
        var response = await _http.PostAsJsonAsync("/process", request);
        response.EnsureSuccessStatusCode();

        return await response.Content.ReadFromJsonAsync<ProcessResult>()
               ?? throw new InvalidOperationException();
    }
}

Rust Backend

#[derive(serde::Deserialize)]
pub struct ProcessRequest {
    pub data: String,
}

#[derive(serde::Serialize)]
pub struct ProcessResult {
    pub result: String,
}

pub async fn process(req: ProcessRequest) -> ProcessResult {
    ProcessResult {
        result: format!("processed: {}", req.data),
    }
}

위반 예시와 실패 결과

다음 코드는 반드시 실패해야 한다.

public async Task RunAsync(string raw)
{
    var engine = new BackendEngine();
    await engine.ProcessAsync(raw);
}

또는

await BackendHost.Instance.ProcessAsync(raw);

실패 결과:

error: UI must access backend through the designated bridge contract.

우회가 실패해야 요청 흐름과 관찰 지점이 다시 하나로 모인다.

보조 강제 수단

이 케이스의 보조 강제 수단은 process 분리만으로 끝나지 않는다. UI 프로젝트에서 backend 타입이 보이지 않도록 assembly 참조를 닫고, 남은 singleton/host shortcut도 analyzer로 함께 막아야 한다.

Roslyn Analyzer

Backend 직접 참조 금지

if (type.ContainingNamespace.ToDisplayString().StartsWith("Atlas.Backend"))
{
    context.ReportDiagnostic(...);
}

Singleton 접근 금지

if (memberAccess.Expression.ToString().EndsWith("Instance"))
{
    context.ReportDiagnostic(...);
}

new 생성 금지

if (type.Name.EndsWith("Engine"))
{
    context.ReportDiagnostic(...);
}

프로젝트 레벨 차단

참조 제거

<ProjectReference Include="..\Backend\Backend.csproj"
                 ReferenceOutputAssembly="false" />

👉 결과:

  • UI에서 Backend 타입 자체를 볼 수 없음

결과

흐름 복원

  • 모든 요청이 Bridge를 통과

  • 흐름이 명확해짐


관찰 가능성 확보

  • 로그

  • 추적

  • 디버깅

모두 가능


제어 가능성 확보

  • 검증

  • 정책 적용

  • 접근 제한


행위자 행동 변화

이제 사람과 AI는 더 이상:

  • 직접 호출

  • singleton 접근

  • shared state

를 사용할 수 없다


실무 적용 팁

  • bridge contract는 좁게 유지하고, UI에 backend DTO 외의 concrete 타입이 새지 않게 하는 편이 좋다.
  • Instance, Host, Engine 같은 전역 진입점은 편의 API가 아니라 우회 표면으로 취급하는 게 안전하다.
  • 통신 실패, retry, timeout도 bridge 안에서 처리하고 UI에는 명시적 결과만 노출하는 편이 낫다.

요약

통신 우회 문제는 하네스를 통해서만 해결된다.

  • Backend 프로세스 분리

  • IPC 경로 강제

  • Analyzer로 직접 접근 차단

  • 빌드 에러로 강제

이 구조를 통해
시스템은 항상 추적 가능한 상태를 유지한다.