Reguły biznesowe w architekturze systemów
Nie betonuj biznesu w kodzie. Postaw na DMN i Drools.
Streszczenie
W świecie architektury i inżynierii oprogramowania pojawia się często pokusa, by rozwiązywać każdy problem za pomocą kolejnych linii kodu w językach programowania. Jednak gdy w grę wchodzą reguły biznesowe charakterystyczne dla obsługiwanej branży, podejście imperatywne staje się pułapką. Jak oddzielić „co” system ma zrobić, od tego „jak” ma to zrobić? Odpowiedzią są silniki do opisu i przetwarzania reguł biznesowych i otwarte standardy - takie jak DMN (Decision Model and Notation).
Opis bieznesowy systemu
Każdy doświadczony programista zna ten scenariusz: po rozmowie z analitykiem biznesowym pojawia się wymaganie zmiany zachowania aplikacji, np. zmiany parametrów produktu, który determinuje określony sposób produkcji w fabryce. Zmiana wydaje się trywialna – często jest to jeden atrybut. Jednak z technicznego punktu widzenia oznacza to modyfikację kodu źródłowego, przebudowanie artefaktów, uruchomienie testów i pełne wdrożenie nowej wersji aplikacji. To klasyczny przykład silnego sprzężenia (tight coupling) architektury technicznej z architekturą biznesową. W idealnym świecie te dwa byty powinny żyć niezależnie obok siebie.
Grzech pierworodny, czyli “hardcodowanie” logiki biznesowej
Tradycyjne podejście do implementacji logiki biznesowej polega na odwzorowaniu jej w instrukcjach warunkowych języka ogólnego przeznaczenia, który jest używany przez zespół programistów do tworzenia aplikacji. Spójrzmy na prosty przykład w Javie. Chcemy przyznać rabat na podstawie typu klienta i wartości koszyka. Poniżej widać podejście imperatywne - umieszczenie logiki biznesowej w kodzie na przykładzie obliczania rabatu dla różnych klas klientów:
public BigDecimal calculateDiscount(Order order) {
if (order.getTotal().compareTo(new BigDecimal("1000")) > 0) {
if ("VIP".equals(order.getCustomerType())) {
return new BigDecimal("0.15");
} else if ("REGULAR".equals(order.getCustomerType())) {
return new BigDecimal("0.05");
}
}
return BigDecimal.ZERO;
}
Na pierwszy rzut oka kod jest czytelny. Problemy zaczynają się, gdy reguł jest dużo więcej, tworzą się między nimi zależności, a dodatkowo często się zmieniają. Taki kod staje się bardzo trudny w utrzymaniu. Wraz ze wzrostem i rozwojem systemu pojawia się refleksja: zmiana logiki biznesowej nie powinna wymagać rekompilacji!
Dlaczego otwarte standardy (DMN), a nie własny sposób zapisu (DSL)?
Wielu architektów w obliczu tego problemu może zasugerować: “Napiszmy własny parser reguł! Stwórzmy własny język domenowy (DSL) w dobrze znanym dla osób biznesowych języku - np. XML lub JSON, tak aby te osoby mogły go edytować”.
Należy pamiętać, że tworzenie własnego silnika reguł to ogromny koszt: konieczność tworzenia parserów i brak kompatybilności z rynkowymi narzędziami. Zamiast wymyślać koło na nowo, warto skłonić się ku otwartym standardom.
Tu na scenę wkracza DMN (Decision Model and Notation). DMN to standard zarządzany przez organizację OMG (Object Management Group). To organizacja, która pracowała nad dobrze znaną notacją UML. Pierwsze wersje DMN pojawiły się w 2015 roku. Choć w branży IT okres powyżej 10 lat to wieczność, jednak w przypadku standardów oznacza to dojrzałość, stabilność i szerokie wsparcie narzędziowe.
DMN pozwala modelować decyzje biznesowe w sposób zrozumiały zarówno dla programu komputerowego, jak i dla człowieka (np. diagramy i tabele decyzyjne).
Drools, czyli silnik, który napędza DMN
Najpopularniejszym obecnie silnikiem reguł, który wspiera DMN, jest Drools (część ekosystemu KIE/JBoss). Drools pozwala na wydzielenie logiki biznesowej - aplikacja staje się jedynie warstwą techniczną, która przesyła dane (fakty) do silnika Drools i odbiera decyzję (obiekty, listy, parametry). Zobaczmy, jak ten sam problem rabatowy wygląda w świecie reguł drools.
Podejście klasyczne: format Drools Rule Language (DRL)
Drools posiada swój natywny format zapisu reguł (pliki .drl). Jest to podejście deklaratywne. Nie skupiamy się nad tym jak sprawdzić warunki, ale nad tym co ma się wydarzyć, gdy warunki zajdą.
Fragment reguł przyznających rabat na podstawie typu klienta:
import pl.psti.learning.model.Order;
import pl.psti.learning.model.Discount;
rule "VIP Discount over 1000"
when
$o : Order( total > 1000, customerType == "VIP" )
then
insert(new Discount(0.15));
end
rule "Regular Discount over 1000"
when
$o : Order( total > 1000, customerType == "REGULAR" )
then
insert(new Discount(0.05));
end
Silnik Drools, używając wewnętrznych, zoptymalizowanych algorytmów, błyskawicznie dopasowuje fakty do wielu podobnych reguł.
Tabele decyzyjne - decision table
Drools pozwala również zdefiniować logikę w formie Tabeli Decyzyjnej. Taka tabela nie jest “kodem” w rozumieniu programistycznym – to macierz, którą analityk biznesowy może edytować w Excelu lub innym edytorze.
Przykładowa tabela decyzyjna dla naszego przykładu:
| U | Typ Klienta (Input) | Wartość Zamówienia (Input) | Rabat (Output) |
|---|---|---|---|
| 1 | ”VIP” | > 1000 | 0.15 |
| 2 | ”REGULAR” | > 1000 | 0.05 |
| 3 | - | <= 1000 | 0.00 |
Dla silnika Drools taki format opisu jest bezpośrednio wykonywalny, analogicznie do notacji .drl
Co zyskujemy dzięki separacji kodu i reguł biznesowych?
Wdrożenie silnika reguł takiego jak Drools i oparcie się o standard DMN to często strategiczna decyzja architektoniczna dla systemu. Podejmując decyzję o takim wdrożeniu warto wziąć pod uwagę poniższe korzyści:
- Oddzielenie cyklu wdrożenia reguł od wdrożenia aplikacji: Aplikacja może być wdrażana np. raz na tydzień. Reguły mogą być aktualizowane codziennie, bez uruchamiania pipeline’ów CI/CD (tzw. hot deployment).
- Testowanie biznesowe: Reguły można testować automatycznie, sprawdzając, czy dla zadanych wejść otrzymujemy oczekiwane wyjścia, bez konieczności uruchamiania całej infrastruktury.
- Spójność i jedno źródło prawdy: Ten sam plik z regułami może być używany przez system oraz może być użyty do wygenerowania dokumentacji.
- Bezpieczeństwo: Oddzielając logikę techniczną od biznesowej, zmniejszamy ryzyko błędu w głównym kodzie aplikacji.
Podsumowanie
Elastyczność systemu to nie cecha, którą dodaje się na końcu projektu. To fundament poprawnej architektury. Wykorzystanie standardu DMN pozwala na bardzo efektywne rozdzielenie tego, co techniczne (skalowalność, bezpieczeństwo, interfejsy), od tego co biznesowe (decyzje, przebieg procesów).
W czasach, gdy biznes zmienia się szybciej niż kiedykolwiek, trzymanie logiki decyzyjnej w kodzie źródłowym to dług technologiczny. Dlatego warto wybierać otwarte standardy, zamiast budować imponujące struktury z if-ów.