tag:blogger.com,1999:blog-15136575.post7945071185012595396..comments2023-10-17T12:00:16.772+01:00Comments on Code rant: Eric Evans on RepositoriesMike Hadlowhttp://www.blogger.com/profile/16441901713967254504noreply@blogger.comBlogger9125tag:blogger.com,1999:blog-15136575.post-76694713060068167462015-05-23T11:06:47.655+01:002015-05-23T11:06:47.655+01:00This book is not that clear to be honest. It says ...This book is not that clear to be honest. It says that value objects should be interchangeable (you could swap any two value objects without care).<br /><br />Well if I swap one name object (Fred Williams) with another name object (Joe Bloggs), then this will definitely have repercussions for the system.<br /><br />You're sure these are value objects?Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-15136575.post-66460078070413155082009-03-02T10:24:00.000+00:002009-03-02T10:24:00.000+00:00Mike,It's more about identity than immutability. E...Mike,<BR/><BR/>It's more about identity than immutability. Entities have an independent identity. You can ask for an individual entity by it's ID. value types only exist in terms of their parent entities and have no separate identity. Think of a line (Entity) made up of some points (Value), or a contact (Entity) that has an address (Value). <BR/><BR/>A common anti-pattern is to have entities with large numbers of properties with basic types (int, string). Often they map 1-to-1 to a database table. Individual or groups of basic types usually have some meaning in terms of the business and should be factored into to value types.<BR/><BR/>Take a contact for example:<BR/><BR/>public class Contact<BR/>{<BR/> public int Id { get; set; }<BR/> public string FirstName { get; set; }<BR/> public string LastName { get; set; }<BR/> public string Address1 { get; set; }<BR/> public string Address2 { get; set; }<BR/> public string City { get; set; }<BR/> public string Postcode { get; set; }<BR/>}<BR/><BR/>It's an entity (has an Id) that has basic type properties that map directly to table columns. It might make more sense as:<BR/><BR/>public class Contact <BR/>{<BR/> public int Id { get; set; }<BR/> public Name Name { get; set; }<BR/> public Address Address { get; set; }<BR/>}<BR/><BR/>public class Name<BR/>{<BR/> public string FirstName { get; set; }<BR/> public string LastName { get; set; }<BR/>}<BR/><BR/>public class Address<BR/>{<BR/> public string Address1 { get; set; }<BR/> public string Address2 { get; set; }<BR/> public string City { get; set; }<BR/> public string Postcode { get; set; }<BR/>}<BR/><BR/>Here, Name and Address are value types, they don't have an Id. Why is this good? Because we're decoupling stuff to do with names from stuff to do with addresses. We can reuse name and address in other entities, but they make no sense and independent things. Note that the database table wouldn't change, we're breaking the 1-to-1 class-to-table link that's often the naive starting point for most object-relational mapping.<BR/><BR/>One problem I have with Evan's book is that it's long on theory and short on example and I think the Entity/Value distinction is a great example of this. He explains the difference in the abstract at great length, but without enough concrete examples to really cement what he's saying.Mike Hadlowhttps://www.blogger.com/profile/16441901713967254504noreply@blogger.comtag:blogger.com,1999:blog-15136575.post-70013031068788824812009-02-28T20:13:00.000+00:002009-02-28T20:13:00.000+00:00I'm reading through Domain Driven Design. One thi...I'm reading through Domain Driven Design. One thing that bugs me is the idea of a "value" type. Why not just call those objects immutable entities? Maybe it's just a personal preference, but in my opinion, building "values" into the design adds little value. They only encapsulate a subset of entity values. Why not just specify immutable entities? Any thoughts?Mike Boldischarhttps://www.blogger.com/profile/11602368403680258990noreply@blogger.comtag:blogger.com,1999:blog-15136575.post-46552102355719720532009-01-19T13:35:00.000+00:002009-01-19T13:35:00.000+00:00Something to bear in mind the discussion of IQuery...Something to bear in mind the discussion of IQueryable being part of the framework and therefore should be used to provide querying logic is beside the point.<BR/><BR/>What should matter is that a the Repository Pattern is a technique/practice which is abstract on his own which requires adherence to some principles. Those principles, such as SOLID, are not related to what's technically possible but by what constitutes good design and some say good design is one that is easy to change but some might think differently hence this discussion :)Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-15136575.post-66078971518652015402009-01-19T09:44:00.000+00:002009-01-19T09:44:00.000+00:00Bryan, that's also my view, but it's a minority on...Bryan, that's also my view, but it's a minority one. Most of the comments I've read about returning IQueryable'1 from a repository are against the idea. They say it allows query logic to leak into other parts of the application and means that the execution of the query can take place at some unspecified time.<BR/><BR/>As for who consumes repositories, there's an argument that it should only be domain services. I'm a bit more relaxed and have controllers consume repositories, but I can see that at certain scales enforcing the former rule might make sense.<BR/><BR/>I also think that much of the argument is about terminology. One man's domain service is another mans repository. What to me is a generic repository consumed by domain services, is to others a repository abstraction consumed by repositories.Mike Hadlowhttps://www.blogger.com/profile/16441901713967254504noreply@blogger.comtag:blogger.com,1999:blog-15136575.post-20596425391143086792009-01-18T11:53:00.000+00:002009-01-18T11:53:00.000+00:00One of the points that has been danced around is t...One of the points that has been danced around is that IQueryable`1 is a framework-level abstraction. With no other persistence-related decisions, you can confidently use it for queries where there would otherwise be nothing. IRepository`1 is the natural other half of the story, the persistent aspect of the abstraction.<BR/><BR/>This gels with DDD, as it removes technical concerns from the domain; the focus is then on <I>which</I> queries to issue and <I>when</I> to make changes.<BR/><BR/>That statement is predicated upon some assumptions I'd like to see you discuss (@Mike and @Colin) about who consumes repositories.<BR/><BR/>I venture to say domain services are the target consumers; they provide operations in the Ubiquitous Language on top of the query/persistence elements. As such, generalization is very very good, instead of YAGNI.<BR/><BR/>Thoughts?Bryan Wattshttps://www.blogger.com/profile/12956937293534286535noreply@blogger.comtag:blogger.com,1999:blog-15136575.post-75789321199462352542009-01-18T08:07:00.000+00:002009-01-18T08:07:00.000+00:00Greg Young has an excellent post arguing against g...Greg Young has an excellent post arguing against generic repositories here: <A HREF="http://codebetter.com/blogs/gregyoung/archive/2009/01/16/ddd-the-generic-repository.aspx" REL="nofollow">http://codebetter.com/blogs/gregyoung/archive/2009/01/16/ddd-the-generic-repository.aspx</A>Mike Hadlowhttps://www.blogger.com/profile/16441901713967254504noreply@blogger.comtag:blogger.com,1999:blog-15136575.post-86423128348778384562009-01-18T07:55:00.000+00:002009-01-18T07:55:00.000+00:00Hi Colin, Thanks for another excellent comment; th...Hi Colin, <BR/><BR/>Thanks for another excellent comment; this series of posts is turning into 'Colin Jack educates Mike Hadlow about DDD'. Sorry I'm such an argumentative and poor student :)<BR/><BR/>"... on the four points ..." Just because you have a generic repository interface, doesn't mean that you can't have diverse implementations. It's certainly possible to use diverse data sources. Of course the design of the generic repository imposes certain expectations about the data provider. Returning IQueryable'1 means that it must have a LINQ provider for example. Substituting generic repositories for testing has worked well for me. I simply return an in-memory object graph from the IQueryable'1 method. The specification extension methods then work with LINQ-to-Objects automatically, there's no need to substitute them.<BR/><BR/>"UOW is actually awkward as far as DDD..." you've lost me there. Do you have a pointer to a fuller explanation?<BR/><BR/>"Keep the concept of 'factory' and 'repository' distinct.. " Yes, absolutely. I was just paraphrasing the book. Evans suggests that a repository might 'create' (reconstitute from the DB) objects using the same factory that the client uses for creating them, but of course using an ORM like NHibernate means that you would never do that.<BR/><BR/>"The core point..." Yes, I guess that's what Evans says. I didn't phrase it very well, he is quite happy to mix and match repository methods and specifications on a repository. My thoughts are that the only thing that differentiates repositories are their queries. If you wrap all your queries up as specifications then surely what you are left with is a generic repository?<BR/><BR/>"That's something I'm keen to correct... " Yes, but we're talking about IQuerayble'1 where 1 is the aggregate root. It's still a query on the aggregate.Mike Hadlowhttps://www.blogger.com/profile/16441901713967254504noreply@blogger.comtag:blogger.com,1999:blog-15136575.post-42233465928516322622009-01-17T22:35:00.000+00:002009-01-17T22:35:00.000+00:00Hi,Yeah on the four points you give its worth cons...Hi,<BR/><BR/>Yeah on the four points you give its worth considering how many generic repositories fulfill. Simple, guess so because queries move elsehwere. Decouple from persistence to allow multiple DB's data sources, not so much. Communicate design decisions, less than concrete. Allow easy substitution, yes...but only if you can substitute all queries.<BR/><BR/>UOW is actually awkward as far as DDD, something that's been discussed in ALT.NET forum recently and that I've blogged vaguely about. Essentially you want to ensure all invariants for an aggregate are met before persisting the aggregate and UOW's don't normally aim for that usage model.<BR/><BR/>"Keep the concept of ‘factory’ and ‘repository’ distinct, although, in theory, a repository might use a factory internally." -> Guess it depends what you mean but normally repositories wouldn't create objects at all.<BR/><BR/>"The core point is that specification definition is a domain concern and is best decoupled from the repository, although earlier he does say that in simple situations it might make sense to have methods on the repository to encapsulate queries." -> You can do both, have the names methods and then have them use specifications if that helps (which is what I often prefer). Specifications written using Linq are useful tho.<BR/><BR/>"That’s something I’m keen to correct. As for the debate about exposing IQueryable’1, Evans doesn’t have much to say. " -> There has been lots of discussions on DDD forum. To me repositories are about aggregates, so returning IQueryable is not in keeping.<BR/><BR/>Ta,<BR/><BR/>ColinColin Jackhttps://www.blogger.com/profile/01403166737046938219noreply@blogger.com