
Microservice 구현 (with EDA,Hexagonal, DDD)
₩99,000
중급이상 / MSA, DDD, hexagonal-architecture
4.2
(18)
도메인 주도 설계, 헥사고널 아키텍처, 이벤트 기반 아키텍처를 모두 적용한 마이크로서비스 개발 과정을 보여줍니다.
중급이상
MSA, DDD, hexagonal-architecture
현 국내 SI업체 소프트웨어 엔지니어(SA,AA)
다수의 대규모 차세대 프로젝트 개발방법론 및 설계방법 리딩
명지대, 서울과학기술대 클라우드,SW과목 강의
SK C&C,한국정보기술연구원(kitri), LG전자 MSA과정 강의
멀티캠퍼스, 한국표준협회, 한국품질협회 MSA 과정 멘토링,스파로스아카데미 웹개발 과정 멘토링
전문분야 : 개발방법론, 소프트웨어 아키텍처/설계/개발 기법
22년 , 위키북스 "도메인주도로 시작하는 마이크로서비스 개발", 저자
국가평생교육진흥원, K-MOOC "Microservice 설계 및 구현 " 강좌 개발 및 강의
Microservice 구현 (with EDA,Hexagonal, DDD)
₩99,000
중급이상 / MSA, DDD, hexagonal-architecture
4.2
(18)
도메인 주도 설계, 헥사고널 아키텍처, 이벤트 기반 아키텍처를 모두 적용한 마이크로서비스 개발 과정을 보여줍니다.
중급이상
MSA, DDD, hexagonal-architecture
Microservice 설계(with EventStorming,DDD)
₩99,000
중급이상 / DDD, MSA, 아키텍처
4.6
(44)
마이크로서비스 설계를 위한 도메인 주도 설계(Domain Driven Design)를 쉽게 설명하고, 실제로 활용하기 위한 구체적인 실천 방법을 소개합니다.
중급이상
DDD, MSA, 아키텍처
Microservice 이해 (with MSA패턴)
₩99,000
중급이상 / MSA, 아키텍처
4.7
(65)
클라우드 분야에서 가장 Hot한 키워드인 Microservice Architecture (MSA)의 전반적인 배경, 다양한 아키텍처 패턴,애플리케이션 유형 , 레거시 전환방법 등을 현장의 목소리로 전달합니다.
중급이상
MSA, 아키텍처
질문&답변
Aggregate 하위에 꼬리를 무는 Entity 는?
안녕하세요 강의자 한정헌입니다.domain을 구현할때 이런 중첩 계층화된 모델은 도메인 모델에서 바람직한 구조는 아닌 것 같네요.즉 도메인 모델의 한 단위가 되는 어그리게이트를 모델링 할때, 여러개의 중첩적인 엔티티를 최대한 가지지 않게 설계해야 합니다.(어그리게이트 에는 개인적으로 한개 정도의 엔티티 설계가 적정하다 생각합니다.)그런 구조를 피하기 위해 다음과 같이 진행합니다. 1. Aggregate Root 기준으로 설계DDD에서는 한 Aggregate Root(Aggregate의 최상위 엔티티)에서 다른 Aggregate Root를 직접 참조하지 않도록 권장합니다.즉, A -> B -> C 형태가 아니라 A가 B의 ID만 갖고, B가 C의 ID만 가지도록 설계하는 것이 일반적입니다.2. Lazy Loading을 도메인 레이어에서 직접 구현JPA의 Lazy Loading을 사용하지 않는다면, 직접 데이터를 가져오는 방식으로 구현할 수 있습니다.예를 들어, A에서 B를 가져올 때, B의 리스트를 로딩하는 것이 아니라 BRepository를 통해 필요할 때 조회하도록 만들 수 있습니다.class A { private List bIds; // ID만 저장 public List getBs(BRepository bRepository) { return bRepository.findAllByIds(bIds); } } 이렇게 하면 A가 B를 직접 포함하지 않고 ID만 저장하여 필요할 때만 데이터를 가져올 수 있습니다. 답변이 되었기를 바라며, 감사합니다.
질문&답변
헥사곤 아키텍쳐 관련하여 문의드립니다.
안녕하세요. 강의자 한정헌입니다.헥사고널 아키텍처는 포트 엔 어댑터 패턴을 제안한 alistair cockburn를 기반으로 다양한 형태의 모습으로 소개되고 있습니다.언급하신 모델은 인터넷에 일반적으로 많이 퍼져 있으나 소프트웨어 아키텍처가 다양한 변종이 있고 상황에 따라 여러 모델이 있을 수 있다 생각합니다.제가 강의 시 참고한 모델은 다비 비에이라의 '헥사고날 아키텍처 설계와 구현'이라는 서적의 모델입니다.헥사고널 아키텍처 모델을 3개의 헥사고널(도메인,애플리케이션,프레임워크)로 나누고 각각의 의미를 부여했는데 애플리케이션 헥사곤의 요소를 유스케이스-인풋포트-아웃풋포트로 구현하고 유스케이스를 인터페이스로 정의하고 인풋포트를 구현체로 활용했습니다.다비 비에이라의 방식은 유스케이스를 단순한 구현체의 역할 보다는이바 야콘슨의 '유스케이스 시나리오, '유스케이스 명세' 의 개념으로 파악한 것으로 애플리케이션 헥사곤이 갖는 의미 즉 '시스템이 정의 한 목표를 달성하기 위해 함께 동작하는 일련의 행위의 집합'를 구현한다. 를 강조하기 위해 유스케이스로 이러한 애플리케이션이 제공할 기능(일련의 행위 집합으로 시나리오 형태임)를 먼저 인터페이스로 정의한 것이라 생각합니다.즉 간단히 말하면, 애플리케이션 헥사곤에서 가장 중요한 것은 도메인 헥사곤이 가진 비지니스 여러 개념을 복합적으로 활용하여 비지니스 목적에 맞는 시나리오를 구현하는 것인데, 그걸 명확히 표현한 방식이 이바 야콥슨 '유스케이스 명세'라는 방식이고, 이것을 강조한 구조라고 생각하면 됩니다.저는 이 방식이 헥사고널 아키텍처 모델에 '유스케이스' 라는 개념을 설명하는데 타당 하다고 생각하여 이 방식으로 강의를 구성하였습니다.물론 Management Uiti님이 제시하신 구조로 헥사고널 아키텍처 구조를 잡아도 타당하다고 생각합니다. Management Uiti님이 제시하신 구조는 비지니스와 기술을 어떻게 분리하여 어떻게 유연하게 할 것 인가? 에 초점을 맞췄다면 , 비에이라의 헥사고널 아키텍처는 한 발 더 나아가 그렇다면 비지니스 개념 과 활동을 어떻게 구조화 할 것인가를 좀 더 생각한 결과라 판단됩니다.답변이 되었기를 바라며 감사합니다.
질문&답변
다른 BC 또는 마이크로서비스 담당 정보를 어떻게 이용하나요?
강의자입니다.^ ^ AI가 이미 답변을 드렸네요. AI 가 말한바와 같이 API,이벤트기반 통신,데이터 복제로 해결할 수 있으며, 의외로 백엔드 서비스간의 연관관계보다는 프론트엔드 단의 정보를 가져갈 수도 있습니다.예를 들면 대여서비스가 필요한 도서정보와 사용자정보를 프론트에 이미 조회된 정보를 가져갈 수 있습니다. 물론 백엔드 대여 서비스에서 실제 사용자가 존재하는지? 와 도서가 대여가능한지에 대한 검증은 필요합니다.이후 강의를 더 듣다 보시면 더 깊은 이해가 가능하실 것이라 판단됩니다. 감사합니다.
질문&답변
VO 클래스의 불변 필드 선언을 하지 않으신 이유?
강의자 한정헌입니다.답변드리면 도메인 주도 설계에서 vo를 설계할 때 불변성을 유지하는 것이 매우 중요한 원칙 중 하나입니다. 따라서 private final로 필드를 선언하여 vo 내부 상태가 변경되지 않게 안전하게 함 좋은 설계 방법입니다. 하지만 이렇게 하면 내부에서 사용하는 객체,List,Map등이 있다면 이 또한 모두 불변으로 유지해야 하고 외부 객체 연동 시 불변성을 유지하는 코드 작성 등 객체 내부의 복잡성이 증가하고 추가 적인 처리 코드 작업이 필요합니다. 따라서 불변성을 유지하는 것의 중요성과 그것을 유지하기 위한 복잡성 추가 등을 트레이드 오프 할 필요성이 있습니다.본 강의에서는 이러한 점을 고려하여 ,특히 가독성 측면에서 final처리하지 않는 것이 좋다고 생각했습니다. 그리고 rentalItem 은 이전 모델링 강의 에서 VO 로 선언했으나 overDued의 값이 변경됨으로 불변성을 잃음으로서 엔티티로 다시 개념 정의 한 부분입니다. 그런데 엔티티임에도 @Entity 처리를 안 한점을 지적 주셨는데 JPA의 @Entity와 도메인 주도 설계(DDD, Domain-Driven Design)에서의 엔티티(Entity)는 서로 다른 맥락에서 사용되는 개념입니다. 두 개념 모두 "엔티티"라는 용어를 사용하지만, 목적과 초점이 다릅니다.DDD의 엔티티 상태와 동작 : 데이터뿐만 아니라 행위(메서드)를 포함식별성(식별자을 기준으로 동일성 판단) JPA의 엔티티데이터베이스와 동기화의 목적데이터베이스 테이블과 매핑됨을 의미반드시 기본키가 존재해야 함.(@id)물론 현실적으로 데이터베이스와 매핑시 JPA의 @Entity와 DDD의 엔티티는 함께 사용되는 경우가 많습니다. 그렇지만 반드시 그래야만 하는 것도 아닙니다.즉 비지니스 로직을 처리하기 위한 도메인 모델링 과 데이터 처리를 하기위한 or매핑과는 전혀 다른 영역이라 생각합니다.따라서 RentalItem의 경우 초기에 도메인 모델링 관점에서 행위가 없기 때문에 vo로 설계했으나 overdued등의 값이 변경되어 불변성이 깨진다 판단하여 엔티티로 개념을 변경한 것이지만 역시 vo의 성격이 강하기 때문에 vo처럼 처리 했다고 생각하시면 될 것 같습니다.
질문&답변
RentalCard 의 calculateLateFee 메서드 구현이 잘못된 것 같습니다.
tkwoo님 안녕하세요. 강의자입니다.네 지적하신 점이 맞습니다. 제가 코드의 결함을 인지하고 제공하는 소스코드에는 이후 변경하였는데, 동영상 상에는 공지를 제대로 하지 못했네요. 죄송합니다. 다시 확인해서 공지를 하도록 하겠습니다. 지적 감사합니다.
질문&답변
20분정도에 말씀 하신 내용 질문 있습니다.
움 아키텍처를 설명하기 위해 개념적인 용어들을 사용했지만 이런 기능은 카프카 매커니즘이 이미 제공하고 있습니다. 예를 들어 간단히 구현해 보면 다음과 같습니다. 주문 서비스가 새로운 주문을 생성하면, 이 주문 정보를 Kafka에 이벤트로 보내고, 주문 이력 서비스가 이 이벤트를 읽어 데이터베이스에 주문 이력을 저장한 후, 메시지가 성공적으로 처리되었음을 확인하고 Kafka에서 해당 메시지를 제거하는 방식으로 구현할 수 있습니다.아래는 이 과정을 간단한 샘플 코드와 함께 설명하겠습니다.1. Kafka에 주문 이벤트 보내기 (주문 서비스)주문 서비스가 주문 정보를 Kafka에 보내는 과정입니다. Python의 kafka-python 라이브러리를 사용하여 Kafka에 메시지를 보내는 예제입니다.from kafka import KafkaProducer import json # Kafka 프로듀서 설정 producer = KafkaProducer( bootstrap_servers='localhost:9092', value_serializer=lambda v: json.dumps(v).encode('utf-8') ) # 주문 데이터 order = { 'order_id': '12345', 'customer_id': '67890', 'amount': 100.0 } # Kafka 토픽에 주문 이벤트 전송 producer.send('order-topic', order) producer.flush()2. 주문 이력 저장 및 Kafka 메시지 삭제 (주문 이력 서비스)주문 이력 서비스가 Kafka에서 메시지를 읽어 데이터베이스에 저장하고, 저장이 완료되면 Kafka에서 해당 메시지를 제거합니다. Python의 kafka-python과 mysql-connector-python을 사용한 예제입니다.from kafka import KafkaConsumer, KafkaProducer import mysql.connector import json # Kafka 컨슈머 설정 consumer = KafkaConsumer( 'order-topic', bootstrap_servers='localhost:9092', auto_offset_reset='earliest', group_id='order-history-group', value_deserializer=lambda x: json.loads(x.decode('utf-8')) ) # Kafka 프로듀서 설정 producer = KafkaProducer( bootstrap_servers='localhost:9092', value_serializer=lambda v: json.dumps(v).encode('utf-8') ) # MySQL 데이터베이스 설정 db_conn = mysql.connector.connect( host='localhost', user='youruser', password='yourpassword', database='yourdatabase' ) cursor = db_conn.cursor() # Kafka 메시지 처리 for message in consumer: order = message.value order_id = order['order_id'] customer_id = order['customer_id'] amount = order['amount'] # 주문 이력을 데이터베이스에 저장 cursor.execute( "INSERT INTO OrderHistory (order_id, customer_id, amount) VALUES (%s, %s, %s)", (order_id, customer_id, amount) ) db_conn.commit() # 메시지 처리가 완료된 후 Kafka에서 메시지 삭제 (offset 커밋) consumer.commit() # 메시지 전송 상태를 확인하고 로그 기록 또는 다른 작업 수행 print(f"Order {order_id} processed and saved to database.") 코드 복사요약주문 서비스: 주문을 Kafka 토픽에 메시지로 전송합니다.주문 이력 서비스:Kafka에서 메시지를 읽어 데이터베이스에 주문 이력을 저장합니다.메시지를 처리한 후 Kafka의 오프셋을 커밋하여 메시지가 더 이상 처리되지 않도록 합니다.엄밀히 말하면 Kafka에서 오프셋(offset)은 특정 파티션 내에서 메시지의 위치를 나타냅니다. 즉 소비자가 메시지를 처리한 후, Kafka의 컨슈머 그룹은 해당 메시지가 성공적으로 처리되었다는 것을 나타내기 위해 오프셋을 커밋합니다. 오프셋 커밋은 Kafka가 메시지를 어느 지점까지 읽었는지를 기록합니다. 즉, 컨슈머가 다음에 재시작될 때, 마지막으로 커밋된 오프셋부터 메시지를 읽기 시작합니다. 따라서 한번 전달된 메시지가 다시 전달되지 않음을 보장합니다. 그리고 카프카의 메시지는 카프카 로그 보존기간에 따라 자동으로 삭제되게 하면 됩니다.
질문&답변
CQRS 6분정도 강의 질문드립니다.
안녕하세요. 강의자 입니다.여기서 이벤트 핸들러는 스프링 이벤트 핸드러 같은 구체적인 기술을 애길한 것은 아니고요. 개념적인 의미로 말씀 드린겁니다. cqrs가 명령( CUD)와 조회( R)를 분리하여 효율성을 높이는 패턴인데요. 예를 들면 주문 서비스가 커맨드 서비스 역할을 수행하고 주문이력 서비스가 조회서비스를 수행한다면, 각기 서비스가 분리되어 있기 때문에 주문이 입력되고, 주문이력이 입력되는 트랜젝션은 분리되기 때문에 분산 트랜젝션이 수행되어 합니다. 이 경우 2개 서비스의 정합성을 맞춰주기 위해 주문 서비스에서 주문 입력 트랜젝션 시 함께 비동기 이벤트를 발생시켜서 주문 이력 서비스에 주문이 들어왔다는 것을 알리는 것이죠. 여기서 주문 이력 서비스의 이벤트 핸들러는 이벤트가 들어왔다는 것을 알아채는 개념적인 기능를 설명하고 있는 겁니다. 여러 가지 기술로 구현 가능할 수 있죠. 주문이력서비스에서는 이벤트 핸들러를 통해 주문이 이벤트를 식별한 뒤 주문 이력 서비스에 주문 이력을 생성하면 주문서비스와 정합성 이 맞게 되는 거죠.
질문&답변
질문드립니다,
강의자 한정헌입니다. 답변 드리면 다음과 같습니다.먼저 개념 정의부터 명확히 하면, 노드 및 컨테이너: 노드는 컨테이너가 실행되는 물리적 또는 가상 머신입니다. Kubernetes 클러스터의 각 노드는 여러 컨테이너를 호스팅할 수 있습니다. 따라서 3개의 노드와 8개의 컨테이너가 있는 경우 해당 컨테이너는 Kubernetes 스케줄러의 결정에 따라 3개 노드에 걸쳐 예약됩니다. 스케줄링: Kubernetes 스케줄러는 노드에 컨테이너(Pod로 패키징됨)를 배치하는 일을 담당합니다. 이는 taints , tolerations, affinity 규칙과 같은 다양한 요소를 기반으로 수행됩니다. 목표는 로드 균형을 맞추고 사용 가능한 리소스를 효율적으로 사용하는 것입니다. 따라서 특정 제약 조건이나 선호도 규칙이 없다고 가정하면 8개의 컨테이너(각 컨테이너가 자체 포드에서 실행된다고 가정)가 3개 노드에 배포됩니다. 그렇지만 분포가 고르지 않을 수도 있습니다. 예를 들어노드 1에는 포드가 3개 ,노드 2에는 포드가 3개 , 노드 3에는 포드가 2개 있을 수 있습니다. 요약하면 Kubernetes는 기본적으로 컨테이너를 노드 전체에 균등하게 나누지 않습니다. 대신 리소스 가용성 및 기타 요소를 기반으로 컨테이너를 예약합니다. 배포는 사용자가 설정한 다양한 구성 및 제약 조건의 영향을 받을 수 있습니다. Spring Cloud API Gateway 앞에서 NGINX를 Ingress 컨트롤러로 사용하는 경우 말씀하신 바대로네트워크 지연 가능성이 있을 수 있으나 매우 경미할 것 같네요. 이를 이중 프록시 레이어로 구성한다고 하는데요. 이런 경우에는 다음과 같이 역할을 줄 수 있겠죠. NGINX 수신 컨트롤러: Kubernetes 클러스터로 들어오는 외부 트래픽을 처리합니다. SSL 종료, 호스트 이름 또는 경로 기반 라우팅과 같은 작업을 수행하고 로드 밸런싱도 처리할 수 있습니다.Spring Cloud API 게이트웨이: 클러스터 내에서 작동하며 라우팅, 로드 밸런싱은 물론 인증, 속도 제한 등과 같은 추가 기능을 제공합니다. 이런 경우 각 계층은 추가 처리 및 네트워크 홉으로 인해 약간의 오버헤드 및 잠재적으로 대기 시간이 증가할 수 있습니다. 그렇지만 이런 아키텍처 결정 전에 우선NGINX와 Spring Cloud API 게이트웨이가 모두 필요한지 고민할 필요가 있을 것 같네요. 또 이런 결정시에는 각 요소의 아래와 같은 장단점을 고려해야 할 것 같네요. NGINX: 클러스터 가장자리에서 트래픽 라우팅 및 로드 밸런싱을 처리하는 데 매우 효과적 Spring Cloud API Gateway: 동적 라우팅, 속도 제한, 서비스 간 통신과 같은 고급 기능을 제공. 네 더 많은 물리적 서버 노드를 추가하여 Kubernetes 클러스터를 확장하는 것은 용량과 복원력을 높이는 강력한 방법이 될 수 있습니다 , 그렇지만 k8s 와 같은 경우 수평형 Pod Autoscaling 를 우선 고려하고 이것이 한계에 도달할 경우 Cluster Autoscaler를 구현하여 단계적으로 Pod 및 노드 수를 동적으로 조정하는 것이 일반적인 방법입니다. 또 Pod Autoscaling 를 고려하여 더 크거나 더 강력한 노드를 추가하는 것이 작은 노드를 많이 추가하는 것보다 더 효과적일 수 있습니다. 당연히 private 망에서도 k8s를 구성할 수 있습니다.예 로컬에 k8s 구성하는 경우 다음과 같이 구성 가능합니다. 개발/테스트: 노드 1개(마스터 및 작업자 역할이 모두 포함된 단일 노드 설정) ex) Minikube기본 프로덕션: 마스터 노드 1개 + 작업자 노드 1개(고가용성 부족으로 인해 프로덕션에는 적합하지 않음)권장 프로덕션: 마스터 노드 3개 + 작업자 노드 2개(고가용성 및 내결함성을 위해)
질문&답변
레어어드 아케텍처 스타일 질문드립니다.
네 mvc모델에서 j2ee패턴의 dto 나 vo가 모델의 역할을 수행하는 거죠.즉 레이어드 아키텍처 스타일을 논하면서 mvc모델과 같은 개념으로 이해하는 분들이 많아서 언급한 내용이고요. 굳이 mvc모델을 레이어드 아키텍처와 매핑해보면 프리젠테이션 레이어의 역할과 매핑됩니다.그리고 두번째 질문에 답변을 드리면, 데이터 엑세스 계층은 제가 레이어드 아키텍처 예를 들며, 4개층 (프리젠테이션,비지니스,퍼시스턴스,데이터베이스) 이렇게 정의했는데 이건 개별 회사 및 시스템 마다 다를 수 있습니다. 용어도 다를 수 있고요. 어떤 프로젝트 에서는 (퍼블리싱,서비스,비지니스로직,데이터엑세스)이런식으로 구분하기도 합니다. 그렇지만 보통 데이터 엑세스 계증은 퍼스시턴스 계층과 같은 용어로 사용됩니다. 감사합니다.
질문&답변
UserCase가 많은데... 이유?
네 강의자 한정헌입니다.말씀하신 바대로 헥사고널 아키텍처에서도 예를 들면 CUD단위로 하나의 유스케이스 인터페이스로 묶고 이를 구현하는 입력포트도 하나의 클래스로 작성할 수 있습니다. 처음에 간단했던 cud야 괜찮겠지만 비지니스가 점점 복잡해지면 유지보수가 거듭되면서 이 클래스가 점점 비대해질 가능성이 있습니다. 그래서 저는 기능 단위로 유스케이스와 입력포트를 분리하는 방법을 선호합니다. 유스케이스 단위로 클래스 생성하는 방식에 대해서는 클린코드의 저자 로버트 c 마틴이 ‘ 소리치는 아키텍처(코드의 명칭을 통해 그 의도롤 소리치게 하자.)’라고도 언급하며 강조를 하기도 했습니다. 왜냐면 이렇게 했을 경우 코드명으로 그 의도를 바로 식별할 수 있기 때문이죠. 즉 클래스 명만 보고 어떠한 유스케이스인지 쉽게 인지 가능하기 때문에 테스트 및 유지보수성 높아 질수 있음을 강조했다고 생각합니다.감사합니다.
han jeong heon님의 소개 - 인프런