I'm new to DDD, and been reading a lot about it, but I can't figure this out. I'm making a tipical CRUD operation (Create), and I have to validate some field against, the rest of the entities persisted in my repository.
I know that Application Services, shouldn't have any business logic, a domain Entity, should not access to repositories directly, a Domain Service, may be the best choice, but I don't know how to do it well. I'm very confused.
How can I correct the next code:
class CustomerApplicationService {
void AddNew ( CustomerDTO myNewCustomerDTO ) {
CustomerRepository myCustomerRepo = new CustomerRepository();
var allCustomers = myCustomerRepo.FindAll();
for each (Customer c in allCustomers) {
if (c.SomeField == myNewCustomerDTO.SomeField) {
// do something, check duplicate data, etc
}
}
var myNewCustomer = new Customer();
// map myNewCustomer ... fields with myNewCustomerDTO
myCustomerRepo.Save( myNewCustomer );
}
}
Thanks!
I guess it all depends on what you are doing on the line that says "// do something". Checking for duplicates is not really a domain layer concern, so that's fine to check in your application layer. Although I wouldn't load all your customers into memory to check for that. Your repository could just have a FindByUsername or FindByEmail method, and if it doesn't return any results then it's not a duplicate. Same goes for simple validation, like checking for nulls or string length. That type of validation goes in the application layer. Only put logic into your domain models when it makes sense to do so, such as when you have a true complex business problem and the logic is volatile. A constraint like username is unique is not really volatile so it doesn't belong in your domain model.
It's also important to remember that just because you are "doing DDD" doesn't mean that's the only tool your system can use. If all you have is a simple CRUD insert, then just do a CRUD insert with ADO.NET or whatever is easiest. Reserve DDD for when you have true complexity and invariants that need to be enforced.
Overall I think your general approach looks pretty good though.
Related
Why are repositories' .Add method usually implemented as accepting the instance of entity to add, with the .Id already "set" (although it can be set again via reflection), which should be repo's responsibility?
Wouldn't it be better to implement it as .CreateAndAdd?
For example, given a Person entity:
public class Person
{
public Person(uint id, string name)
{
this.Id = id;
this.Name = name;
}
public uint Id { get; }
public string Name { get; }
}
why are repositories usually implemented as:
public interface IRpository<T>
{
Task<T> AddAsync(T entity);
}
and not as:
public interface IPersonsRpository
{
Task<Person> CreateAndAddAsync(string name);
}
why are repositories usually implemented as...?
A few reasons.
Historically, domain-driven-design is heavily influenced by the Eric Evans book that introduced the term. There, Evans proposed that repositories provide collection semantics, providing "the illusion of an in memory collection".
Adding a String, or even a Name, to a collection of Person doesn't make very much sense.
More broadly, figuring out how to reconstitute an entity from a set of a parameters is a separate responsibility from storage, so perhaps it doesn't make sense to go there (note: a repository often ends up with the responsibility of reconstituting an entity from some stored memento, so it isn't completely foreign, but there's usually an extra abstraction, the "Factory", that really does the work.)
Using a generic repository interface often makes sense, as interacting with individual elements of the collection via retrieve/store operations shouldn't require a lot of custom crafting. Repositories can support custom queries for different kinds of entities, so it can be useful to call that out specifically
public interface IPersonRepository : IRepository<Person> {
// Person specific queries go here
}
Finally, the id... and the truth of it is that identity, as a concept, has a whole lot of "it depends" baked into it. In some cases, it may make sense for the repository to assign an id to an entity -- for instance, using a unique key generated by the database. Often, you'll instead want to have control of the identifier outside of the repository. Horses for courses.
There already is a great answer on the question, I just want to add some of my thoughts. (It will contain some duplication from the previous answer, so if this is a bad thing just let me know and I'll remove it :) ).
The Responsibility of ID generation can belong to different part of an organization or a system.
Sometimes the ID will be generated by some special rules like a Social Security Number. This number can be used for ID of a Person in a system, so before creating a Person entity this code will have to be generated from a specific SSNGenerator Service.
We can use a random generated ID like a UUID. UUIDs can be generated outside of the Repository and assigned to the entity during creation and the Repository will only store it (add, save) it to the DB.
IDs generated by databases are very interesting. You can have Sequential IDs like in RDBMS, UUID-ish like in MonogoDB or some Hash. In this case the Responsibility of ID generation is assigned to the DB so it can happen only after the Entity is stored not when it's created. (I'm allowing myself freedom here as you can generate it before saving a transaction or read the last one etc.. but I like to generalize here and avoid discussing cases with race conditions and collisions). This means that you Entity does't have an identity before the save completes. Is this a good thing? Of course It depends :)
This problem is a great example of leaky abstractions.
When you implement a solution sometimes the technology used will affect it. You will have to deal with the fact that for example the ID is generated by your Database which is part of your Infrastructure (if you have defined such a layer in your code). You can also avoid this by using s UUID even if you use a RDBMS, but then you have to join (again technology specific stuff :) ) on these IDs so sometimes people like to use the default.
Instead of having Add or AddAndCreate you can have Save method instead that does the same thing, it's just a different term that some people prefer. The repository is indeed often defined as an "In memory collection" but that doesn't mean that we have to stick to it strictly (It can be a good thing to do that most of the time but still...).
As mentioned, if you database generates ID's, the Repository seems like a good candidate to assign IDs (before of after storing) because it is the one talking to the DB.
If you are using events the way you generate ID's can affect things. For example lets say you want to have UserRegisteredEvent with the UserID as s property. If you are using the DB to generate ID's you will have to store the User first and then create and store/dispatch the event or do something of the sort. On the other hand if you generate the ID beforehand you can save the event and the entity together (in a transaction or in the same document doesn't matter). Sometimes this can get tricky.
Background, experience with technologies and framework, exposure to terminology in literature, school and work affects how we think about things and what terminology sounds better to us. Also we (most of the time) work in teams and this can affect how we name things and how implement them.
Using Martin Fowler's definition:
A Repository mediates between the domain and data mapping layers,
acting like an in-memory domain object collection. Client objects
construct query specifications declaratively and submit them to
Repository for satisfaction. Objects can be added to and removed from
the Repository, as they can from a simple collection of objects, and
the mapping code encapsulated by the Repository will carry out the
appropriate operations behind the scenes. Conceptually, a Repository
encapsulates the set of objects persisted in a data store and the
operations performed over them, providing a more object-oriented view
of the persistence layer
A Repository gives an Object Oriented view of the underlying Data (which may be otherwise stored in a relational DB). It's responsible for mapping your Table to your Entity.
Generating an ID for an object is whole different responsibility, which is not trivial and can get quite complex. You may decide to generate the ID in the DB or a separate service. Regardless of where the ID is generated, a Repository should seamlessly map it between your Entity and Table.
ID generation is a responsibility of its own, and if you add it to the Repository, then you are moving away from Single Responsibility Principle.
A side note here that using GUID for an ID is a terrible idea, because they are not sequential. They only meet the uniqueness requirement of an ID but they are not helpful for searching through the Database Index.
I am in the process of refactoring an application and am trying to figure out where certain logic should fit. For example, during the registration process I have to check if a user exists based upon their email address. As this requires testing if the user exists in the database it seems as if this logic should not be tied to the model as its existence is dictated by it being in the database.
However, I will have a method on the repository responsible for fetching the user by email, etc. This handles the part about retrieval of the user if they exist. From a use case perspective, registration seems to be a use case scenario and accordingly it seems there should be a UserService (application service) with a register method that would call the repository method and perform if then logic to determine if the user entity returned was null or not.
Am I on the right track with this approach, in terms of DDD? Am I viewing this scenario the wrong way and if so, how should I revise my thinking about this?
This link was provided as a possible solution, Where to check user email does not already exits?. It does help but it does not seem to close the loop on the issue. The thing I seem to be missing from this article would be who would be responsible for calling the CreateUserService, an application service or a method on the aggregate root where the CreateUserService object would be injected into the method along with any other relevant parameters?
If the answer is the application service that seems like you are loosing some encapsulation by taking the domain service out of the domain layer. On the other hand, going the other way would mean having to inject the repository into the domain service. Which of those two options would be preferable and more in line with DDD?
I think the best fit for that behaviour is a Domain Service. DS could access to persistence so you can check for existence or uniquenes.
Check this blog entry for more info.
I.e:
public class TransferManager
{
private readonly IEventStore _store;
private readonly IDomainServices _svc;
private readonly IDomainQueries _query;
private readonly ICommandResultMediator _result;
public TransferManager(IEventStore store, IDomainServices svc,IDomainQueries query,ICommandResultMediator result)
{
_store = store;
_svc = svc;
_query = query;
_result = result;
}
public void Execute(TransferMoney cmd)
{
//interacting with the Infrastructure
var accFrom = _query.GetAccountNumber(cmd.AccountFrom);
//Setup value objects
var debit=new Debit(cmd.Amount,accFrom);
//invoking Domain Services
var balance = _svc.CalculateAccountBalance(accFrom);
if (!_svc.CanAccountBeDebitted(balance, debit))
{
//return some error message using a mediator
//this approach works well inside monoliths where everything happens in the same process
_result.AddResult(cmd.Id, new CommandResult());
return;
}
//using the Aggregate and getting the business state change expressed as an event
var evnt = Transfer.Create(/* args */);
//storing the event
_store.Append(evnt);
//publish event if you want
}
}
from http://blog.sapiensworks.com/post/2016/08/19/DDD-Application-Services-Explained
The problem that you are facing is called Set based validation. There are a lot of articles describing the possible solutions. I will give here an extract from one of them (the context is CQRS but it can be applied to some degree to any DDD architecture):
1. Locking, Transactions and Database Constraints
Locking, transactions and database constraints are tried and tested tools for maintaining data integrity, but they come at a cost. Often the code/system is difficult to scale and can be complex to write and maintain. But they have the advantage of being well understood with plenty of examples to learn from. By implication, this approach is generally done using CRUD based operations. If you want to maintain the use of event sourcing then you can try a hybrid approach.
2. Hybrid Locking Field
You can adopt a locking field approach. Create a registry or lookup table in a standard database with a unique constraint. If you are unable to insert the row then you should abandon the command. Reserve the address before issuing the command. For these sort of operations, it is best to use a data store that isn’t eventually consistent and can guarantee the constraint (uniqueness in this case). Additional complexity is a clear downside of this approach, but less obvious is the problem of knowing when the operation is complete. Read side updates are often carried out in a different thread or process or even machine to the command and there could be many different operations happening.
3. Rely on the Eventually Consistent Read Model
To some this sounds like an oxymoron, however, it is a rather neat idea. Inconsistent things happen in systems all the time. Event sourcing allows you to handle these inconsistencies. Rather than throwing an exception and losing someone’s work all in the name of data consistency. Simply record the event and fix it later.
As an aside, how do you know a consistent database is consistent? It keeps no record of the failed operations users have tried to carry out. If I try to update a row in a table that has been updated since I read from it, then the chances are I’m going to lose that data. This gives the DBA an illusion of data consistency, but try to explain that to the exasperated user!
Accepting these things happen, and allowing the business to recover, can bring real competitive advantage. First, you can make the deliberate assumption these issues won’t occur, allowing you to deliver the system quicker/cheaper. Only if they do occur and only if it is of business value do you add features to compensate for the problem.
4. Re-examine the Domain Model
Let’s take a simplistic example to illustrate how a change in perspective may be all you need to resolve the issue. Essentially we have a problem checking for uniqueness or cardinality across aggregate roots because consistency is only enforced with the aggregate. An example could be a goalkeeper in a football team. A goalkeeper is a player. You can only have 1 goalkeeper per team on the pitch at any one time. A data-driven approach may have an ‘IsGoalKeeper’ flag on the player. If the goalkeeper is sent off and an outfield player goes in the goal, then you would need to remove the goalkeeper flag from the goalkeeper and add it to one of the outfield players. You would need constraints in place to ensure that assistant managers didn’t accidentally assign a different player resulting in 2 goalkeepers. In this scenario, we could model the IsGoalKeeper property on the Team, OutFieldPlayers or Game aggregate. This way, maintaining the cardinality becomes trivial.
You seems to be on the right way, the only stuff I didn't get is what your UserService.register does.
It should take all the values to register a user as input, validate them (using the repository to check the existence of the email) and, if the input is valid store the new User.
Problems can arise when the validation involve complex queries. In that case maybe you need to create a secondary store with special indexes suited for queries that you can't do with your domain model, so you will have to manage two different stores that can be out of sync (a user exists in one but it isn't replicated in the other one, yet).
This kind of problem happens when you store your aggregates in something like a key-value store where you can search just with the id of the aggregate, but if you are using something like a sql database that permits to search using your entities fields, you can do a lot of stuff with simple queries.
The only thing you need to take care is avoid to mix query logic and commands logic, in your example the lookup you need to do is easy, is just one field and the result is a boolean, sometimes it can be harder like time operations, or query spanning multiple tables aggregating results, in these cases it is better to make your (command) service use a (query) service, that offers a simple api to do the calculation like:
interface UserReportingService {
ComplexResult aComplexQuery(AComplexInput input);
}
That you can implement with a class that use your repositories, or an implementation that executes directly the query on your database (sql, or whatever).
The difference is that if you use the repositories you "think" in terms of your domain object, if you write directly the query you think in terms of your db abstractions (tables/sets in case of sql, documents in case of mongo, etc..). One or the other depends on the query you need to do.
It is fine to inject repository into domain.
Repository should have simple inteface, so that domain objects could use it as simple collection or storage. Repositories' main idea is to hide data access under simple and clear interface.
I don't see any problems in calling domain services from usecase. Usecase is suppossed to be archestrator. And domain services are actions. It is fine (and even unavoidable) to trigger domain actions by usecase.
To decide, you should analyze Where is this restriction come from?
Is it business rule? Or maybe user shouldn't be a part of model at all?
Usualy "User" means authorization and authentification i.e behaviour, that for my mind should placed in usecase. I prefare to create separate entity for domain (e.g. buyer) and relate it with usecase's user. So when new user is registered it possible to trigger creation of new buyer.
I am working on an application where we try to use a Domain Model. The idea is to keep the business logic inside the objects in the Domain Model. Now a lot is done by objects subscribing to related objects to react to changes in them. This is done through PropertyChanged and CollectionChanged. This work OK except in the following:
Complex actions : Where a lot of changes should be handled as a group (and not individual property/collection changes). Should I / how can I 'build' transactions?
Persistency : I use NHibernate for persistency and this also uses the public property setters of classes. When NHibernate hits the property a lot of bussiness logic is done (which seems unnecessary). Should I use custom setters for NHibernate?
Overal it seems that pushing all logic in the domain model makes the domain model rather complex. Any ideas???
Here's a 'sample' problem (sorry for the crappy tooling i use):
You can see the Project my container and objects below it are reacting to each other by subscribing. Now changes to Network are done via NetworkEditor but this editor has no knowledge of NetworkData. This data might even be defined in a another assembly sometimes. The flow goes from user->NetworkEditor->Network->NetworkData and the all other object interested. This does not seem to scale.
I fear that combination of DDD and PropertyChanged/CollactionChanged events might now be the best idea. The problem is, that if you base your logic around these events it is extremely hard to manage the complexity as one PropertyChanged leads to another and another and soon enough you loose control.
Another reason why ProportyChanged events and DDD doesn't exactly fit is that in DDD every business operation should be as explicit as possible. Keep in mind that DDD is supposed to bring technical stuff into the world of business, not the other way around. And basing on the PropertyChanged/CollectionChanged doesn't seem very explicit.
In DDD the main goal is to keep consistency inside aggregate, in other words, you need to model the aggregate in such way, that whatever operation you invoke the aggregate is valid and consistent (if the operation succeeds of course).
If you build your model right that there's no need to worry about 'building' transaction - an operation on aggregate should be a transaction itself.
I don't know how your model looks like, but you might consider moving the responsibilities one level 'up' in the aggregate tree, quite possibly adding additional logical entities in the process, instead of relying on the PropertyChanged events.
Example:
Lets assume you have a collection of payments with statuses and whenever a payment changes, you want to recalculate the total balance of customer orders. Instead of subscribing changes to the payments collection and calling a method on customer when collection changes, you might do something like this:
public class CustomerOrder
{
public List<Payment> Payments { get; }
public Balance BalanceForOrder { get; }
public void SetPaymentAsReceived(Guid paymentId)
{
Payments.First(p => p.PaymentId == paymentId).Status = PaymentStatus.Received;
RecalculateBalance();
}
}
You might have noticed, that we recalculate the balance of single order and not the balance of entire customer - and in most cases that's ok as customer belongs to another aggregate and its balance can be simply queried when needed. That is exactly the part that shows this 'consistency only within aggregate' thingy - we don't care about any other aggregate at this point, we only deal with single order. If that's not ok for requirements, then the domain is modeled incorrectly.
My point is, that in DDD there's no single good model for every scenario - you have to understand how the business works to be successful.
If you take a look at the example above, you'll see that there is no need to 'build' the transaction - entire transaction is located in SetPaymentAsReceived method. In most cases, one user action should lead to one particular method on an entity withing aggregate - this method explicitly relates to business operation (of course this method may call other methods).
As for events in DDD, there is a concept of Domain Events, however these are not directly related with PropertyChanged/CollectionChanged technical events. Domain Events indicate the business operations (transactions) that have been completed by an aggregate.
Overal it seems that pushing all logic in the domain model makes the
domain model rather complex
Of course it does as it is supposed to be used for scenarios with complex business logic. However if the domain is modeled correctly then it is easy to manage and control this complexity and that's one of the advantages of DDD.
Added after providing example:
Ok, and what about creating an aggregate root called Project - when you build aggregate root from Repository, you can fill it with NetworkData and the operation might look like this:
public class Project
{
protected List<Network> networks;
protected List<NetworkData> networkDatas;
public void Mutate(string someKindOfNetworkId, object someParam)
{
var network = networks.First(n => n.Id == someKindOfNetworkId);
var someResult = network.DoSomething(someParam);
networkDatas.Where(d => d.NetworkId == someKindOfNetworkId)
.ToList()
.ForEach(d => d.DoSomething(someResult, someParam));
}
}
NetworkEditor would not operate on Network directly, rather through Project using NetworkId.
I'm looking for some advice on how much I should be concerned around avoiding the anemic domain model. We are just starting on DDD and are struggling with analysis paralysis regarding simple design decisions. The latest point we are sticking on is where certain business logic belongs, for example we have an Order object, which has properties like Status etc. Now say I have to perform a command like UndoLastStatus because someone made a mistake with an order, this is not as simple as just changing the Status as other information has to be logged and properties changed. Now in the real world this is a pure administration task. So the way I see it I have two options I can think of:
Option 1: Add the method to order so something like Order.UndoLastStatus(), whilst this kinda make sense, it doesn't really reflect the domain. Also Order is the primary object in the system and if everything involving the order is placed in the order class things could get out of hand.
Option 2: Create a Shop object, and with that have different services which represent differant roles. So I might have Shop.AdminService, Shop.DispatchService, and Shop.InventoryService. So in this case I would have Shop.AdminService.UndoLastStatus(Order).
Now the second option we have something which reflects the domain much more, and would allow developers to talk to business experts about similar roles that actually exists. But its also heading toward an anemic model. Which would be the better way to go in general?
Option 2 would lead to procedural code for sure.
Might be easier to develop, but much harder to maintain.
Now in the real world this is a pure administration task
"Administration" tasks should be private and invoked through public, fully "domain`ish" actions. Preferably - still written in easy to understand code that is driven from domain.
As I see it - problem is that UndoLastStatus makes little sense to domain expert.
More likely they are talking about making, canceling and filling orders.
Something along these lines might fit better:
class Order{
void CancelOrder(){
Status=Status.Canceled;
}
void FillOrder(){
if(Status==Status.Canceled)
throw Exception();
Status=Status.Filled;
}
static void Make(){
return new Order();
}
void Order(){
Status=Status.Pending;
}
}
I personally dislike usage of "statuses", they are automatically shared to everything that uses them - i see that as unnecessary coupling.
So I would have something like this:
class Order{
void CancelOrder(){
IsCanceled=true;
}
void FillOrder(){
if(IsCanceled) throw Exception();
IsFilled=true;
}
static Order Make(){
return new Order();
}
void Order(){
IsPending=true;
}
}
For changing related things when order state changes, best bet is to use so called domain events.
My code would look along these lines:
class Order{
void CancelOrder(){
IsCanceled=true;
Raise(new Canceled(this));
}
//usage of nested classes for events is my homemade convention
class Canceled:Event<Order>{
void Canceled(Order order):base(order){}
}
}
class Customer{
private void BeHappy(){
Console.WriteLine("hooraay!");
}
//nb: nested class can see privates of Customer
class OnOrderCanceled:IEventHandler<Order.Canceled>{
void Handle(Order.Canceled e){
//caveat: this approach needs order->customer association
var order=e.Source;
order.Customer.BeHappy();
}
}
}
If Order grows too huge, You might want to check out what bounded contexts are (as Eric Evans says - if he had a chance to wrote his book again, he would move bounded contexts to the very beginning).
In short - it's a form of decomposition driven by domain.
Idea is relatively simple - it is OK to have multiple Orders from different viewpoints aka contexts.
E.g. - Order from Shopping context, Order from Accounting context.
namespace Shopping{
class Order{
//association with shopping cart
//might be vital for shopping but completely irrelevant for accounting
ShoppingCart Cart;
}
}
namespace Accounting{
class Order{
//something specific only to accounting
}
}
But usually enough domain itself avoids complexity and is easily decomposable if You listen to it closely enough. E.g. You might hear from experts terms like OrderLifeCycle, OrderHistory, OrderDescription that You can leverage as anchors for decomposition.
NB: Keep in mind - I got zero understanding about Your domain.
It's quite likely that those verbs I'm using are completely strange to it.
I would be guided by the GRASP principles. Apply the Information Expert design principle, that is you should assign the responsibility to the class that naturally has the most information required to fulfill the change.
In this case, since changing the order status involves other entities, I would make each of these low-level domain objects support a method to apply the change with respect to itself. Then also use a domain service layer as you describe in option 2, that abstracts the whole operation, spanning multiple domain objects as needed.
Also see the Facade pattern.
I think having a method like UndoLastStatus on the Order class feels a bit wrong because the reasons for its existence are in a sense outside of the scope of an order. On the other hand, having a method which is responsible for changing the status of an order, Order.ChangeStatus, fits nicely as a domain model. The status of an order is a proper domain concept and changing that status should be done through the Order class, since it owns the data associated with an order status - it is the responsibility of the Order class to keep itself consistent and in a proper state.
Another way to think of it is that the Order object is what's persisted to the database and it is the 'last stop' for all changes applied to an Order. It is easier to reason about what a valid state for an order might be from the perspective of an Order rather than from the perspective of an external component. This is what DDD and OOP are all about, making it easier for humans to reason about code. Furthermore, access to private or protected members may be required to execute a state change, in which case having the method be on the order class is a better option. This is one of the reasons why anemic domain models are frowned upon - they shift the responsibility of keeping state consistent away from the owning class, thereby breaking encapsulation among other things.
One way to implement a more specific operation such as UndoLastStatus would be to create an OrderService which exposes the domain and is how external components operate upon the domain. Then you can create a simple command object like this:
class UndoLastStatusCommand {
public Guid OrderId { get; set; }
}
An the OrderService would have a method to process that command:
public void Process(UndoLastStatusCommand command) {
using (var unitOfWork = UowManager.Start()) {
var order = this.orderRepository.Get(command.OrderId);
if (order == null)
throw some exception
// operate on domain to undo last status
unitOfWork.Commit();
}
}
So now the domain model for Order exposes all of the data and behavior that correspond to an Order, but the OrderService, and the service layer in general, declare the different kind of operations that are performed on an order and expose the domain for utilization by external components, such as the presentation layer.
Also consider looking into the concept of domain events which considers anemic domain models and ways of improving them.
It sounds like you are not driving this domain from tests. Take a look at the work of Rob Vens, especially his work on exploratory modeling, time inversion and active-passive.
I'm looking for some advice on architecture for a client/server solution with some peculiarities.
The client is a fairly thick one, leaving the server mostly to peristence, concurrency and infrastructure concerns.
The server contains a number of entities which contain both sensitive and public information. Think for example that the entities are persons, assume that social security number and name are sensitive and age is publicly viewable.
When starting the client, the user is presented with a number of entities, not disclosing any sensitive information. At any time the user can choose to log in and authenticate against the server, given the authentication is successful the user is granted access to the sensitive information.
The client is hosting a domain model and I was thinking of implementing this as some kind of "lazy loading", making the first request instantiating the entities and later refreshing them with sensitive data. The entity getters would throw exceptions on sensitive information when they've not been disclosed, f.e.:
class PersonImpl : PersonEntity
{
private bool undisclosed;
public override string SocialSecurityNumber {
get {
if (undisclosed)
throw new UndisclosedDataException();
return base.SocialSecurityNumber;
}
}
}
Another more friendly approach could be to have a value object indicating that the value is undisclosed.
get {
if (undisclosed)
return undisclosedValue;
return base.SocialSecurityNumber;
}
Some concerns:
What if the user logs in and then out, the sensitive data has been loaded but must be disclosed once again.
One could argue that this type of functionality belongs within the domain and not some infrastructural implementation(i.e. repository implementations).
As always when dealing with a larger number of properties there's a risk that this type of functionality clutters the code
Any insights or discussion is appreciated!
I think that this is actually a great example of using View Models. Your concern seems directly related to the consumption of the entities, because of the data that they contain. Instead of passing your entities all the way up to the UI, you could restrict them to live within the domain only - i.e. no entities are passed into or out of the domain at all, with most/all activities done with a command/query approach on the repositories. Repositories would then return a view model instead of the entity.
So how/why does this apply? You could actually have two different view models. One for authenticated and one for non-authenticated users. You expose the actual values for the sensitive data in the authenticated view model and not for the non-authenticated one. You could have them derived from a common interface, and then code against the interface instead of the object type. For your concrete implementation of the non-authenticated user, you can just populate the non-sensitive data, leaving the sensitive getters to do what you want them to do.
My opinion on a couple of points:
I am not a fan of lazy loading in entities. Lazy loading is a data access responsibility and not really part of the model. For me, it is a first-class member of the things I vehemently avoid in my domain, along with paging and sorting. As for how to relate these items together, I would rather loosely couple the objects via ID pointers to other entities. If I want/need the data contained by one of these entities, then I can load it. It is kind of like lazy loading in a way, but I enforce that it never happens in the domain model itself by doing this.
I am not a fan of throwing exceptions on getters. Setters, on the other hand, is fine. I look at it this way. The entity should always be in a valid state. Getters will not impact the state of the entity - setters will. Throwing on a setter is enforcing the integrity of the model. Using the two view model approach would allow me to move the logic to the presenter. So, I could basically do something like "if user is of type non-authorized, do this; otherwise do something else". Since what you are referring to would ultimately be a case of how the data is presented to the user, and not important to the model, I think it fits well. In general, I use nullable types for my properties that can be null and do not enforce anything on the getters, as it is not part of its responsibility, usually. Instead, I use roles to determine what view model to use.
The obvious drawback is that there is more coding required to use the view models, but it comes at the obvious benefit of decoupling presentation and views from the domain. It also will help in unit/integration testing, where you can verify that a certain view model cannot return a type of data.
However, you can use something akin to AutoMapper (depending on what your platform is) to help in populating your view model from your entities.
I made the mistake of posting the question without creating an OpenId so it looks like I'll have to comment here(?).
First of all, thanks for taking you time to answer - It certainly has more to do with how data is presented than how the model works. However, I feel the need to clarify a few things.
The domain model / entities are never referenced directly from the UI. I'm using a variant of the DM-V-VM pattern for UI/business model separation. For lazy loading and repository implementation in general I have entity implementations in a infrastructure layer where things like serialization, dirty tracking and lazy loading is handled.
So the domain layer has entities like:
class Entity {
virtual string SocialSecurityNumber { get; }
}
And the infrastructure layer adds some other functionality to be able to update and restore entites from a server:
class EntityImpl : Entity {
bool isDirty;
bool isLoaded;
// Provide the means to set value on deserialization
override string SocialSecurityNumber;
}
So the lazy loading behavior would be implemented in the infrastructure layer and never seen by the domain layer.
I agree that throwing on getters wouldn't be nice but my concerns are on how an anonymous view model would retrieve the data. As of now, to retrieve a list of entities the viewmodel would hold a reference to a domain repository, should I have two repositories, one for authenticated(and therefore disclosed) entities, and another one for the unauthenticated users - maybe even two different entities?