Etsi DDD-aggregaattijuuri
On helmikuu 1, 2021 by adminAnna ”pelata kaikkien” suosikkipeliä, etsi Aggregate Root. Käyttäkäämme ensisijaista Asiakas / Tilaus / Tilauslinjat / Tuote-ongelma-aluetta. Perinteisesti Asiakas, Tilaus ja tuote ovat AR: t, joiden Tilauslinjat ovat Tilauksen alaisia kokonaisuuksia. Tämän takana on logiikka, että sinun on tunnistettava asiakkaat, tilaukset ja tuotteet, mutta OrderLineä ei olisi olemassa ilman tilausta. Joten ongelma-alueellamme on liiketoimintasääntö, jonka mukaan asiakkaalla voi olla vain yksi toimittamaton tilaus. kerrallaan.
Siirtääkö tämä tilauksen asiakasryhmän juuressa? Luulen, että se liikkuu. Mutta se tekee asiakkaan AR: sta melko suuren ja joutuu myöhemmin samanaikaisuuteen.
Tai entä jos meillä olisi liikesääntö, jonka mukaan asiakas voi tilata tietyn tuotteen vain kerran sen elinaikana. Tämä on enemmän todisteita, jotka edellyttävät Asiakkaan omistavan Tilauksen.
Mutta kun se tulee Lähetykseen he tekevät kaikki toimintansa Tilauksessa, ei asiakkaassa. On tavallista tyhmää, että koko asiakkaan on ladattava, jotta yksittäinen Tilaus voidaan merkitä toimitetuksi.
Tämä on mitä ehdotan:
class Customer { public Guid Id {get;set;} public string Name { get; set; } public Address Address { get; set; } public IEnumerable<Order> Orders { get; set; } public void PlaceOrder(ThingsInTheOrder thingsInTheOrder) { // Make sure there aren"t any pending orders already. // Make sure they aren"t ordering a Widget if they"ve already ordered a Widget in the past. // Create an Order object and add it to the collection. Raise a domain event to trigger emails and other stuff } } class Order { public Guid Id { get; set; } public IEnumerable<OrderLine> OrderLines { get; set; } public ShippingData {get;set;} public void Ship(ShippedByPerson shippedByPerson, string trackingCode) { // Create a new ShippingData object and assign it from the data passed in. // Publish a domain event } }
Suurin huoleni on samanaikaisuuskysymys ja se, että järjestyksellä itsessään on ominaispiirteitä aggregaattijuuren s.
Vastaus
Mitkä ovat kriteerit aggregaatin määrittelemiselle?
Palatkaamme takaisin suuren sinisen kirjan perusteisiin:
Kokoomateos: Ryhmä liitettyjä objekteja, joita käsitellään yhtenä yksikkönä datamuutosten yhteydessä . Ulkoiset viitteet on rajoitettu yhteen AGGREGATEn jäseneksi, joka on nimetty juureksi. Yhdenmukaisuussääntöjä sovelletaan AGGREGATES-rajoissa.
Tavoitteena on ylläpitää invarianteja. Mutta hallitaan myös paikallista identiteettiä oikein, eli sellaisten kohteiden tunnistaminen, joilla ei ole pelkästään merkitystä.
Order
ja Order line
kuuluvat lopullisesti tällaiseen klusteriin. Esimerkiksi:
- Poista
Order
, edellyttää kaikkien sen rivien poistamista. - Rivin poistaminen saattaa edellyttää seuraavien rivien numerointia uudelleen.
- Uuden rivin lisääminen edellyttäisi linjan nulber määrittämistä kaikkien muiden saman järjestyksen rivien perusteella.
- Joidenkin tilaustietojen, kuten valuutan, muuttaminen voi vaikuttaa rivikohtien hinnan merkitykseen (tai vaatia hintojen uudelleenlaskemista).
Joten tässä koko aggregaatti vaaditaan yhdenmukaisuussääntöjen ja invariantien varmistamiseksi.
Milloin lopettaa?
Kuvailet nyt joitain liiketoimintasääntöjä ja väität, että niiden varmistamiseksi sinun on otettava huomioon asiakas osana aggregaattia:
Meillä on busines Sääntö, jonka mukaan asiakkaalla voi olla vain yksi toimittamaton tilaus kerrallaan.
Tietysti, miksi ei. Katsotaanpa seuraukset: tilaukseen pääsee aina asiakkaan kautta. Onko tämä tosielämää? Pitäisikö heidän lukea asiakkaan viivakoodi ja tilauksen viivakoodi, kun työntekijät täyttävät tilauksen toimituksen ruudut ? Itse asiassa tilauksen henkilöllisyys ei ole globaalia eikä paikallista asiakkaalle, ja tämä suhteellinen riippumattomuus viittaa siihen, että hänet pidetään aggregaatin ulkopuolella.
Lisäksi nämä liiketoimintasäännöt näyttävät enemmän käytännöiltä: yrityksen mielivaltainen päätös suorittaa prosessi näiden sääntöjen mukaisesti. Jos sääntöjä ei noudateta, pomo saattaa olla tyytymätön, mutta tiedot eivät ole oikeastaan epäjohdonmukaisia. Ja lisäksi yön yli ” asiakasta kohti yksi toimittamaton tilaus kerrallaan ” voi tulla ” kymmenen toimittamatonta tilausta asiakasta kohti ” tai jopa ” asiakkaasta riippumatta, sata toimittamatonta tilausta varastoa kohti ”, joten aggregaatti ei ehkä ole enää perusteltu.
Vastaa
Lyhyt versio
DDD: n perustelu on, että toimialueobjektit ovat abstrakteja, joiden tulisi täyttää toimialueen toiminnalliset vaatimukset – jos toimialueobjektit eivät pysty täyttämään näitä vaatimuksia helposti, se viittaa siihen, että käytät mahdollisesti väärää abstraktiota.
Nimeäminen Verkkotunnusobjektit , jotka käyttävät entiteettien substantiiveja , voivat johtaa siihen, että nämä objektit kytkeytyvät tiiviisti toisiinsa ja että heistä tulee paisuneita ”jumalan” esineitä, ja ne voivat heittää esiin tämän kysymyksen kaltaisia asioita kuten ”Missä on oikea paikka s käytetäänkö CreateOrder-menetelmää? ”.
”Oikean” aggregaattijuuren tunnistamisen helpottamiseksi harkitse erilaista lähestymistapaa, jossa toimialueobjektit perustuvat toiminnallisiin korkean tason liiketoiminnan vaatimuksiin – ts.Valitse substantiivit, jotka viittaavat toiminnallisiin vaatimuksiin ja / tai käyttäytymiseen, jotka järjestelmän käyttäjien on suoritettava.
Pitkä versio
DDD on OO-suunnittelun lähestymistapa, jonka on tarkoitus tuottaa toimialueen toimialueobjektien kaavio Järjestelmän taso – Verkkotunnusobjektit ovat vastuussa liiketoiminnan korkean tason vaatimusten täyttämisestä, ja ihannetapauksessa niiden pitäisi voida luottaa tietokerrokseen esimerkiksi taustalla olevan pysyvän tietovaraston suorituskyvyn ja eheyden suhteen.
Toinen tapa tarkastella sitä voivat olla tämän luettelon luettelomerkit
- Entiteettien substantiivit ehdottavat yleensä tietomääritteitä.
- Verkkotunnuksen nimien tulisi ehdottaa käyttäytymistä
- DDD- ja OO-mallinnus käsittelevät abstraktioita, jotka perustuvat toiminnallisiin vaatimuksiin ja ydinalueeseen / liiketoimintalogiikkaan.
- Liikelogiikkataso on vastuussa korkean tason verkkotunnusvaatimusten täyttämisestä.
Yksi DDD: tä koskevista yleisimmistä väärinkäsityksistä on, että toimialueobjektien tulisi perustua joihinkin fyysisiin realiteetteihin. maailman ”juttu” (ts. jokin substantiivi, johon voit viitata reaalimaailmassa, joka liitetään kaikenlaisiin tietoihin / ominaisuuksiin), mutta näiden tosielämän asioiden data / attribuutit eivät välttämättä ole hyvä lähtökohta kun yritetään naulata toiminnalliset vaatimukset.
Liikelogiikan tulisi tietysti käyttää näitä tietoja, mutta verkkotunnusobjektien itsensä tulisi viime kädessä olla abstrakteja, jotka edustavat toimialueen toimivia vaatimuksia ja käyttäytymistä.
Esimerkiksi; substantiivit, kuten Order
tai Customer
, eivät tarkoita mitään käyttäytymistä, ja siksi ne ovat yleensä hyödyttömiä abstraktioita liiketoimintalogiikan ja toimialueobjektien esittämisessä.
Kun etsit abstrakteja, joista voi olla hyötyä Business Logicin esittämisessä, ota huomioon tyypilliset vaatimukset, joiden odotat järjestelmän täyttävän:
- Myyjänä minä haluan luoda tilauksen uudelle asiakkaalle, jotta voin luoda laskun myytävistä tuotteista niiden hintojen ja määrän kanssa.
- Asiakaspalvelun neuvonantajana haluan peruuttaa odottavan tilauksen, jotta Varasto-operaattori ei täytä tilausta.
- Asiakaspalvelun neuvonantajana haluan palauttaa tilausrivin, jotta tuote voidaan säätää varastoon ja maksu palautetaan takaisin asiakkaan alkuperäisen maksun kautta. menetelmä.
- Varasto-operaattorina haluan tarkastella kaikkia odottavan tilauksen tuotteita ja lähetystietoja, jotta voin valita tuotteet ja lähettää ne kuriirin kautta.
- jne.
Verkkotunnusvaatimusten mallinnus DDD-lähestymistavalla
Harkitse yllä olevan luettelon perusteella joitain potentiaalisia toimialueobjekteja ts tällaiselle Orders-järjestelmälle:
SalesOrderCheckout PendingOrdersStream WarehouseOrderDespatcher OrderRefundProcessor
Verkkotunnusobjekteina nämä edustavat abstraktioita, jotka omistavat erilaiset käyttäytymisalueiden vaatimukset; niiden substantiivit viittaavat voimakkaasti heidän täyttämiinsä toiminnallisiin vaatimuksiin.
(Siellä voi olla myös lisäinfrastruktuuria, kuten EventMediator
ohitettavaksi ilmoitukset tarkkailijoille, jotka haluavat tietää, kun uusi tilaus on luotu, tai kun tilaus on lähetetty, jne.).
Esimerkiksi SalesOrderCheckout
on todennäköisesti käsittele asiakkaita, lähetyksiä ja tuotteita koskevia tietoja, mutta ei kuitenkaan kiinnosta mitään tekemistä lähetystilausten, odottavien tilausten lajittelun tai hyvitysten antamisen kanssa.
For SalesOrderCheckout
verkkotunnusvaatimusten täyttämiseen kuuluu näiden liiketoimintasääntöjen täytäntöönpano, esimerkiksi estämällä asiakkaita tilaamasta liian monta tuotetta, mahdollisesti suorittamalla jonkinlainen vahvistus ja ehkä nostamalla ilmoituksia järjestelmän muille osille – se voi tehdä kaikki nämä asiat ilman, että heidän tarvitsee välttämättä olla riippuvaisia minkä tahansa muun objektin.
DDD käyttämällä Entiteettien substantiiveja toimialueobjektien esittämiseen
Ther e ovat joukko potentiaalisia vaaroja käsiteltäessä yksinkertaisia substantiiveja, kuten Order
, Customer
ja Product
verkkotunnusobjekteina; näiden ongelmien joukossa ovat ne, joihin viittaat kysymyksessä:
- Jos menetelmä käsittelee
Order
,Customer
ja aProduct
, mihin verkkotunnusobjektiin se kuuluu? - Missä näiden kolmen objektin aggregaattijuuri on?
Jos valitset Entiteetin substantiivit edustamaan toimialueen objekteja, voi tapahtua useita asioita:
-
Order
,Customer
jaProduct
on vaarassa kasvaa” jumaliksi ”. - Riski, että päädytään yhteen
Manager
jumala-objekti sitoa kaikki yhteen. - Nämä objektit voivat liittyä tiukasti toisiinsa – verkkotunnuksen vaatimuksia voi olla vaikea täyttää siirtämättä
this
(taiself
) - ”vuotavien” abstraktien – ts.verkkotunnusobjektien odotetaan paljastavan kymmeniä
get
/set
-menetelmiä, jotka heikentävät kapselointia (tai jos et, niin joku muu ohjelmoija luultavasti myöhemmin ..). - Riski, että toimialueobjektit paisuvat monimutkaisesta yritystietojen (esim. käyttäjätietojen syöttö käyttöliittymän kautta) ja väliaikaisen tilan (esim. käyttäjän toimintojen ”historia”) sekoituksesta. kun järjestystä on muutettu).
DDD-, OO-suunnittelu- ja tavalliset mallit
Yleinen väärinkäsitys DDD- ja OO-suunnittelusta on, että ”tavalliset” mallit ovat jotenkin ” huono ”tai” anti-malli ”. Martin Fowler kirjoitti artikkelin, jossa kuvataan aneeminen verkkotunnusmalli – mutta kuten hän tekee selväksi artikkelissa, DDD: n tulisi ei ”ole ristiriidassa” kerrosten välisen puhtaan erottamisen lähestymistavan kanssa
”On myös syytä korostaa, että käyttäytymisen lisääminen verkkotunnuksen kohteisiin ei saisi olla ristiriidassa vankka lähestymistapa kerrostuksen käyttämiseen sepaan arvioi verkkotunnuslogiikkaa esimerkiksi pysyvyydestä ja esittelyvastuista. Logiikka, jonka pitäisi olla verkkotunnusobjektissa, on toimialalogiikka – tarkistukset, laskelmat, liiketoimintasäännöt – mitä haluat kutsua. ”
Toisin sanoen pelkkien mallien käyttäminen muiden kerrosten välillä siirrettyjen yritystietojen pitämiseen (esim. Tilausmalli, jonka käyttäjäsovellus välittää, kun käyttäjä haluaa luoda uuden tilauksen) ei ole sama asia kuin ”aneeminen verkkotunnusmalli”. ”Tavalliset” tietomallit ovat usein paras tapa seurata tietoja ja siirtää tietoja kerrosten välillä (kuten REST-verkkopalvelu, pysyvyysvarasto, sovellus tai käyttöliittymä jne.).
Liikelogiikka voi käsitellä tiedot näissä malleissa ja voivat seurata niitä osana liiketoimintatilaa – mutta eivät välttämättä ota mallien omistusta.
Aggregate Root
Tarkastellaan uudelleen esimerkki verkkotunnusobjekteista – SalesOrderCheckout
, PendingOrdersStream
, WarehouseOrderDespatcher
, OrderRefundProcessor
ei vielä ole ilmeistä kokonaisjuurta, mutta niin on Minulla ei todellakaan ole väliä, koska näillä Domain-objekteilla on villin erilliset vastuut, jotka eivät näytä olevan päällekkäisiä.
Toiminnallisesti SalesOrderCheckout
ei tarvitse puhua PendingOrdersStream
kanssa, koska edellisen työ on valmis, kun se on lisännyt uuden tilauksen tietokantaan; toisaalta PendingOrdersStream
voi hakea uusia tilauksia tietokannasta. Näiden objektien ei tarvitse olla vuorovaikutuksessa jokaisen kanssa muu suoraan (Ehkä Tapahtumavälittäjä saattaa lähettää ilmoituksia näiden kahden välillä, mutta odotan, että näiden objektien välinen kytkentä on hyvin löysää)
Ehkä aggregaattijuuri on IoC-kontti, joka ruiskuttaa yhtä tai useampaa nämä toimialueobjektit käyttöliittymän ohjaimeksi ja toimittavat myös muuta infrastruktuuria, kuten EventMediator
ja Repository
. Tai ehkä se on jonkinlainen kevyt orkesteripalvelu, joka istuu yrityskerroksen päällä.
Yhdistelmähakemuksen ei tarvitse välttämättä olla toimialuekohde. Jotta huolenaiheita voidaan pitää erillään toimialueobjektien välillä, se on yleensä hyvä asia, kun aggregaatti root on erillinen objekti, jolla ei ole liiketoimintalogiikkaa.
Kommentit
- Äänestin alas, koska vastauksesi sekoittaa käsitteitä Entity Frameworkista, joka on Microsoft-erityinen tekniikka, ja Domain Driven Design -sovelluksesta, joka on peräisin kirjasta. kirjoittanut samanniminen Eric Evans. Sinulla on vastauksessasi joitain lauseita, jotka ovat suoraan ristiriidassa DDD-kirjan kanssa, ja tässä kysymyksessä ei mainita entiteettikehystä, mutta se on nimenomaisesti merkitty DDD: llä. Siellä ’ ei myöskään mainita pysyvyyttä lainkaan kysymyksessä, joten en ’ näe, missä tietokantataulukot ovat merkityksellisiä.
- @RibaldEddie Kiitos, että otit aikaa vastauksen ja kommentin tarkistamiseen, olen samaa mieltä pysyvien tietojen mainitsemisen ei tarvitse ’ t todella olla vastauksessa, joten ’ ve sen uudelleen muotoilemiseksi sen poistamiseksi. Vastauksen pääkohdat voidaan tiivistää seuraavasti: ” Entiteettien substantiivit eivät usein ole ’ t erittäin hyviä Domain Object -luokan nimiä, koska niillä on taipumus tulla tiiviisti toisiinsa paisutettuihin jumalakohteisiin ”, toivottavasti WRT: n viesti ja perustelut ovat nyt selkeämpiä?
- DDD-kirja ei ’ ei ole tätä IIRC-käsitettä. Siinä on entiteettejä, jotka ovat vain luokkia, joilla instanssilla on pysyvä ja ainutlaatuinen identiteetti siten, että kaksi erotettua instanssia tarkoittaa kahta ainutlaatuista ja pysyvää kykyä, mikä on ristiriidassa arvo-objektien kanssa, jotka eivät ’ heillä ei ole identiteettiä, eivätkä ne ’ ole jatkuvia ajan myötä. Kirjassa sekä Entiteetit että Arvo-objektit ovat toimialueen objekteja.
vastaus
ongelma-alueellamme, meillä on liikesääntö, jonka mukaan asiakkaalla voi olla vain yksi toimittamaton tilaus kerrallaan.
Ennen kuin menet liian syvälle kaninreikään, sinun tulee tarkistaa Greg Nuorten keskustelu -sarjan johdonmukaisuudesta ja erityisesti:
Mikä on epäonnistumisen liiketoiminnan vaikutus?
Koska monissa tapauksissa oikea vastaus ei ole yrittää estää väärä asia ei tapahdu, vaan sen sijaan, että luodaan poikkeusraportit , kun ongelmana saattaa olla.
Mutta olettaen, että useita toimittamattomia tilauksia on merkittävä vastuu yrityksellesi ….
Kyllä, jos haluat varmistaa, että on vain yksi toimittamaton tilaus, täytyy olla jokin aggregaatti, joka näkee kaikki asiakkaan tilaukset
Tämä aggregaatti ei välttämättä ole asiakasaggregaatti .
Se voi olla jotain tilausjonoa tai tilaushistoriaa, jossa kaikki tietyn tilauksen tilaukset asiakas menee samaan jonoon. Sanomasi perusteella se ei tarvitse kaikkia asiakkaan profiilitietoja, joten sen ei pitäisi olla osa tätä aggregaattia.
Mutta kun on kyse toimituksesta, he tekevät kaikki toimintansa tilauksessa, ei asiakkaassa.
Kyllä, kun työskentelet tosiasiallisesti täyttämisen ja vedä taulukoita, historianäkymä ei ole erityisen tärkeä.
Historia-näkymä tarvitsee vain invariantisi pakolliseksi vain tilaustunnuksen ja sen nykyisen käsittelytilan. Sen ei välttämättä tarvitse olla osa samaa aggregaattia kuin tilaus – muista, että aggregaattirajat koskevat muutoksen hallintaa, ei näkymien jäsentämistä.
Joten voi olla, että käsittelet tilausta aggregaattina. ja tilaushistoria erillisenä aggregaattina ja koordinoi näiden kahden toiminta.
Vastaa
Olet määrittänyt olki-esimerkki. Se on liian yksinkertainen ja epäilen, että se heijastaa todellisen järjestelmän järjestelmää. En mallintaa näitä entiteettejä ja niihin liittyvää käyttäytymistä tavalla, jonka määritit sen vuoksi.
Luokkiesi on mallinnettava tilauksen tila tavalla, joka näkyy useissa aggregaateissa. Esimerkiksi kun asiakas asettaa järjestelmän tilaan, jossa asiakkaan tilauspyyntö on käsiteltävä, voin luoda toimialueobjektiobjektikokoelman nimeltä CustomerOrderRequest
tai PendingCustomerOrder
tai jopa vain CustomerOrder
tai mikä tahansa kieli, jota yritys käyttää, ja se voi pitää osoittimen sekä asiakkaalle että OrderLinesille ja käyttää sitten menetelmää kuten canCustomerCompleteOrder()
, jota kutsutaan palvelutasolta.
Tämä toimialueobjekti sisältäisi liiketoimintalogiikan sen määrittämiseksi, onko tilaus kelvollinen.
Jos tilaus oli kelvollinen ja käsitelty, minulla olisi jokin tapa siirtää tämä objekti toiseen objektiin, joka edusti käsiteltyä tilausta.
Mielestäni ongelmana ymmärryksessäsi on, että käytät keksittyä liian yksinkertaistettu esimerkki aggregaateista. PendingOrder
voi olla sen oma aggregaatti erillään UndeliveredOrder
-kohdasta ja taas erillään tai CancelledOrder
tai mitä tahansa.
Kommentit
- Vaikka yrityksesi sukupuolineutraali kieli on huvittavaa, huomaan, että naiset eivät koskaan seiso pelloilla pelotella variksia.
- @RobertHarvey, että ’ on outo asia, johon keskittyä viestissäni. Variksenpelättejä ja kuvitteita ovat molemmat säännöllisesti esiintyneet naismuodossa koko historian ajan.
- Et olisi ’ et olisi tehnyt eroa viestissäsi, jos et olisi ’ ei pidä sitä tärkeänä. Kielitieteessä termi on ” olkimies; ” kaikki epäilykset seksismistä ovat melkein epäonnistuneet ” mitä helvettiä hän puhuu tekijästä ”, joka on luotu keksimällä oma termisi.
- @RobertHarvey jos joku tietää mitä olkea mies tarkoittaa, että olen ’ varma, että he voivat selvittää, mitä olki tarkoittaa, jos he eivät ole ’ kuullut tuota termiä. Voimmeko keskittyä viestini sisältöön, kirjoita ohjelmisto?
Vastaus
Vaughn Vernon mainitsee tämän kirja ”Toimialueohjatun suunnittelun toteuttaminen” luvun 7 (Palvelut) alussa:
”Usein paras merkki siitä, että sinun tulisi luoda palvelu verkkotunnusmalliin, on, kun suoritettava operaatio tuntuu hyvältä paikka kokonaisuutena tai arvoobjektina ”.
Tässä tapauksessa voi siis olla verkkotunnuspalvelu nimeltä ”CreateOrderService”, joka vie asiakkaan ilmentymän ja tilauksen kohteiden luettelon.
class CreateOrderService { public Order CreateOrder(Customer customer, ThingsInTheOrder thingsInTheOrder) { // Get all the orders for the customer // Check if any of the things to be ordered exist in previous orders // If none have been previously ordered, create the order and return it // Otherwise return null } }
kommentit
- Voitteko selittää tarkemmin, kuinka verkkotunnuspalvelu voi auttaa vastaamaan kysymyksen samanaikaisuuteen?
Vastaa