시스템의 전체적인 구조를 정의하는 중요한 개념
좋은 아키텍처 설계
소프트웨어의 품질, 유지보수성, 확정성을 결정하는 핵심요소
시스템의 전체적인 구조 정의
ex) 웹기반 시스템에서는
클라이언트와 서버 간의 HTTP연결 및 상호작용 포함
비기능적 품질 요구사항 만족
좋은 아키텍처는 시스템의 비기능적 품질 요구사항을 만족시키기위해 필수, 품질 보장을 위해 매우 중요
전반적인 구조 설계
소프트웨어 시스템에 대한 전반적인 구조를 설계하는 과정
시스템을 구성하는 서브시스템과 묘듈을 정의
덩어리화(Chunking)작업
서브시스템 수준에서 관련 기능을 그룹화하고 이를 바탕으로 그룹 수준의 설계 진행
추상화와 관계 정의
다양한 수준에서 구성 요소의 역할과 구성 요소 간의 관계에 집중하여, 클래스 수준 이상의 그루핑과 역할, 인터페이스를 정의
아키텍처 설계는 중요한 과정, 개발 효율성을 높이고 유지보수에 용이
1. 이해도 향상
-- 누구나 시스템을 이해할 수 있도록 도움
2. 독립적 작업
-- 시스템의 일부를 독립적으로 작업 가능
3. 확장성 준비
-- 시스템의 미래 확장을 위한 기반 제공
4. 재사용성 증대
-- 컴포넌트 재사용과 재사용 가능성 용이
소프트웨어 아키텍처는 시스템 구조를 확립하는 개발의 중심축
설계, 구현, 통합, 테스팅까지 영향을 미치는 뼈대이고
모든 개발 단계에 영향을 줄 수 있는 핵심적인 요소
1. 소프트웨어도 특정 목적에 맞게 설계해야 함
2. 기능보다는 품질 속성이 더 많은 비중을 차지
같은 기능을 구현한 두 개의 구조가 다른 이유
달성하고자 하는 품질 속성(보안성, 확장성, 사용성 등)이 다르기 때문
좋은 아키텍처 모델
논리적 분할
- 시스템을 논리적으로 분할된 서브시스템으로 표현
물리적 배치
- 컴포넌트가 런타임에 존재하는 물리적 위치
인터페이스
- 서브시스템 사이의 인터페이스 정의
동적 상호작용
- 컴포넌트 사이의 동적인 인터렉션 방식
공유 데이터
- 서브시스템 사이에 공유하는 데이터 구조
블랙박스 표현
계층적 분할식 표현
다양한 뷰 사용
효과적인 아키텍처 표현은 복잡한 시스템을 이해하기 쉽게 만들고 커뮤니케이션을 원활하게 함
아키텍처 모델의 개발
아키텍처 정제(Refine)
컴포넌트 간 상호작용 방식과 인터페이스를 파악하고
자료와 기능이 여러 컴포넌트 사이에 어떻게 분배되는지 결정아키텍처 성숙화
반복적인 검토와 수정을 통해 아키텍처를 점차 성숙시킴아키텍처 모델은 초기 설계 후 완성되는 것이 아니라,
프로젝트 진행 과정에서 지속적으로 발전하고 성숙해짐
독립적 컴포넌트 설계
컴포넌트를 이용하여
융통성 있는 시스템을 설계하도록 도움
컴포넌트가 서로 독립적이여서 한 부분의 변경이 다른 부분에 영향을 최소화해야 함
전체적인 조화 정의
MVC 스타일
모델(Model)
사용자에게 보여주고 조작될 수 있는 중요한 클래스의 인스턴스를 포함애플리케이션의 핵심 데이터와 가능을 제공
뷰와 컨트롤러에 영향받지 않도록 설계뷰(View)
모델에 있는 데이터를 사용자 인터페이스에 보여주는 역할 담당
동일한 모델에 대해 다양한 뷰를 쉽게 추가 가능컨트롤러(Controller)
사용자가 모델과 뷰와 상호작용하는 것을 제어하는 객체를 포함
사용자가 요청을 처리하고, 모델을 생성, 적절한 뷰 선택MVC패턴은 모델과 뷰 간의 결합관계를 약화시켜 동일한 모델에 대해 다양한 뷰를 쉽게 추가할 수 있게 해줌
뷰가 변경되어도 모델에 영향을 주지 않도록 함
ex) 옵서버 패턴, 스프링 프레임워크
MVC 스타일의 사례
1. 사용자 요청
사용자가 컨트롤러에게 요청을 보냄
컨트롤러는 요청을 분석하고 처리2. 모델 처리
컨트롤러는 모델에 데이터 변경이나 조화를 요청
모델은 비지니스 로직을 수행하고 결과를 반환3. 뷰 업데이트
모델이 변경되면 뷰에 알림이 가고, 뷰는 모델의 최신 데이터를 반영하여 사용자에게 표시MVC패턴은 웹 애플리케이션에서 널리 사용됨
사용자 인터페이스와 비지니스 로직을 분리하여 유지보수성과 확장성을 높임
스프링 MVC, ASP.NET MVC, Ruby on Rails 등 많은 프레임워크에서 이 패턴을 채택
모델 디렉토리
데이터와 비즈니스 로직을 담당하는 클래스들이 위치
뷰 디렉토리
사용자 인터페이스 관련 클래스들이 위치
컨트롤러 디렉토리
모델과 뷰를 연결하는 클래스들이 위치
메인 클래스
애플리케이션의 시작점이 되는 클래스
=> 이렇게 명확한 구조는 코드의 역할과 책임을 분리하여 유지보수와 확장을 용이하게 함
각 디렉토리는 특정 기능에 집중된 클래스들을 포함하여, 개발자는 코드의 구조를 쉽게 이해할 수 있음
Model: User.java
데이터 관리
User클래스는
사용자의 이름을 저장하고 관리하는 역할 담당
오로지 user에 관련된 것만 포함하는 클래스독립성 유지
뷰나 컨트롤러에 대한 어떠한 참조도 가지지 않으며, 이를 통해 다른 컴포넌트의 변경에 영향받지 않음
View: UserView.java
사용자 인터페이스 담당
UserView클래스는 사용자에게 정보를 표시하는 역할담당모델에 의존
뷰는 모델의 데이터를 표시하기 위해 모델에 의존하지만 어떻게 데이터를 가져오는지는 알 필요가 없음뷰는 사용자와의 상호작용을 담당하는 중요한 컴포넌트
Controller: UserController.java
모델과 뷰를 연결
두 객체에 대한 참조를 유지하며 상호작용을 조정모델 업데이트
setUserName 메서드는 사용자 입력에 따라 모델의 데이터를 업데이트
이 과정에서 데이터 검증이나 변환 작업이 이루어질 수 있음뷰 업데이트
updateView메서드는 모델의 변경사항을 뷰에 반영하도록 지시, 사용자에게 최신 정보가 표시컨트롤러는 사용자 입력을 처리하고, 모델을 업데이트하며, 적절한 뷰를 선택하여 사용자에게 결과를 보여줌
이를 통해 모델과 뷰의 독립성을 유지할 수 있음
“모델과 뷰가 서로 직접 참조하거나 조작하지 않도록, 컨트롤러가 중간에서 그 역할을 대신한다"
모델을 직접 변경하거나 조작하면, 뷰와 모델이 너무 밀접하게 연결됨 → 유지보수 어려워짐
그래서 모델-뷰 사이에 컨트롤러가 꼭 필요하다.
Main
객체 생성
Model, View, Controller객체를 생성하고 초기화
각 컴포넌트가 적절히 연결되도록 함컨트롤러 설정
컨트롤러에 모델과 뷰 객체를 설정하여 세 컴포넌트가 함께 작동할 수 있도록 함사용자 상호작용
사용자 이름을 설정하고 화면에 표시하는 과정을 시뮬레이션
MVC 스타일 장점
독립적 설계와 수정 용이성
각 구성요서(Model, View, Controller)가 독립젹으로 설계되어 수정이 쉬움
하나를 변경해도 다른 부분에 영향을 최소화할 수 있음부분 수정 가능
기능 확장 용이
User.java 더 많은 사용자 속성(나이, 이메일)을 추가해도 Controller와 View는 그대로 유지 가능
이것은 시스템 확장성을 크게 향상시킴관심사의 분리를 통해 코드의 유지보수와 확장을 용이하게 한다는 점
각 구성요서가 명확한 역할과 책임을 가지니까 개발자는 특정 부분만 집중해서 개발하거나 수정할 수 있음개별 컴포넌트 단위 테스트
분리해서 테스트를 하면 개별 컴포넌트 단위 테스트가 가능
버그를 초기에 발견할 수 있음컨트롤러 테스트
동적인 단위 테스트를 할 수 있음
이를 통해서 비지니스 로직의 정확성을 검증할 수 있음독립적 테스트
View가 없어도 Model과 Controller만으로 테스트가 가능
View를 여러 방식으로 바꿔도 Model과 Controller는 그대로 사용가능
하나의 모델과 컨트롤러로 다양한 인터페이스를 구현할 수 있어 개발 효율성이 높아짐명확한 역할 분담
백엔드 개발
데이터 처리와 로직 구현에 집중할 수 있게 함
프론트엔드 개발
디자인과 사용자 경험 향상에 집중할 수 있게 함UI와 비지니스 로직 분리
가장 많이 사용되는 아키텍처
시스템을 여러 계층으로 나누어 설계하고 구현
각 계층은 바로 아래에 있는 계층과만 통신
상위 계층은 하위 계층을 서비스로 이용
1-tier 아키텍처
단일 시스템 구조
모든 기능(UI, 비지니스 로직, 데이터 접근)이 하나의 시스템에 통합된 구조장점
적은 비용으로 매우 쉽게 구성할 수 있다, 배포가 단순하고, 성능 측면에서도 유리할 수 있다.구현 단순성
낮은 학습 비용
빠른 실행 성능
소규모 프로젝트 적합성단점
확장성, 이식성에 적합하지 않다.
데이터베이스 내용을 여러 사람이 공유할 수 없어서 협업 환경에 적합하지 않다.
유지보수가 어려워지고, 기능 확장이 제한적, 코드 재사용성이 낮다.유지보수가 어려움
낮은 재사용성
확장성 한계
사용자 수가 증가하거나 기능이 복잡헤질 경우 대응하기 어려움
테스트가 어려움
기능 테스트를 위해 전체 프로그램을 실행해야하므로 테스트 효율성이 낮음 자동화된 단위 테스트를 작성하기도 어려움실무 활용 사례
- 관리도구
- 개발도구
- 스트립트도구
- 임베디드 시스템
2-tier 아키텍처
클라이언트-서버 모델
클라이언트와 서버로 구성된 구조클라이언트: 사용자 인터페이스와 비지니스 로직을 처리
서버: 데이터베이스 관리를 담당장점
- 데이터베이스를 분리하여 여러 사용자가 공유 가능
- 데이터베이스 변경이 용이함
- 1-tier보다 확장성 향상
- 계층 분리
- 재사용성 향상
- 단위 테스트 가능
- 여러 클라이언트가 동일한 데이터 서비스를 공유할 수 있음
단점
- 클라이언트 수가 늘어날수록 데이터베이스 서버에 부하 집중
- 전체 애플리케이션 성능 저하 가능성
- 비즈니스 로직 변경 시 모든 클라이언트 업데이트 필요
- 보안성 취약점 발생 가능성
- 소규모 네트워크 환경이나 부서별 애플리케이션에 적합하지만 대규모 기업 환경에서는 확장성 문제로 한계가 있음
- 비지니스 로직과 UI의 결합
- 확장성 부족
- 보안 및 권한 관리 어려움
- 계층간의 의존도가 높아 데이터 계층 구조가 바뀌면 UI계층까지 코드 변경이 필요
2-tier 아키텍처 코드
코드 구조 구분
UserDAO.java 데이터 엑세스 계층(Tier 2)
UserApp.java 프레젠테이션 + 비즈니스 로직(Tier 1)UserDAO.java
데이터 관리 담당
사용자 정보를 관리하고 저장하는 역할 담당
추가 읽기 기능 제공
사용자 데이터에 대한 기본적인 생성, 조회 기능을 제공
데이터 관리의 기본 연산
구현 추상화
클라이언트 코드는 데이터가 어떻게 저장되는지 알 필요가 없음
UserDAO가 제공하는 메소드를 통해 데이터에 접근
데이터 저장방식이 변경되어도 클라이언트 코드는 수정할 필요가 없음UserApp.java
프레젠테이션 계층과 비지니스로직 계층을 모두 포함하고 있어서 2-tier 아키텍처의 클라이언트 부분을 구성함
사용자와의 상호작용을 담당하면서 데이터 계층과 통신하는 역할
사용자 인터페이스
사용자와 상호작용하는 인터페이스를 제공
비지니스 로직
사용자 정보를 추가, 조회하는 기능을 구현하고 필요에 따라 데이터 검증도 수행
DAO 활용
UserDAO 객체를 통해 데이터 계층과 상호작용함
사용자 요청에 따라 적절한 DAO메서드를 호출하고 그 결과를 사용자에게 표시
3-tier 아키텍처
클라이언트
사용자 인터페이스
- 프레젠테이션 계층
웹/애플리케이션 서버
핵심 기능과 규칙 처리
- 프레젠테이션 계층
- 비지니스 로직 게층
- 데이터 접근 계층
데이터베이스 서버
데이터 저장 및 검색
- 데이터베이스
작업이 복잡하고 비용이 많이 소모되는 단점이 있지만
보안성, 성능, 확장성이 1-tier와 2-tier아키텍처에 비해 뛰어난 장점을 가지고 있다.
각 계층이 명확히 분리되어 유지보수와 확장성이 용이물리적 분리 기능
각 계층은 논리적으로 분리될 뿐만 아니라, 물리적으로도 다른 서버에 배포할 수 있음
- 클라이언트 티어: 웹 브라우저, 모바일 웹
- 미들 티어: 애플리케이션 서버
- 데이터 티어: 데이터베이스 서버
기술 스택 분리
각 계층의 전문가가 자신의 영역에 집중할 수 있게 하고
특정 계층의 기술 변경이 다른 계층에 영향을 미치지 않도록 함장점
- 관심사 분리
- 유지보수 및 확장 용이
- 보안성 향상
- 테스트 용이
단점
- 초기 설계 복잡도
- 오버헤드 증가
성능 저하 가능성
계층 간 통신 비용이 불필요한 오버헤드가 될 수 있음- 소규모 프로젝트에 과도함
- 계층 간 종속성 가능성
잘못 설계하면 계층 간 의존성이 복잡해질 수 있음각 계층을 독립적으로 배포한다면 인프라 및 버전 관리 복잡성이 증가한다.
이벤트 중심 통신
이벤트 생산자가 이벤트를 발생시키고 이벤트 소비자가 이를 수신하는 방식으로 통신
실시간 반응성
이벤트는 사용자 행동, 데이터 변경, 시스템 상태 변화 등 비지니스 내외부에서 발생하는 주목할만한 사건을 의미
이벤트는 실시간으로 전달되어야 함
상태 기반 처리
발생된 이벤트의 종류와 시스템 상태에 따라 다른 처리가 이루어짐
이벤트(Event)
시스템 또는 서비스의 상태 변화를 나타내는 신호나 데이터
이벤트 생산자(Producer)
이벤트를 감지하거나 생성하여 메시지로 발행하는 역할
사용자 인터페이스, 외부 시스템, 내부 서비스 등
이벤트 브로커(Broker)
이벤트 중개하고 여러 소비자에게 이벤트를 전달하는 역할
컴포넌트 간 직접적인 의존성 없이 상호작용할 수 있음
시스템의 결합도를 낮추고 유연성을 높임
이벤트 소비자(Consumer)
이벤트 수신하여 적절한 처리를 수행하는 서비스나 컴포넌트
이메일 발송, 로깅, 알림 등 다양한 후속 작업
이벤트 리스너(Listener)
이벤트 소비자의 인터페이스, 이벤트를 처리하는 메서드 정의
이벤트 소비자가 구현해야하는 계약을 정의
인터페이스를 통한 느슨한 결합을 구현하여
이벤트 생산자와 소비자를 분리
새로운 이벤트 소비자를 쉽게 추가할 수 있고 기존 코드 수정없이 기능을 확장할 수 있음
이벤트 기반 아키텍처에서 가장 핵심적인 역할
이벤트 소비자의 표준 계약을 정의함으로써 일관된 이벤트 처리 방식 보장, 시스템의 확장성과 유연성을 높임
인터페이스
=> 모든 것이 구현되지 않은 상태
마이크로 서비스 아키텍처
애플리케이션을 작고 독립적인 서비스들의 집합으로 나누어 구성하는 소프트웨어 아키텍처 스타일
대규모 애플리케이션을 개발하고 유지보수하는데 효과적인 접근 방식
각 서비스의 독립적인 개발과 배포를 통해 개발 속도와 시스템 안정성을 향상시킬 수 있음
독립적 서비스
각 기능이 별도의 서비스로 구현각 서비스 자체가 자체 데이터베아스를 가지고 독립적으로 개발 및 배포될 수 있게 함
작은 단위 서비스
단일 책임 원칙을 따르며 특정 도메인 기능만 담당독립적 배포
각 서비스는 별도로 개발 테스트 배포 가능
개발 사이클 빨라짐
특정 기능만 업데이트 가능자체 데이터 보유
자기만의 데이터베이스 소유네트워크 통신
REST API, gRPC, 메시지 큐 등을 사용경량화
Spring Boot, Node.js, Go등으로 빠르게 기동되고 가볍게 동작
리소스 효율성과 빠른 시작 시간을 확보마이크로 서비스 아키텍처 장점
- 서비스별 독립적 개발 가능
- 부분적 배포와 업데이트 지원
- 서비스 단위의 확장성 제공
- 장애 격리 (한 서비스의 문제가 전체에 영향을 미치지 않음)
- 기술 스택 다양화 가능
- 향상된 유지보수성
- 독립적인 배포
- 확장성 강화
- 기술 다양성
마이크로 서비스 아키텍처 단점
- 운영복잡성
- 통신 오버헤드
- 개발 어려움
- 데이터 일관성 문제