Archetypy Programowania

Software Archetypes

Na podstawie "Enterprise Patterns and MDA" Jima Arlowa i Ili Neustadt

Software Archetypes to otwarte źródło wiedzy o wzorcach danych, które stoją za prawie każdym systemem biznesowym: jak modelować osoby i organizacje, produkty i katalogi, zamówienia, płatności, magazyn i wysyłki. Każdy wzorzec zaczyna się od konkretnego problemu, prowadzi przez strukturę z diagramem klas UML, a następnie pokazuje schemat SQL, cykl życia jako maszynę stanów i niezmienniki, które muszą zachodzić w czasie działania.

Wzorce bazują na książce Enterprise Patterns and MDA Jima Arlowa i Ili Neustadt, zweryfikowanej dwiema dekadami budowania systemów produkcyjnych. Są napisane dla inżynierów backendowych i architektów, którzy potrzebują punktu wyjścia sprawdzonego w wielu branżach — nie podręcznikowej abstrakcji, ale działającego modelu danych, który można od razu wdrożyć w PostgreSQL, MySQL lub dowolnej bazie relacyjnej.

Wszystkie przykłady mają działające implementacje w PHP, Javie i TypeScript. Każdy wzorzec to około 10–15 minut czytania i samodzielnie zrozumiały model, który można zastosować osobno lub złożyć z innymi.

Przegląd

Każdy wzorzec jest przedstawiony wraz z:

  • Opis problemu — Kiedy potrzebujesz tego wzorca
  • Przegląd koncepcyjny — Główna idea
  • Struktura — Diagramy klas Mermaid
  • Zachowania — Pseudokod operacji
  • Maszyny stanów — Diagramy cyklu życia
  • Niezmienniki — Reguły biznesowe, które muszą być spełnione
  • Schemat SQL — ANSI SQL do persystencji
  • Zagadnienia projektowe — Kompromisy i alternatywy

Katalog wzorców

Archetyp Party (Kto)

Wzorzec Plik Opis
Party 01-party-pattern.md Abstrakcja Person lub Organization
Party Role 02-party-role-pattern.md Role: Customer, Supplier, Employee
Party Relationship 03-party-relationship-pattern.md Employment, Ownership, Marriage
Party Identifier 04-party-identifier-pattern.md PESEL, NIP, Paszport, Numer podatkowy

Archetyp Product (Co)

Wzorzec Plik Opis
Product 05-product-archetype.md ProductType → Product → ProductInstance

Wzorce transakcyjne (Handel)

Wzorzec Plik Opis
Order 06-order-archetype.md Order + Order Line, cykl życia
Payment 07-payment-pattern.md Payment i Refund
Inventory 08-inventory-pattern.md Śledzenie stanów magazynowych, transakcje
Shipment 09-shipment-pattern.md Dostawa fizyczna, śledzenie

Relacje między wzorcami

ORDER (Handel)

składa

zawiera

dotyczy

opłacone przez

rezerwuje

wysyłane jako

wydanie przy wysyłce

pełni rolę

PARTY (Kto)

Person

Organization

PartyRole
(Customer / Supplier)

Customer

Order

OrderLine

Product
Catalog

Payment

Inventory

Shipment

Scenariusz integracji end-to-end

Ten przewodnik pokazuje, jak wszystkie wzorce łączą się w typowym przepływie e-commerce: Customer składa Order, płaci, towar jest rezerwowany, a Order jest wysyłane.

1. Konfiguracja Party

// Jan Kowalski is registered as a Person with a Customer role
jan = new Person(firstName: "Jan", lastName: "Kowalski")
jan.addIdentifier(PESEL, "85031512345")
jan.addAddress(homeAddress)

customerRole = new Customer(
    party: jan,
    customerNumber: "CUST-00001234",
    loyaltyTier: LoyaltyTier.Gold,
    creditLimit: Money(1000000, "PLN")
)

2. Złożenie Order

order = new Order(
    orderNumber: "ORD-2026-000042",
    customer: customerRole,
    currency: "PLN",
    billingAddress: jan.getPrimaryAddress()
)

order.addLine(thinkpad, quantity: 1, unitPrice: Money(649900, "PLN"))
order.addLine(mouse,    quantity: 2, unitPrice: Money(44900, "PLN"))
// order.grandTotal = 909633 (with 23% VAT)

order.confirm()
// emits OrderConfirmed → triggers inventory reservation

3. Rezerwacja Inventory

// Listener handles OrderConfirmed event
for line in order.lines:
    item = findInventoryItem(line.product, warehouse)
    item.reserve(line.quantity, order.orderNumber, "Order reservation")
    // emits StockReserved

// Warehouse state:
// ThinkPad: onHand=20, reserved=1, available=19
// Mouse:    onHand=50, reserved=2, available=48

4. Payment

payment = new Payment(
    reference: "PAY-2026-000089",
    order: order,
    amount: order.grandTotal,
    method: PaymentMethod.Card
)

payment.markProcessing()
// ... gateway webhook: payment.success ...
payment.complete("gw_txn_abc123")
// emits PaymentCompleted → triggers shipment creation

order.markPaid(payment)
// emits OrderPaid

5. Utworzenie Shipment i przepływ Inventory

shipment = Shipment.fromOrder(order, "SHP-2026-000018", warehouseAddress)
shipment.addItemFromOrderLine(order.lines[0], 1)  // ThinkPad
shipment.addItemFromOrderLine(order.lines[1], 2)  // Mouse

shipment.startPicking()     // warehouse staff collects items
shipment.markPacked()       // items boxed
shipment.assignCarrier(dhl, "1234567890")
shipment.markLabelPrinted()
shipment.handOverToCarrier()
// emits ShipmentShipped

6. Wydanie Inventory

// Listener handles ShipmentShipped event
for item in shipment.items:
    inv = findInventoryItem(item.product, warehouse)
    inv.shipReserved(item.quantity, order.orderNumber)
    // emits StockIssued

// Warehouse state:
// ThinkPad: onHand=19, reserved=0, available=19
// Mouse:    onHand=48, reserved=0, available=48

7. Dostawa

// Carrier webhook updates
shipment.markInTransit("Warszawa Hub")
shipment.markOutForDelivery()
shipment.markDelivered({ signature: "J. Kowalski" })
// emits ShipmentDelivered

order.markDelivered()
order.complete()
// emits OrderCompleted

Podsumowanie przepływu zdarzeń

ShipmentInventoryPaymentOrderCustomerShipmentInventoryPaymentOrderCustomerplace orderconfirm()OrderConfirmedreserve()initiate paymentcomplete()PaymentCompletedmarkPaid()create shipmentpick → pack → label → handoverShipmentShippedshipReserved()inTransit → deliveredShipmentDeliveredcomplete()

Wspólne zasady projektowe

Identyfikatory i klucze

  • Klucz główny: UUID v7 (sortowalny chronologicznie)
  • Klucz biznesowy: Czytelny dla człowieka (ORD-2024-000001)
  • Klucz zewnętrzny: Z innych systemów (identyfikator transakcji bramki płatniczej)

Pieniądze

// NEVER use floating point!
// Store in smallest currency unit (cents, grosze)

amount_cents: 19999  // = 199.99
currency: "PLN"

Czas

  • Znaczniki czasu: UTC, niezmienne (createdAt)
  • Daty: Data lokalna bez czasu (birthDate)
  • Okres ważności: validFrom/validTo dla encji ograniczonych czasowo

Strategie dziedziczenia

Strategia Zastosowanie SQL
Jedna tabela Niewiele pól podtypów Jedna tabela, kolumna typu
Łączenie tabel Wiele pól specyficznych dla podtypów Tabela bazowa + tabele podtypów
Tabela konkretna Zupełnie różne podtypy Osobne tabele

Katalog zdarzeń domenowych

Każdy wzorzec emituje zdarzenia domenowe, gdy zachodzą istotne zmiany stanu. Zdarzenia te umożliwiają luźne powiązanie między wzorcami (np. OrderConfirmed wyzwala rezerwację magazynową).

Domena Party

Zdarzenie Źródło Wyzwalacz Dane
CustomerTierUpgraded Party Role Customer.upgradeTier() customer, previousTier, newTier
EmployeePromoted Party Role Employee.promote() employee, previousPosition, newPosition
RelationshipTerminated Party Relationship PartyRelationship.terminate() relationship, endDate, reason
EmployeePromoted Party Relationship Employment.promote() employment, previousTitle, newTitle
EmployeeTransferred Party Relationship Employment.transfer() employment, newDepartment, newLocation
OwnershipChanged Party Relationship Ownership.adjustOwnership() ownership, previousPct, newPct
IdentifierVerified Party Identifier PartyIdentifier.verify() identifier, verifier
IdentifierRevoked Party Identifier PartyIdentifier.revoke() identifier, reason

Domena Product

Zdarzenie Źródło Wyzwalacz Dane
ProductDiscontinued Product Product.discontinue() product
InstanceSold Product ProductInstance.sell() instance, order

Domena Handlowa

Zdarzenie Źródło Wyzwalacz Dane
OrderConfirmed Order Order.confirm() order
OrderPaid Order Order.markPaid() order, payment
OrderCancelled Order Order.cancel() order, reason
PaymentProcessing Payment Payment.markProcessing() payment
PaymentCompleted Payment Payment.complete() payment
PaymentFailed Payment Payment.fail() payment, reason
PaymentCancelled Payment Payment.cancel() payment

Domena Realizacji

Zdarzenie Źródło Wyzwalacz Dane
StockReceived Inventory InventoryItem.receive() item, quantity, reference
StockIssued Inventory InventoryItem.issue() item, quantity, reference
StockReserved Inventory InventoryItem.reserve() item, quantity, reference
StockReleased Inventory InventoryItem.release() item, quantity, reference
StockAdjusted Inventory InventoryItem.adjust() item, quantity, reference
StockTransferred Inventory InventoryService.transfer() source, destination, quantity, reference
ShipmentShipped Shipment Shipment.handOverToCarrier() shipment
ShipmentDelivered Shipment Shipment.markDelivered() shipment
ShipmentReturned Shipment Shipment.markReturned() shipment
ShipmentCancelled Shipment Shipment.cancel() shipment

Kluczowe łańcuchy zdarzeń

Zdarzenie wyzwalające Typowa akcja nasłuchiwacza
OrderConfirmed Rezerwacja magazynowa dla każdej Order Line
OrderCancelled Zwolnienie rezerwacji magazynowych
PaymentCompleted Oznaczenie Order jako opłacone, utworzenie Shipment
ShipmentShipped Wydanie zarezerwowanego towaru z Inventory
ShipmentDelivered Oznaczenie Order jako dostarczone
ShipmentReturned Utworzenie rekordu Refund, uzupełnienie Inventory

Renderowanie diagramów Mermaid

Te samouczki używają Mermaid do diagramów. Aby je wyświetlić:

  1. GitHub — Renderuje automatycznie w plikach Markdown
  2. VS Code — Zainstaluj rozszerzenie "Markdown Preview Mermaid Support"
  3. Online — Użyj mermaid.live
  4. CLI — Użyj mmdc (mermaid-cli)

Działające implementacje

Trzy kompletne implementacje dostępne w osobnym repozytorium: software-archetypes-examples

Stos technologiczny Katalog Uruchomienie
PHP 8.3 / Symfony 7 / Doctrine ORM 3 php/ cd php && make up && make demo
Java 21 / Spring Boot 3.4 / JPA+Hibernate java/ cd java && make up && make demo
TypeScript / Node 22 / TypeORM 0.3 nodejs/ cd nodejs && make build && make demo

Każde demo tworzy ten sam scenariusz: Jan Kowalski (Person) składa Order w Acme (Organization), płaci kartą, towar jest rezerwowany i wysyłany przez DHL, a następnie dostarczany.

Słowniczek

Termin Definicja
Archetyp Powtarzalny, uniwersalny wzorzec w modelowaniu biznesowym. Archetypy (Party, Product, Order) pojawiają się praktycznie w każdym systemie korporacyjnym, niezależnie od branży.
Party Abstrakcja dla dowolnej encji — Person lub Organization — która może uczestniczyć w transakcjach, pełnić role lub wchodzić w relacje.
Person Konkretny podtyp Party reprezentujący pojedynczego człowieka.
Organization Konkretny podtyp Party reprezentujący firmę, instytucję lub grupę.
Party Role Funkcja lub zdolność, w jakiej Party działa w systemie (Customer, Supplier, Employee). Oddziela tożsamość od możliwości.
Party Relationship Skierowane powiązanie między dwoma Party z własnymi atrybutami i cyklem życia (Employment, Ownership, Marriage).
Party Identifier Zewnętrzny kod identyfikacyjny przypisany Party przez organ wydający (PESEL, NIP, Paszport).
ProductType Kategoria lub szablon definiujący strukturę (atrybuty, reguły) dla grupy produktów. Tworzy hierarchię (Elektronika > Laptopy).
Product Pozycja katalogowa z SKU i ceną, którą można zamówić. Należy do ProductType.
ProductInstance Konkretna fizyczna lub serializowana jednostka Product, śledzona indywidualnie (po numerze seryjnym, partii, dacie ważności).
Order Transakcja handlowa rejestrująca, co Customer chce kupić, z danymi nagłówkowymi i pozycjami.
Order Line Pojedyncza pozycja w Order: produkt, ilość, cena jednostkowa i obliczone sumy.
Payment Transakcja finansowa reprezentująca wpływ pieniędzy (Payment) lub ich wypływ (Refund). Ma własny cykl życia niezależny od Order.
Refund Payment z isRefund = true, powiązana z oryginalną Payment. Modeluje zwrot pieniędzy do Customer.
Inventory Item Stan magazynowy konkretnego Product w konkretnej Location. Śledzi ilości: dostępne, zarezerwowane i na stanie.
Inventory Transaction Niezmienny wpis w księdze rejestrujący zmianę stanu magazynowego (przyjęcie, wydanie, rezerwacja, zwolnienie, korekta, transfer).
Location Fizyczne lub wirtualne miejsce, w którym przechowywany jest towar, tworzące hierarchię (Warehouse > Strefa > Alejka > Regał).
Shipment Fizyczne przemieszczenie towaru z miejsca nadania do miejsca docelowego. Ma własny cykl życia oddzielony od Order.
Shipment Event Oznaczona czasowo zmiana statusu w podróży Shipment (odebrana, w tranzycie, dostarczona).
Carrier Dostawca usług wysyłkowych (DHL, UPS, InPost) z integracją śledzenia przesyłek.
Pieniądze (Money) Obiekt wartości reprezentujący kwotę pieniężną przechowywaną jako liczba całkowita w najmniejszej jednostce walutowej (centy/grosze) plus kod waluty. Nigdy nie używaj zmiennoprzecinkowych.
Zdarzenie domenowe (Domain Event) Powiadomienie emitowane, gdy dzieje się coś istotnego (OrderConfirmed, PaymentCompleted). Używane do luźnego powiązania między wzorcami.
Niezmiennik (Invariant) Reguła biznesowa, która musi być zawsze prawdziwa (np. „zarezerwowane nie może przekraczać stanu na ręku"). Wymuszana przez warunki wstępne i ograniczenia bazodanowe.
Warunek wstępny (Precondition) Warunek sprawdzany przed wykonaniem operacji (require). Rzuca błąd, jeśli jest naruszony.
EAV Entity-Attribute-Value — wzorzec schematu dla dynamicznych atrybutów, w którym każdy atrybut jest przechowywany jako wiersz, a nie kolumna.
SKU Stock Keeping Unit — unikalny kod identyfikujący produkt w katalogu.
UUID v7 Sortowalny chronologicznie uniwersalny unikalny identyfikator. Zalecany jako klucz główny dla wszystkich encji.

Licencja

Licencja MIT. Koncepcje wzorców na podstawie "Enterprise Patterns and MDA" autorstwa Jima Arlowa i Ili Neustadt (Addison-Wesley, 2003).