domain driven design - Dealing with a user dependent application -
an application i'm writing heavily dependent on current logged in user, give concrete example lets have list of products.
now every user has 'rights' see products, particular details of product, , edit / remove fewer of those.
e.g.:
- the user can see 3/5 products
- the user can see details 2 out of 3 products
- ...
as case of application's domain, have tendency pass around user in methods. becomes cumbersome time time. have pass in user in methods, pass down 1 needs it.
my gut tells me i'm missing something, i'm not sure how tackle problem.
i gave thoughts @ using class holds user, , inject class everywhere need it. or using static property.
now time time handy pass in user in method, guess override then:
public dosomething(user user = null) { var u = user ?? this.authservice.user; ... }
are there other ways tackle kind of problem ?
your gut correct, keep listen it.
authorization checks should not mixed core domain checks. example, if
checks user may update product details , if
checks product details long enough should not contained in same class or same bounded context. if have monolith 2 checks should contained in separate namespaces/modules.
now tell how it. in latest monolithic project use cqrs lot, separation between commands , queries. give example of command validation can extended query validation , non-cqrs architectures.
for every command register 0 or more command validators check if command may sent aggregate
. these validators eventual consistent. if command passes validators command sent aggregate
further checked in strong consistent manner. so, talking 2 kinds of validation: validation outside aggregate , validation inside aggregate. checks belongs other bounded context can implemented using command validators outside aggregate, that's how it. , example source code, in php:
<?php namespace coredomain { class productaggregate { public function handle(changeproductdetails $command):void //no return value { //this check strong consistent //the method yields 0 or more events or exception in case of failure if (strlen($command->getproductdetails()) < 10) { throw new \exception("product details must @ least 10 characters long"); } yield new productdetailswerechanged($command->getproductid(), $command->getproductdetails()); } } } namespace authorization { class usercanchangeproductdetailsvalidator { private $authenticationreaderservice; private $productspermissionsservice; public function validate(changeproductdetails $command): void //no return value, if no exception thrown { //this check eventual consistent if (!$this->productspermissionsservice->canuserchangeproductdetails($this->authenticationreaderservice->getauthenticateduserid(), $command->getproductid())) { throw new \exception("user may not change product details"); } } } }
this example uses style commands sent directly aggregates should apply pattern other styles too. brevity, details of command validators registering not included.
Comments
Post a Comment