Kilka dni temu okazało się, że będziemy realizować zupełnie nowy projekt. Dostałem dokument ze wstępną analizą wykonalności, na którego podstawie miałem przygotować zarys architektury rozwiązania wraz ze wstępnym modelem domeny.

Z miejsca zacząłem rysować na tablicy encje i value object’y, łączyć je w agregaty, szukać abstrakcji. Niestety im bardziej się zagłębiałem w temat tym wynajdywane przeze mnie abstrakcje były bardziej kruche. Przykład?

System powinien sprawdzać, czy systemy docelowe przetworzyły transakcje i dokonywać odpowiednich aktualizacji po swojej stronie

Oczywiście systemów docelowych może być kilka, a mechanizm komunikacji został zidentyfikowany jako potencjalny punkt zmian. Stworzyłem więc abstrakcje IResultCheckingStrategy

[Transaction]++1->1[IResultCheckingStrategy||+ICheck()]Problemy z taką abstrakcją są dwa:

  • Nie nadaje się do reprezentacji strategii, która reaguje na asynchroniczną odpowiedź od zewnętrznego systemu (musi być wykonana metoda Check)
  • Obiekt reprezentujący Transakcję musi, jako korzeń agregatu, posiadać także metodę Check, która byłaby dla każdej instancji wywoływana okresowo przez jakiegoś “demona”.

Prawda, że kiepski ten model?

Ostatecznie więc, po kilku godzinach podjąłem odważną decyzję o porzuceniu tradycyjnego sposobu modelowania Domain-Driven Design. Problem, który staramy się rozwiązać (głównie routing transakcji) zdecydowanie lepiej modelować w oparciu o procesy, a nie encje.

Nowy model zakłada istnienie anemicznych struktur danych, które są przetwarzane przez wiele następujących po sobie procesów. Każdy proces jest zaś sekwencją czynności, z których każda reaguje na konkretny rodzaj zdarzenia. Efektem wykonania czynności jest opublikowanie innego zdarzenia, aktywujące kolejną czynność.

Procesy są konfigurowane na zewnątrz za pomocą trzech “łączników”:

  • reaguj na zdarzenie X natychmiast (przetwarzaj kolejną czynność w ramach tego samego unit of work — tej samej transakcji)
  • reaguj na zdarzenie X z checkpoint’em (przetwarzaj kolejną czynność w ramach osobnego unit of work po zapisaniu stanu procesu w bazie danych)
  • reaguj na zdarzenie X z opóźnieniem Y (analogicznie do poprzedniego, ale aktywacja jest opóźniona o zadaną wartość)

Na bazie tych trzech prostych specyfikacji udało mi się zbudować szablon wszystkich procesów biznesowych aplikacji.

Zapewne design będzie się jeszcze wiele razy zmieniał w przeciągu najbliższych 6 tygodni. To jest jedynie pierwsze przybliżenie. O wszelkich zmianach będę donosił niezwłocznie.

VN:F [1.8.7_1070]
Rating: 5.0/5 (2 votes cast)
Don't model out of the box5.052