C#로 소프트웨어 개발: 1부 - 역사

발행: (2026년 5월 29일 AM 05:29 GMT+9)
9 분 소요
원문: Dev.to

출처: Dev.to

3‑Layer Architecture

2010년 체코 프라하에서 C# 프로그래밍을 시작했을 때, 가장 흔했던 흐름은 3‑계층 모놀리식 아키텍처였다. 이 방식은 애플리케이션을 프레젠테이션 계층, 비즈니스 계층, 데이터베이스 계층으로 나눈다.

하지만 어쩐지 이 개념은 자주 오해되었다. 계층이라기보다 사람들은 이를 “필요할 때마다” 서로 통신할 수 있는 독립된 컴포넌트로 취급했다. 면접에서 시니어 개발자들은 비즈니스 계층이 프레젠테이션 계층과 데이터베이스 계층 사이에 정확히 위치해야 하며, 프레젠테이션 계층이 데이터베이스와 직접 통신해서는 안 된다고(또는 그 반대도 마찬가지라고) 엄격히 주장했다.

UI와 데이터베이스가 양방향으로 직접 통신하고, 비즈니스 계층은 “복잡해지면” 헬퍼 코드를 버리는 쓰레기통 역할만 하는 기이한 레거시 프로젝트들이 바로 이 시기에 생겨났다.


Onion Architecture

그 후 얼마 지나지 않아 Onion Architecture 기법이 인기를 끌었다. 개발자들은 이 방법에 엄청난 흥분을 감추지 못했다—소프트웨어가 단순히 세 개의 계층만으로 이루어지는 일은 없으니 말이다. 너무 쉬워 보였기 때문이다. 소프트웨어는 인생처럼 복잡하니 여러 계층이 필요하다고 생각했다. 그래서 이것이 정답이라고 믿었다.

양파의 중심에는 핵심—즉, 비즈니스의 궁극적인 뿌리이 있다. 그 위에 쌓이는 모든 것은 순차적으로 쌓이는 기술적 계층이다. 외부 계층은 별로 중요하지 않으며, 오직 중심만이 중요하다고 여겨졌다.

이론적으로는 너무나도 매력적이었기에 팀들은 서둘러 적용했지만, 그 결과는 향후 수년간 지속될 거대한 기술 부채를 낳았다.

오늘날까지도 “양파” 모델의 실제 의미는 모호하다. 구글 이미지에서 “onion layer architecture”를 검색하면 전혀 다른, 상충되는 해석들을 쉽게 찾을 수 있다.

  • 양파의 중심이 비즈니스 로직인가, 아니면 데이터베이스 엔티티의 형태인가?
  • 서로 접촉하는 계층끼리 양방향으로 통신할 수 있는가?
  • 가장 바깥쪽 계층은 실제로 무엇이어야 하는가?

Domain‑Driven Design (DDD)

나는 Domain‑Driven Design (DDD) 가 인기를 끈 이유가 사람들 사이에서 Onion Architecture의 “핵심”을 과도하게 강조했기 때문이라고 생각한다. “핵심”은 바로 비즈니스 로직, 즉 가장 중요한 부분을 의미한다.

DDD는 이를 명확히 했다: 도메인은 비즈니스의 성배다. 개발자는 뒤로 물러서서 비즈니스 로직을 최우선으로 두어야 한다. 비즈니스 요구사항을 코드로 번역하는 번역가 역할만 하면 된다. 이것이 DDD다—비즈니스가 먼저!

그럼 어떻게 구현하냐? 바로 도메인 전문가가 필요하다—도메인의 공통 언어를 유지하고 비즈니스 목표를 요구사항으로 변환하는 전담 역할이다.

내 경력 전체를 돌아보아도 공식적으로 “도메인 전문가”라는 직함을 가진 사람을 본 적이 없다. 다국적 대기업에서도 공식적인 역할로는 존재하지 않았다(넷플릭스에선 실제로 있었던 것으로 소문이 있긴 하지만).

결국 이 접근법은 표준 3‑계층 아키텍처를 다시 구현하되, 이번엔 올바르게 하는 식으로 돌아갔다. 도메인이 비즈니스 계층이 되고, 데이터 흐름은 한 방향으로만 움직인다: 프레젠테이션 → 비즈니스 → 데이터베이스. 백그라운드 프로세스, WSDL SOAP API, 웹훅 등은 모두 양파 안에 깔끔히 들어간 것처럼 가장했다. 그래야 코드베이스가 스파게티가 되지 않는다.


DDD, Event Sourcing, and CQRS

한때 이 조합은 모든 것을 완벽하고 깔끔하게 보이게 하는 궁극적인 트렌드였다.

  • 비즈니스 핵심이벤트 소싱(Event Sourcing, ES) 이라 불리는 불변의 변경 스트림으로 격리한다. 도메인은 순수하고 깨끗하게 유지된다. 클래스들은 비즈니스와 1:1 관계를 이루는 도메인 객체이며, 메서드는 실제 비즈니스 프로세스를 반영한다.
  • CQRS(Command‑Query Responsibility Segregation)는 전체 구성을 프로그래밍 완벽함과 마주하게 만든다. 명령은 도메인에 직접 전달되고, 쿼리는 이벤트에서 비동기적으로 구성된 읽기 모델이 처리한다. “점진적 일관성(eventual consistency)”이라는 아름다운 개념이 있기에 말이다.

그런데 누군가 근본적인 질문을 던졌다:

“사용자 이메일 주소가 고유함을 어떻게 보장하나요?”

이 간단한 요구사항 때문에 일부 설계자는 방어적으로 반박했다:

“그건 바보 같은 요구사항이야, 고유한 이메일이 필요 없으니 그냥 넘어가.”

하지만 진짜 문제는 순수 DDD/ES/CQRS 환경에서 이걸 어떻게 처리하느냐이다.

  • User 클래스 안에서 쉽게 강제할 수 없다. 해당 클래스는 단일 사용자 컨텍스트만 알기 때문이다.
  • 명령 앞에 UserCollection 같은 클래스를 만들어 이메일을 관리해야 할까? 그렇다면 UserCollection이 DDD가 강조하는 의미 있는 비즈니스 지식을 어떻게 담을 수 있겠는가?
  • 이벤트 소싱을 통해 도메인 상태를 로드한다면, 컬렉션 전체에 걸친 고유성 검증을 위해 모든 과거 이메일을 메모리로 로드하는 것은 비효율적이다. 결국 기본 이벤트 스토어와는 별도로 사용자 이메일을 별도 저장소에 두어야 한다.

이것이 DDD/ES/CQRS 패러다임의 가장 큰 단점, 극도의 복잡성을 보여준다. 스냅샷 관리, 명령/이벤트 버전 관리, GDPR을 위한 데이터 익명화, 이벤트 순서 보장, 동시성, 읽기 모델 비동기화 문제 등을 다루다 보면 실제 기능

0 조회
Back to Blog

관련 글

더 보기 »

마이크로소프트, C# 메모리 안전성을 러스트 수준으로 높인다

마이크로소프트의 C 메모리 안전성 강화 계획 마이크로소프트는 C 언어의 메모리 안전성을 러스트 수준으로 끌어올리겠다는 계획을 발표했습니다. 닷넷 제품 관리자 리처드 랜더는 21일 개발자 블로그에서 “C의 메모리 안전성을 대폭 개선하는 작업을 진행 중”이라며, unsafe 키워드를 재설...

Chibil: .NET IL용 C 컴파일러

What is chibil Chibil is a C compiler based on chibicchttps://github.com/rui314/chibicc rewritten in C and updated to target .NET IL MSIL. It is complete enoug...