ã¯ããã«
ããã«ã¡ã¯ãããã¯ãã¯ã¿ã¼ã§ããã¯ã¨ã³ãã¨ã³ã¸ãã¢ããã¦ããç§ã¨ç³ãã¾ãã
æ°è¦ãããã¯ãã®ããã¯ã¨ã³ãã§ãDDD (Domain-Driven Design) 㨠CQRS (Command Query Responsibility Segregation) ãçµã¿åãããã¢ã¼ããã¯ãã£ãæ¡ç¨ãã¾ããã
DDDã®æ¬ãè¨äºã¯ãEric EvansèãDomain-Driven Designããã実践ドメイン駆動設計ããªã©æ§ã ããã¾ããCQRSã«ã¤ãã¦ãMartin Fowleræ°ã®CQRSの解説記事ãªã©ãããã¾ããããããDDDã«CQRSãã©ãçµã¿è¾¼ãã§ãã£ããã¨ãã話ã¯ãã¾ãè¦ããã¾ããã
ãã®ç¹ã«ã¤ãã¦ä»¥åããæ å ±åéã試è¡é¯èª¤ãéãã¦ãã¾ããããä»åã®ãããã¯ãã§ããããç´å¾ã®ããå½¢ã§å®è£ ãã§ãã¾ããããã®è¨äºã§ã¯ãã®ãã¤ã³ãããç´¹ä»ãã¾ããç¹ã«CQRSãå ·ä½çã«å®è£ ãã¦ããApplication層ãä¸å¿ã«ãä»ã®å±¤ã¨ã®ãã¼ã¿ã®ããã¨ãã責ååæ ã«ã¤ãã¦è©³ãã説æãããã¨æãã¾ãã
ãã®è¨äºã®æ³å®èªè ã¨ã´ã¼ã«
ãã®è¨äºã¯ã以ä¸ã®ãããªæ¹ãæ³å®ãã¦ãã¾ãï¼
- DDDã®åºæ¬ï¼EntityãValue ObjectãRepositoryçã®æ¦å¿µï¼ã¯çè§£ãã¦ãã
- å®éã®ã³ã¼ãã§CQRSãã©ãå°å ¥ããã°ãããããããªã
è¨äºãèªã¿çµãã£ãã¨ãã«ãApplication層ã®Command/QueryHandlerã®å®è£ ããä»ã®å±¤ã¨ã®ãã¼ã¿ã®ããã¨ããå ·ä½çã«ã¤ã¡ã¼ã¸ã§ããããã«ãªããã¨ãã´ã¼ã«ã§ãã
CQRSã¨ã¯ä½ã
ã¾ãããã®è¨äºã§ã®CQRSã®å®ç¾©ãæç¢ºã«ãã¦ããã¾ãã
CQRSã¯ããã¼ã¿ã夿´ããæä½ï¼Commandï¼ã¨ããã¼ã¿ãèªã¿åãæä½ï¼Queryï¼ãåé¢ãããã¿ã¼ã³ã§ããé常ã®CRUDã§ã¯ãã¼ã¿ã¢ãã«ãèªã¿æ¸ãå ±éã§ãããCQRSã§ã¯ä»¥ä¸ã®ããã«åãã¾ãï¼
- Commandå´ï¼æ¸ãè¾¼ã¿ï¼: ãã¸ãã¹ã«ã¼ã«ã®æ¤è¨¼ãéè¦ãEntityãçµç±ãã¦ãã¼ã¿ãæ´æ°
- Queryå´ï¼èªã¿è¾¼ã¿ï¼: ããã©ã¼ãã³ã¹ã¨å©ä¾¿æ§ãéè¦ãæé©åãããã¯ã¨ãªã§ç´æ¥DTOã«ãããã³ã°
ãã®åé¢ã«ãããããããã®æä½ã«æé©ãªå®è£ ã鏿ã§ããããã«ãªãã¾ãã
å ¨ä½åï¼ã¬ã¤ã¤ã¼æ§æã®æ¦ç¥ã¨è²¬åã®å²ãå½ã¦
ä»åã®ãããã¯ãã¯ä¸ç¨®ã®ããã·ã¥ãã¼ãã·ã¹ãã ã§ããã¼ã¿ã®éè¨ã»å¯è¦åãè¡ãã»ããçµç¹ãã¦ã¼ã¶ã¼æ
å ±çã®ç»é²ãè¡ãã¾ãã
ã¬ã¤ã¤ã¼æ§æã¯ä»¥ä¸ã®5層ã¨ãã¾ããã
| 層å | 説æ |
|---|---|
| Presentation層 | â API ã¨ã³ããã¤ã³ãï¼èãå±¤ï¼ |
| UseCase層 | â ãã¸ãã¹ããã¼ + èªå¯å¶å¾¡ |
| Application層 | â Command/Query Handlerï¼ç´ç²ãªCRUDï¼ |
| Domain層 | â EntityãValue ObjectãRepository Interface |
| Infrastructure層 | â Repositoryå®è£ ãQuery Service |
å層ã®è²¬åãç°¡åã«æ´çãã¾ãã
Presentation層ã¯HTTPãªã¯ã¨ã¹ã/ã¬ã¹ãã³ã¹å¤æã®ã¿ãæ å½ãã¾ãããã¸ãã¹ãã¸ãã¯ã¯æããã¾ããã
UseCase層ã¯èªå¯ãã§ãã¯ããè¤æ°ã®Command/Queryãçµã¿åããããã¸ãã¹ããã¼ãæ±ãã¾ãã
Application層ã¯ç´ç²ãªCRUDæä½ã®ã¿ã§ãèªå¯å¦çã¯æã¡ã¾ããã
Domain層ã¯ãã¸ãã¹ã«ã¼ã«ã®ä¸æ ¸ãæ ããä»ã®å±¤ã«ä¾åãã¾ããã
Infrastructure層ã¯ãã¼ã¿ãã¼ã¹ãå¤é¨ãµã¼ãã¹ã¨ã®å®éã®ããã¨ããæ å½ãã¾ãã
Core層ãããã¾ãããDIã³ã³ãããå ±éè¨å®ãæ ãè£å©çãªå±¤ãªã®ã§æ¬ç¨¿ã§ã¯è©³ããæ±ãã¾ããã
ç¹ã«éè¦ãªã®ã¯UseCase層ã¨Application層ã®å¢çã§ããApplication層ã®Command/QueryHandlerã¯èªå¯å¦çãæãããç´ç²ã«ãã¡ã¤ã³ãã¸ãã¯ã«éä¸ãã¾ãã䏿¹ãèªå¯ãç£æ»ãã°ã¨ãã£ã横æçãªé¢å¿äºã¯UseCaseå±¤ã§æ±ãã¾ãã
ãã®è¨è¨ã«ããçç±ã¯ãå¥ãããã¯ãã§UseCase層ã¨ãã®ä¸ã®Service層ï¼ä»åã®Application層ã«ç¸å½ï¼ãåãã¦æåããçµé¨ããã£ãããã§ããUseCase層ã«CQRSã®Command/Queryãç´æ¥é ç½®ããã¨ãèªå¯å¦çã¨ãã¼ã¿æä½ã®ãã¸ãã¯ãæ··å¨ãã¦ãã¾ããããApplication層ã¨ãã¦åé¢ãã¾ããã
Application層ã«ãããCQRSå®è£
Application層ã§ã¯ãCommandï¼æ¸ãè¾¼ã¿ï¼ã¨Queryï¼èªã¿è¾¼ã¿ï¼ãæç¢ºã«åé¢ãã¦ãã¾ãã
Commandã®å®è£ ä¾ï¼çµç¹ã使ãã
ä¾ã¨ãã¦ãçµç¹ã使ããCommandHandlerãè¦ã¦ã¿ã¾ãããã以ä¸ã¯å®éã®ãããã¯ãã®ã³ã¼ããç°¡ç¥åãããµã³ãã«ã§ãã
class CreateOrganizationCommand(BaseModel): """çµç¹ä½æã³ãã³ã""" organization_id: OrganizationId name: OrganizationName # ... ãã®ä»ã®ãã£ã¼ã«ã class CreateOrganizationCommandResult(BaseModel): """çµç¹ä½æçµæ""" organization: Organization created: bool class CreateOrganizationCommandHandler( ICommandHandler[CreateOrganizationCommand, CreateOrganizationCommandResult] ): """çµç¹ä½æã³ãã³ããã³ãã©ã¼""" def __init__(self, organization_repository: IOrganizationRepository) -> None: self._organization_repository = organization_repository async def handle( self, command: CreateOrganizationCommand ) -> CreateOrganizationCommandResult: # 1. æ¢åãã§ã㯠if await self._organization_repository.exists(command.organization_id): raise EntityAlreadyExistsException(...) # 2. ãã¡ã¤ã³ã¢ãã«ã§ãã¸ãã¹ã«ã¼ã«æ¤è¨¼ organization = Organization.create( organization_id=command.organization_id, name=command.name, # ... ) # 3. æ°¸ç¶å await self._organization_repository.save(organization) return CreateOrganizationCommandResult( organization=organization, created=True, )
ãã®CommandHandlerã§æãéè¦ãªã®ã¯ãèªå¯å¦çãä¸åæããªãç¹ã§ããããã®çµç¹ã使ã§ããæ¨©éããããï¼ãã¨ãã£ããã§ãã¯ã¯UseCase層ã®ä»äºã§ãApplication層ã¯ç´ç²ã«ãçµç¹ã®ä½æãã¨ãããã¸ãã¹ãã¸ãã¯ã«éä¸ãã¦ãã¾ãã
å ·ä½çãªå¦çã®æµãã¯ãå ¥åã¨ãã¦Commandï¼å¿ è¦ãªãã¼ã¿ã®ã¿ï¼ãåãåããåºåã¨ãã¦CommandResultï¼å¦ççµæï¼ãè¿ãã¾ããå é¨ã§ã¯ããã¡ã¤ã³ã¢ãã«ã®Organization.create()ã使ã£ã¦ãã¸ãã¹ã«ã¼ã«æ¤è¨¼ãè¡ãï¼ä¾ãã°ãOrganizationNameã¨ããValue Objectã§çµç¹åã®é·ããå½¢å¼ããã§ãã¯ãã¦ãã¾ãï¼ãæå¾ã«Repositoryã§æ°¸ç¶åãã¾ãã
ãããããã¨ã§Handlerãã·ã³ãã«ã«ãªãããã¹ããæ¸ãããããªãã¾ããèªå¯ãæ°ã«ããå¿ è¦ããªããInfrastructure層ã®DBã»ãã·ã§ã³ã«ãä¾åããªããããã¢ãã¯ã®Repositoryãæ¸¡ãã ãã§åä½ãã¹ããã§ãã¾ããã
Queryã®å®è£ ä¾ï¼çµç¹ãåå¾ãã
次ã«ãçµç¹ãåå¾ããQueryHandlerã§ãã
class GetOrganizationQuery(BaseModel): """çµç¹åå¾ã¯ã¨ãª""" organization_id: OrganizationId class GetOrganizationQueryResult(BaseModel): """çµç¹åå¾çµæ""" organization: OrganizationDTO | None class GetOrganizationQueryHandler( IQueryHandler[GetOrganizationQuery, GetOrganizationQueryResult] ): """çµç¹åå¾ã¯ã¨ãªãã³ãã©ã¼""" def __init__(self, organization_repository: IOrganizationRepository) -> None: self._organization_repository = organization_repository async def handle(self, query: GetOrganizationQuery) -> GetOrganizationQueryResult: organization = await self._organization_repository.find_by_id( query.organization_id ) if organization is None: return GetOrganizationQueryResult(organization=None) # Entity â DTOã¸ã®å¤æ organization_dto = OrganizationDTO( organization_id=str(organization.organization_id.value), name=str(organization.name.value), created_at=organization.created_at, # ... ) return GetOrganizationQueryResult(organization=organization_dto)
QueryHandlerã§éè¦ãªã®ã¯ãEntityâDTOã®å¤æã§ããå ¥åã¨ãã¦Queryï¼æ¤ç´¢æ¡ä»¶ï¼ãåãåããåºåã¨ãã¦QueryResultï¼DTOå½¢å¼ã®ãã¼ã¿ï¼ãè¿ãã¾ãã責åã¯ãã¼ã¿åå¾ã¨DTO夿ã®ã¿ã§ãCommandå´ã®ãããªãã¸ãã¹ã«ã¼ã«æ¤è¨¼ã¯è¡ãã¾ããã
DTOã«å¤æããçç±ã¯ãPresentation層ã§ä½¿ããããå½¢ã«ããããã§ããEntityã¯ãã¸ãã¹ãã¸ãã¯ãæã¤éããªãã¸ã§ã¯ãã§ãããDTOã¯åãªããã¼ã¿è»¢éç¨ã®è»½ããªãã¸ã§ã¯ãã§ãããã®å¤æãApplication層ã§è¡ããã¨ã§ãPresentation層ã¯ã·ã³ãã«ã«ä¿ã¦ã¾ãã
ãã¼ã¿ã¢ãã«ã®ä½¿ãåã
å®è£ ãã¦ãã¦æãæ©ãã ã®ãããã©ã®ãã¼ã¿ã¢ãã«ãã©ãã§ä½¿ãããã§ããã
å½åãåãã¼ã¿ã¢ãã«ã®å½¹å²ã¯ âãªãã¨ãªãâ æ±ºã¾ã£ã¦ãããã®ã®ãå ·ä½çãªã«ã¼ã«ãããã¾ããã§ãããä¾ãã°ãDTOã®ä½¿ãåãããæ¦å¿µã®åé¢ãã§ãã¦ããªãã£ãããã¾ããã
æçµçã«ãå層ã®å¢çãæç¢ºã«ããããã以ä¸ã®ããã«ãã¼ã¿ã¢ãã«ãæ´çãã¾ããï¼
| ãã¼ã¿ã¢ãã« | å½¹å² | é ç½®å ´æ | å½åã®ç±æ¥ |
|---|---|---|---|
| Command/Query | ãªã¯ã¨ã¹ããã¼ã¿ï¼å ¥åï¼ | Application層 | CQRSã®æ¦å¿µãããã®ã¾ã¾ |
| CommandResult /QueryResult |
ã¬ã¹ãã³ã¹ãã¼ã¿ï¼åºåï¼ | Application層 | Commandã®çµæãQueryã®çµæã¨ããæç¢ºãªåå |
| Projection | Infrastructure âApplication層ã®ãã¼ã¿ |
Infrastructure層 | CQRSã®æç®ã§ä½¿ããã¦ããç¨èªï¼å¾è¿°ï¼ |
| DTO | Application âPresentation層ã®ãã¼ã¿ |
Application層 | ç¹ã«ä»ã®ååãæãã¤ããªãã£ã |
Projectionã¨ããååã«ã¤ãã¦è£è¶³ãã¾ããå½åã¯XXResultã¨ããååãæ¤è¨ãã¾ããããCommandResult/QueryResultã¨ååã被ã£ã¦ãã¾ããã¨ãããã¦Repositoryã®çµæã¨Query Serviceã®çµæã®ä¸¡æ¹ããããã©ã¡ãã®ååãåãããã¨ããè«äºãèµ·ãããã ã£ããã䏿¡ç¨ã«ãã¾ããã
CQRSã®æç®ã調ã¹ãã¨ãããèªã¿åãå´ã®ãã¼ã¿ã¢ãã«ã¨ãã¦ãProjectionãã¨ããç¨èªã使ããã¦ãããã¨ï¼参考1ã参考2ï¼ããããããã®ååãæ¡ç¨ãã¾ããã
ããããæç¢ºã«åãããã¨ã§ãå層ã®é¢å¿äºãæ··ãããªãããã«ã§ãã¦ãã¾ããç¹ã«ååä»ãã«ã¯è¦å´ãã¾ããããå½¹å²ãæç¢ºã«ãªã£ã¦ããã¯ã³ã¼ãã®è¦éããæ ¼æ®µã«è¯ããªãã¾ããã
UseCaseï¼Infrastructureï¼èªå¯ã¨ãã¼ã¿ã¢ã¯ã»ã¹ãã©ãæ¥ç¶ããã
Application層ã®Command/QueryHandlerã¯ç´ç²ãªCRUDæä½ã ããæ±ãã®ã§ãèªå¯å¦çã¯UseCase層ã§è¡ãã¾ãã
UseCaseã§ã®èªå¯çµ±åï¼Commandå®è¡åã«æ¨©éãã§ãã¯
UseCase層ã§ã¯ãApplication層ã®Handlerãã©ãããã¦èªå¯å¦çã追å ãã¾ããå®è£ ä¾ãè¦ã¦ã¿ã¾ãããã
class CreateOrganizationUseCase: """çµç¹ä½æUseCaseï¼èªå¯ä»ãï¼""" def __init__( self, permission_checker: PermissionChecker, create_organization_handler: CreateOrganizationCommandHandler, ): self._permission_checker = permission_checker self._create_organization_handler = create_organization_handler async def execute( self, request: CreateOrganizationRequest, user_claims: JWTClaims ) -> Organization: # 1. èªå¯ãã§ãã¯ï¼UseCase層ã®è²¬åï¼ await self._permission_checker.verify_role(user_claims, required_roles=["org-admin"]) # 2. RequestããCommandã¸ã®å¤æ command = CreateOrganizationCommand( organization_id=OrganizationId.generate(), name=OrganizationName(request.name), # ... ) # 3. Application層ã®Handlerãå®è¡ result = await self._create_organization_handler.handle(command) return result.organization
ãã®ããã«ãèªå¯ãã§ãã¯ã¨Commandå®è¡ãåé¢ãããã¨ã§ãããã¤ãã®ã¡ãªãããããã¾ãã
ã¾ããApplication層ã¯ãã¸ãã¹ãã¸ãã¯ã«éä¸ã§ãã¾ãããçµç¹ã使ãããã¨ãããã¡ã¤ã³ãã¸ãã¯ã«èªå¯å¦çãæ··ãããªãã®ã§ãã³ã¼ããèªã¿ããããªãã¾ãã
次ã«ãèªå¯ãã¸ãã¯ãä¸ç®æã«éç´ã§ãã¾ããæ¨©éãã§ãã¯ã®æ¹æ³ã夿´ãããã¨ããUseCase層ã ãä¿®æ£ããã°æ¸ã¿ã¾ãã
ããã¦ä½ããããã¹ããæ¸ãããããªãã¾ããApplication層ã¯ãã¸ãã¹ãã¸ãã¯ã®åä½ãã¹ãã«éä¸ã§ããUseCase層ã¯èªå¯ã®ãã¹ãã¨ãã¦åé¢ã§ãã¾ããã
èªå¯å¦çã®è¨è¨
èªå¯å¦çã®å®è£ ã«ã¤ãã¦ãä»åã®ãããã¯ãã§ã¯ç´°ãããã¼ã«è¨å®ãããã¯ã¨ã³ãå´ã§æ å½ãããã¨ã«ãã¾ãããããã«ãããããæè»ãªæ¨©é管çãå®ç¾ãã¦ãã¾ãã
Query Serviceã§ã®ãã¼ã¿å徿é©å
èªã¿åãå´ã«ããã¦ãè¤éãªã¯ã¨ãªã¯Infrastructure層ã®Query Serviceã§æé©åãã¾ãã
Query Serviceã¨ã¯ãæé©åãããã¯ã¨ãªãå®è¡ããããã®èªã¿åãå°ç¨ã®ãµã¼ãã¹ã§ããRepositoryãã¿ã¼ã³ã¨ã¯ç°ãªããè¤æ°ã®ãã¼ãã«ãJOINãã¦1åã®ã¯ã¨ãªã§å¿ è¦ãªãã¼ã¿ãåå¾ãããã¨ã«ç¹åãã¦ãã¾ãã
ä»åã®ãããã¯ãã¯ãããã·ã¥ãã¼ãã·ã¹ãã ã§ãããè¤éãªãã¼ã¿ã®éè¨ã»å¯è¦åãè¡ãã¾ããRepositoryãã¿ã¼ã³ã ãã ã¨å¤§éã®ã¯ã¨ãªãçºçããããã©ã¼ãã³ã¹ãä½ä¸ããå¯è½æ§ããããããCQRSãæ¡ç¨ããèªã¿åãå´ã§ã¯Query Serviceã使ã£ã¦1åã®ã¯ã¨ãªã§å¹ççã«ãã¼ã¿ãåå¾ãã¦ãã¾ãã
å ·ä½ä¾ãè¦ã¦ã¿ã¾ãããï¼å®éã®ãããã¯ãã®ã³ã¼ããç°¡ç¥åãããã®ã§ãï¼ï¼
class OrganizationQueryService: """çµç¹ã¯ã¨ãªãµã¼ãã¹ï¼Infrastructure層ï¼""" async def get_organization_with_stats( self, organization_id: str ) -> OrganizationProjection | None: # æé©åãããJOINã¯ã¨ãªã§ä¸åº¦ã«åå¾ query = select( OrganizationModel.id, OrganizationModel.name, func.count(MemberModel.id).label('member_count'), func.count(ItemModel.id).label('item_count'), ).select_from( OrganizationModel ).outerjoin( MemberModel ).outerjoin( ItemModel ).where( OrganizationModel.id == organization_id ).group_by(OrganizationModel.id) result = await self._session.execute(query) row = result.first() if not row: return None # Projectionã¨ãã¦è¿ãï¼DTO夿ã¯QueryHandlerã§ï¼ return OrganizationProjection( id=row.id, name=row.name, member_count=row.member_count or 0, item_count=row.item_count or 0, )
ããã§ã®ãã¤ã³ãã¯ãQuery ServiceãProjectionãè¿ãç¹ã§ãããã¼ã¿ããã¼ã¯æ¬¡ã®ããã«ãªãã¾ãï¼
QueryService(Projection) â QueryHandler(DTO) â UseCase â API(Response)
Projectionã¯Infrastructure層ããApplication層ã¸ã®ãã¼ã¿ã¢ãã«ãDTOã¯Application層ããPresentation層ã¸ã®ãã¼ã¿ã¢ãã«ã¨ãå½¹å²ãåããã¦ãã¾ãã
ãã®è¨è¨ã«ããã®ã¯ãInfrastructure層ã«ãã¡ã¤ã³ç¥èãæ¼ãããªãããã§ããããQuery ServiceãDTOãç´æ¥è¿ãã¨ãInfrastructure層ãPresentation層ã®é½åï¼ã©ããªå½¢å¼ã§ãã¼ã¿ãè¿ããï¼ãç¥ãå¿ è¦ããããä¾åæ¹åãé転ãã¦ãã¾ãã¾ããProjectionã¨ããä¸éãã¼ã¿ã¢ãã«ãæããã¨ã§ãå層ã®è²¬åãæç¢ºã«ä¿ã¦ã¦ãã¾ãã
Query Serviceã¨Repositoryã®ä½¿ãåã
å ·ä½çãªå¤æåºæºã¨ãã¦ãè¤æ°åJOINãå¿ è¦ãã©ãããè¦ã¦ãã¾ãã
åç´ãªåå¾ã§ããã°Repositoryã使ãã¾ãããçµç¹ã«ç´ã¥ãè¤æ°ã®é¢é£ãã¼ã¿ãåæã«åå¾ããå ´åãªã©ãè¤æ°ã®ãã¼ãã«ãJOINããå¿ è¦ãããå ´åã¯Query Serviceã使ãã¾ããããã«ãããã¯ã¨ãªå®è¡åæ°ãæããããã©ã¼ãã³ã¹ãåä¸ããã¦ãã¾ãã
Presentation層ã¨Coreå±¤ã®æ±ã
Presentation層ï¼UseCaseã«å§è²ããã ãã®èã層
APIã¨ã³ããã¤ã³ãã¯æ¬å½ã«èããUseCaseã«å¦çãå§è²ããã ãã§ãã
@router.post("", response_model=CreateOrganizationResponse, status_code=201) @require_roles(["org-admin"]) async def create_organization( request: CreateOrganizationRequest, create_organization_use_case: Annotated[ CreateOrganizationUseCase, Depends(get_create_organization_use_case) ], user_claims: Annotated[JWTClaims, Depends(get_current_user)], ) -> CreateOrganizationResponse: """çµç¹ä½æã¨ã³ããã¤ã³ã""" try: # UseCaseã«å¦çãå§è² organization = await create_organization_use_case.execute(request, user_claims) # ã¬ã¹ãã³ã¹ã«å¤æãã¦è¿ãã ã return CreateOrganizationResponse( organization_id=str(organization.organization_id.value), name=str(organization.name.value), # ... ) except ValidationException: # ã¨ã©ã¼ãã³ããªã³ã°ï¼è©³ç´°ã¯çç¥ï¼ raise
ã¨ã³ããã¤ã³ãã§ã¯ãã¸ãã¹ãã¸ãã¯ãæãããHTTPã®ä¸çã¨ã¢ããªã±ã¼ã·ã§ã³ã®ä¸çãç¹ã責åã ãã«å¾¹ãã¦ãã¾ããå®éã®ã³ã¼ããè¦ã¦ããUseCaseã®å®è¡çµæãResponseã«å¤æããä¾å¤ãHTTPã¹ãã¼ã¿ã¹ã³ã¼ãã«å¤æãã¦ããã ãã§ãã
ãã®è¨è¨ã«ãã¦ããã£ãã®ã¯ãã¨ã³ããã¤ã³ãã®ãã¹ããã·ã³ãã«ã«ãªã£ããã¨ã§ããHTTPãªã¯ã¨ã¹ãã®å½¢å¼ãæ£ãããã ãããã¹ãããã°ããããã¸ãã¹ãã¸ãã¯ã®ãã¹ãã¯UseCase層ã§å®çµãã¾ãã
Core層
Core層ã¯DI ContainerãJWTæ¤è¨¼ã¨ãã£ãå ±éæ©è½ãæä¾ãã¦ãã¾ãããã¢ã¼ããã¯ãã£ã®ä¸å¿ã§ã¯ãªãã®ã§æ¬ç¨¿ã§ã¯è©³ãã触ãã¾ãããéè¦ãªã®ã¯ãå層ã®è²¬åãæç¢ºã«åãããã¨ã§ãã
ã¾ã¨ãï¼å®éã«å°å ¥ãã¦ã¿ã¦æããã¡ãªãã
DDD+CQRSãå®éã®ãããã¯ãã«å°å ¥ãã¦ã¿ã¦ã以ä¸ã®ã¡ãªãããæãã¾ããã
ã¾ããèªå¯ãã¸ãã¯ã®æç¢ºåã§ããUseCase層ã«èªå¯å¦çãéç´ãããã¨ã§ãã誰ãä½ã«ã¢ã¯ã»ã¹ã§ãããããä¸ç®ã§ãããããã«ãªãã¾ããã
次ã«ããã¹ãã®å®¹ææ§ã§ããApplication層ã®Handlerãã·ã³ãã«ãªã®ã§ãåä½ãã¹ããæ¸ãããããªãã¾ãããèªå¯å¦çã¨åé¢ããã¦ããããããã¸ãã¹ãã¸ãã¯ã®ãã¹ãã«éä¸ã§ãã¾ããã¾ããInfrastructure層ã«ä¾åããªããããDBã»ãã·ã§ã³ãç¨æããå¿ è¦ãããã¾ããã
ããã¦ãä¿å®æ§ã®åä¸ã§ããå層ã®è²¬åãæç¢ºãªã®ã§ã夿´ã®å½±é¿ç¯å²ãäºæ¸¬ãããããã³ã¼ãã®è¦éããè¯ããªãã¾ãããæ°ããã¡ã³ãã¼ãã¸ã§ã¤ã³ããã¨ãããããã®æ©è½ã¯ã©ããè¦ãã°ããï¼ãã¨ãã質åã«æç¢ºã«çããããããã«ãªã£ã¦ãã¾ãã
ç¹ã«Application層ã¨UseCase層ãåãããã¨ã§ããã¸ãã¹ãã¸ãã¯ã¨èªå¯å¦çãæ··ããããããããã«éä¸ã§ããããã«ãªãã¾ãããå½åã¯ã層ãå¤ããã¦è¤éã§ã¯ï¼ãã¨å¿é ããã®ã§ãããå®è£ ãé²ãããã¡ã«æç¢ºãªã«ã¼ã«ãæ´åããã責åãæç¢ºãªåããããã·ã³ãã«ã«æãã¦ãã¾ãã
DDDãCQRSãå¦ç¿ã³ã¹ãã¯é«ãã§ãããå®éã«æãåããã¦è¨è¨ãã¦ã¿ãã¨ããã®ä¾¡å¤ã宿ã§ãã¾ãããã®è¨äºããããããDDD+CQRSãå°å ¥ãããã¨ãã¦ããæ¹ã®åèã«ãªãã°å¹¸ãã§ãã

æ¸ãã人ï¼ç§