W poprzednim wpisie opisałem swoje świeże podejście do tematu aplikacji AnimalShelter. Od razu po jego napisaniu zabrałem się za kodowanie. W ten sposób podstawowa wersja aplikacji powstała naprawdę szybko. Na razie efekt mogę porównać do projektu Jakuba Pilimona o nazwie ddd-by-examples/library. Z jednej strony będzie istniał CRUD do zbierania danych o zwierzakach, natomiast obok powstanie bogatszy model do zarządzania wnioskami. Sprawdźmy zatem jak to aktualnie wygląda.

Część CRUDowa

Na ten moment istnieją trzy możliwości obsługi danych. Możemy dodać informacje o zwierzaku, edytować je lub usunąć. Przy dwóch operacjach emitowane są zdarzenia, które odbiera nasz drugi moduł do zarządzania wnioskami. Chodzi tutaj oczywiście o operację dodawania oraz usuwania.

Zdarzenia emitowane przez CRUD i obsługiwane w module Proposals
Zdarzenia emitowane przez CRUD i obsługiwane w module Proposals

Zgodnie z tym co pisałem w poprzednim wpisie zastosowałem tutaj podejście z dwoma bazami danych. Z tego powodu, gdy dodamy dane zwierzaka do CRUD to powstanie odpowiadający im wpis w bazie danych przypisanej do tej części aplikacji. Następnie wyemitowane zostanie zdarzenie, które odbierze drugi moduł. On na jego podstawie stworzy wniosek w swojej bazie danych.

Odwrotny skutek będzie miała operacja usuwania. Wtedy w dwóch bazach danych nie pozostanie żaden ślad po dodanym wpisie. W późniejszej części aplikacji chciałbym tego uniknąć, aby jednak wpis został, ale miał dedykowany do tego status usunięcia.

Natomiast operacja aktualizacji danych pozostaje tylko w obrębie CRUDa. Moduł wniosków nawet się o niej nie dowie. Oczywiście warto byłoby nie zmieniać danych zwierzaka, gdy zostanie on już przyjęty do schroniska albo wymagane byłby do tego specjalne uprawnienie. Jednak to rozważanie zostawię sobie na kolejne wersje aplikacji.

Moduł wniosków

W części domenowej nie ma na razie żadnych dostępnych możliwości. Istnieje tylko handler dla zdarzeń, który tworzy oraz usuwa nowe wnioski i wygląda tak jak na poniższym kodzie.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package pl.devcezz.shelter.proposal;

import lombok.RequiredArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.transaction.annotation.Transactional;
import pl.devcezz.shelter.shared.event.AnimalCreatedEvent;
import pl.devcezz.shelter.shared.event.AnimalDeletedEvent;

@RequiredArgsConstructor
class ProposalEventHandler {

  private final AnimalProposalRepository animalProposalRepository;

  @EventListener
  @Transactional("proposalTransactionManager")
  public void handleCreatedAnimal(AnimalCreatedEvent event) {
    AnimalProposal animalProposal = AnimalProposal.newOne(
        AnimalProposalId.of(event.getAnimalId()));
    animalProposalRepository.save(animalProposal);
  }

  @EventListener
  @Transactional("proposalTransactionManager")
  public void handleDeletedAnimal(AnimalDeletedEvent event) {
    animalProposalRepository.deleteByAnimalProposalId(
        AnimalProposalId.of(event.getAnimalId()));
  }
}

To tak naprawdę tyle w tej części. Na tą chwilę nic nadzwyczajnego.

Dla lepszego wyobrażenia sobie jak wygląda cały projekt załączam dodatkowo obrazek struktury klas.

Aktualna struktura nowego podejścia w AnimalShelter
Aktualna struktura nowego podejścia w AnimalShelter

Podsumowanie

Jestem naprawdę zadowolony z efektów jak na 4 godziny pracy. Większość z tego czasu zeszło mi na podłączenie dwóch baz danych do aplikacji. Problemem okazało się uruchamianie dedykowanych skryptów Liquibase dla każdej z baz oraz strategia nazewnictwa dla encji JPA. Jeśli jesteś ciekawy/a jak to rozwiązałem to zapraszam na mojego GitHuba. Link znajdziesz poniżej.

Link do GitHub: https://github.com/cezarysanecki/animal-shelter
Tag: 20220712-animalshelter-pierwsze-linijki-kodu