Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AIによるイベントストーミング図からのコード生成 / AI-powered code g...

Avatar for nrs nrs
January 09, 2026

AIによるイベントストーミング図からのコード生成 / AI-powered code generation from Event Storming diagrams

Avatar for nrs

nrs

January 09, 2026
Tweet

More Decks by nrs

Other Decks in Programming

Transcript

  1. 2

  2.  @Operation(summary = "Creating a new doc.") @PostMapping @ResponseStatus(HttpStatus.CREATED) public

    DocsPostResponse post(@Validated @RequestBody DocsPostRequest request) { var command = new DocCreate(new DocId(), request.body()); DocId docId = commandGateway.sendAndWait(command); return new DocsPostResponse(docId.value()); }
  3.  @Aggregate public class DocAggregate extends AbstractAggregate<Doc, DocId, DocEvent> {

    @Override protected DocId getAggregateRootId(Doc aggregate) { if (aggregate != null) { return aggregate.docId(); } else { return null; } } public DocAggregate() { } @CommandHandler public DocAggregate(DocCreate command) { var event = Doc.create(command.docId(), command.body()); apply(event); } @CommandHandler public void handle(DocUpdate command) { apply(it -> it.update(command.body())); } }
  4.  public record Doc( DocId docId, String body ) implements

    EventDrivenAggregateRoot<DocEvent> { public static DocCreated create(DocId docId, String body) { return new DocCreated(docId, body); } public static Doc applyEvent(DocCreated event) { return new Doc(event.docId(), event.body()); } public DocUpdated update(String body) { return new DocUpdated(docId, body); } @Override public EventDrivenAggregateRoot<DocEvent> applyEvent(DocEvent event) { return switch (event) { case DocCreated docCreated -> new Doc(docCreated.docId(), docCreated.body()); case DocUpdated docUpdated -> new Doc(this.docId, docUpdated.body()); default -> throw new IllegalStateException("Unexpected value: " + event); }; } }
  5.  @GetMapping("{docsId}") public DocsGetResponse get(@PathVariable UUID docsId) throws ExecutionException, InterruptedException

    { var query = new GetDoc(docsId); var result = queryGateway.query(query, GetDocResult.class).get(); var docDataModel = result.docDataModel().orElseThrow(NotFoundException::new); return new DocsGetResponse(docsId, docDataModel.getBody(), docDataModel.getEffectiveCount()); }
  6.  @Service public record DocQueryService(QueryGateway queryGateway, DocRepository repository) { @QueryHandler

    public GetDocResult handle(GetDoc query) { return new GetDocResult(repository.findById(query.docId().toString())); } }
  7.  @Component public class DocProjection { private final DocRepository repository;

    public DocProjection(DocRepository repository) { this.repository = repository; } @EventHandler public void on(DocCreated event) { var doc = new DocDataModel(); doc.setDocId(event.docId().asString()); doc.setBody(event.body()); repository.save(doc); } @EventHandler public void on(DocUpdated event) { var doc = repository.findById(event.docId().asString()).orElseThrow(); doc.setBody(event.body()); repository.save(doc); } : }
  8.  @EventHandler public void on(AlbumCreated event) { if (!event.photos.isEmpty()) {

    commandGateway.send(new AddPhotos(event.albumId, event.photos)) } }
  9.  @CommandHandler public void handle(MakePayment command) { var result =

    paymentService.makePayment(command.accountId(), command.amount()); if (result.isSuccessful()) { eventGateway.publish( new PaymentSucceeded(command.paymentId(), result.getTransactionId())); } else { eventGateway.publish( new PaymentFailed(command.paymentId(), result.getFailureReason())); } }
  10. 52 l ܇࿅σʔλʹͳ͍৘ใΛٻΊΒΕͨͱ͖ l ࠷৽"1* l ࣾ಺ن໿ l ͍͋·͍ͳࢦࣔΛड͚ͨͱ͖ l

    ʮ͍͍ײ͡ʹͯ͠ʯ l จ຺͕ෆ଍͍ͯ͠Δͱ͖ l ෳ਺ͷղऍ͕Մೳͳ࣭໰ ϋϧγωʔγϣϯΛى͜͠΍͍͢ঢ়گ
  11. 57 ৘ใΛ౉͢ • ܇࿅σʔλʹͳ͍΋ͷΛҾ͖౉͢ #### 2.1. Set-Based Consistency Validationύλʔϯʹ͓͚ΔίϚϯυ෼཭ ू໿࡞੒લʹ֎෦σʔλʢϦϙδτϦ౳ʣΛࢀরͨ͠ݕূ͕ඞཁͳ৔߹ɺίϚϯυΛ2ͭʹ෼཭͢Δɿ

    **֎෦ެ։ίϚϯυʢRequest* Commandʣ**: - **໨త**: ΫϥΠΞϯτ͔ΒͷϦΫΤετΛड͚औΓɺݕূΛ࣮ࢪ - **໋໊نଇ**: `Request{໊ࢺ}Command` (ྫ: `RequestReservationSlotCommand`) - **Ξϊςʔγϣϯ**: `@RoutingKey` - Application ServiceʹϧʔςΟϯά - **ϋϯυϥʔ**: Application Serviceʢ`@Service` + `@CommandHandler`ʣͰॲཧ - **ྫ**: ```java public record RequestReservationSlotCommand( @RoutingKey String slotId, String facilityId // ... ͦͷଞͷϑΟʔϧυ ) {} ```
  12. 58 બ୒ࢶΛ௵͢ ʮΠϕϯτΛ࡞ͬͯʯ͚ͩͩͱ ໋໊͸ 0SEFS$SFBUFE 0SEFS$SFBUFE&WFOU $SFBUFE0SEFS Ͳ͜ʹஔ͘ʁ FWFOUT EPNBJOFWFOUT

    BQJ • ͍͋·͍ͳࢦࣔΛݻఆ͢Δ - **໋໊نଇ**: `{໊ࢺ}{ಈࢺաڈ෼ࢺ}Event` (ྫ: `FacilityRegisteredEvent`, `ReservationCancelledEvent`) - **ྫ**: ʮอҭࢪઃ͕ొ࿥͞Εͨʯ→ `FacilityRegisteredEvent` - **ύοέʔδ**: `com.example.eventsourcing.{context}.api.events`
  13. 59 ϧʔϧΛఆٛ • จ຺͕ෆ଍͍ͯ͠Δͱ͜ΖΛϧʔϧͰΧόʔ ### 1. ΠϕϯτʢΦϨϯδ৭ͷ෇ᝦʣ - **ఆٛ**: γεςϜͰൃੜͨ͠ࣄ࣮ΛաڈܗͰදݱ

    - **࣮૷**: ֤Bounded Contextͷ`api/events`ύοέʔδʹrecordͱͯ͠ఆٛ - **഑ஔཧ༝**: ଞͷBounded Context΍ϚΠΫϩαʔϏε͔ΒࢀরՄೳͳެ։API ### σΟϨΫτϦߏ଄ ``` src/main/java/com/example/eventsourcing/ ├── {bounded-context}/ # ྫ: facility, parent │ ├── api/ │ │ └── events/ # ⭐ ެ։ΠϕϯτʢଞαʔϏε͔ΒࢀরՄೳʣ │ │ └── {Context}Events.java │ ├── adapter/ │ │ ├── inbound/ # Inbound Adaptersʢೖྗʣ
  14. 61 • ϓϩϯϓτ࡞Γ͸ूதͰ͸ͳ͘஝ੵ ◦ ׬ᘳͳϓϩϯϓτΛ࡞Ζ͏ͱ͠ͳ͍ ◦ ࢖͍ͳ͕ΒҭͯΔ • มߋͷλΠϛϯά͸ࢦࣔͷத ◦

    ࢦࣔΛग़͢ ◦ ˠҙʹ͙ͦΘͳ͍ ◦ ˠमਖ਼Λ఻͑Δ ◦ ˠͦͷྲྀΕͰNEϑΝΠϧͷमਖ਼΋ࢦࣔ ϓϩϯϓτ͸࡞ΒͤΔ΋ͷ
  15. "*ʹΑΔύϥμΠϜγϑτ ਤ͕ίʔυʹ ͳΔʂ @Service public class DocumentApplicationService { private final

    DocumentRepository documentRepository; public DocumentApplicationService(DocumentRepository documentRepository) { this.documentRepository = documentRepository; }
  16. 64