Auctions have no concept of "repository"; it's a technical concern
leaking into and polluting the domain of auctions. If I want to model
a collection of domain-things I look for the appropriate concept in
the domain. I often model that as an interface in the application
domain model and then implement it in memory (wrapping a collection)
or using some underlying technology in an adapter layer that maps
domain concepts onto technical concepts.
In GOOS, for example, we introduce an AuctionHouse to represent one
collection of Auctions, being run by some organisation, and a
Portfolio as another collection of Auctions that the user is bidding in.
We deliberately did not call either AuctionRepository, because the
word Repository is vague and has no meaning in the domain, because we
try to avoid naming classes after patterns, and because it wouldn't
distinguish between the two quite different collections of auctions.
--Nat
> We deliberately did not call either AuctionRepository, because the
> word Repository is vague and has no meaning in the domain, because we
> try to avoid naming classes after patterns, and because it wouldn't
> distinguish between the two quite different collections of auctions.
I hadn't thought about this, Nat, but it seems to me that *Repository
represents yet another structurally accurate name begging for us to
refactor it into more intention-revealing classes, such as
AuctionHouse and Portfolio. Very nice.
--
J. B. (Joe) Rainsberger :: http://www.jbrains.ca ::
http://blog.thecodewhisperer.com
Diaspar Software Services :: http://www.diasparsoftware.com
Author, JUnit Recipes
2005 Gordon Pask Award for contribution to Agile practice :: Agile
2010: Learn. Practice. Explore.
I did some refactoring on my last project on some code which had been written by someone in the Spring camp: lots of DAO's, Service's, etc. I don't remember the detail, but I changed one name from XXXService to something more relevant to the domain (let's say a GribbleFoo). All of a sudden, it was obvious that some of the behaviour was in the wrong place. The language in the code didn't make sense any more because GribbleFoo's don't do that. A little Intellj magic and the result was much cleaner.
I've often seen GribbleService types become a bloated dumping ground for everything to do with Gribbles, because there's no criteria for what they /don't/ do.
S.
Sure, the implementation might be to hold a collection, but what does the rest of the codebase think of them?
Another example that came up in a recent project is that of an 'order management system'. Naturally, this system had Orders, and the first three attempts (before we got there) had OrderDAO, OrderService, etc. Given that we could start again, we introduced an OrderBook (which was an interface) and lived happily within the domain. This had an implementation called HibernateOrderBook and another called OrderBookView (that did some filtering and sorting), but all the domain ever saw was an OrderBook.
Another example from the same system was that the original attempts had User, UserDAO, UserService, etc. Now users are frequently problematic in a system, because their is no 'user' in the domain. There were, however, sales-people. So we also had SalesForce as a domain model concept.
Finally, from the same system, the sales force talked to clients. Once again, there was Client (good), ClientDAO and ClientService. We had Client and ClientBook.
Regards,
Lance
A DAO or Repository typically has many query methods that provide
services for many tenants, e.g., OrderDAO.findFor(SalesForce). A
typical answer to that query would be a Collection<Order>. In your
case, does OrderBook fulfill the same responsibilities, or is it
something with which a domain concept, such as Client or SalesForce,
directly has an association that is unique to it? In other words, is
OrderBook a concept for a specific set of orders for a specific
client?
We sometimes did things such as gave the SalesForce implementation a reference to the OrderBook so that clients of the SalesForce didn't need an OrderBook as well (e.g. SalesForce.listOrders() forwards to OrderBook.list()). This was very much done as it made sense, to reduce coupling, etc.
But remember that OrderBook, SalesForce, etc. are interfaces, so how one particular implementation works is completely unknowable from any client code.
Regards,
Lance
Sent from my iPhone
How might the interface look to get a SalesForce or an OrderBook
reference from a datastore? What class would be responsible for a
query such as:
return all SalesForce's with OrderBooks of less than $1 million last year
Thanks.
On Mon, Sep 6, 2010 at 5:21 AM, Lance Walton
Imagine having a SalesPersonDAO, OrderDAO and ClientDAO. These are not business domain concepts, so we don't like referencing them from the business domain model (henceforth referred to as THE domain model). So one solution is to have a service layer that gets references to those DAOs, pulls what is needed out of them in order to do each piece of functionality and then, maybe passes control to whatever Orders, SalesPerson or Client that it has retrieved.
Instead of that, imagine making SalesPersonDAO implement SalesForce, OrderDAO implement OrderBook and ClientDAO implement ClientBook (it may not actually be implemented this way, but nothing else in the system will care now as long as you make sure the interface isn't leaking details of the DAOness). Package the SalesForce, OrderBook and ClientBook with the domain model because they can rightfully be viewed as part of the domain model. You now have persistence layer classes implementing domain model interfaces.
Now, you might still need a service layer which has references to these things as an entry point to your system and to coordinate activity between diverse parts of the domain model, but you can also pass SalesForce, OrderBook and ClientBook into whatever domain model methods you call so that the domain model can rummage around in the SalesForce, OrderBook and ClientBook as it needs to. This keeps the knowledge of how the domain model does its work local to the domain model, rather than distributing it between the domain model and the service layer.
Another solution to passing those objects into the domain model is to inject them at the point that the domain model objects are bought into existence from persistence. Hibernate lifecycle events can do this, for example. But even though I've done this on one project and it worked pretty well, I'm not sure if it's elegant or a horrible bodge and I have a sense of dirtiness about it.
With regard to the query you ask about: we only had one SalesForce who's OrderBook was being maintained, so it wouldn't have made sense for us. However, if we wanted to use the OrderBook or SalesForce interfaces to provide some subset of the whole, then we'd just put a method on whichever of OrderBook or SalesForce that made sense at the time and give it some appropriate name. That's a judgement based on what you have in scope at the time, minimising coupling, etc. Whether this returned an instance (or collection of instances )of SalesForce or not we'd make a judgement of on a case by case basis. If we did do that, the implementation of that SalesForce implementation for this purpose would again be down to judgement.
By the way, we didn't shy away from putting findById() type methods on these interfaces. Maybe if we'd spelled that as Chaucer would have done it would have retained the flavour of it :-) But there's nothing in principle that ties a numeric id to the notion of a relational (or other kind of technological) database. Raffle tickets, buses and the works of J.S.Bach are all uniquely numbered without there being a 'database'.
But the central point of this is to allow the domain model access to the abstraction without fhe domain model is becoming intimate with knowledge of the persistence layer. Everything else is a problem left for the reader :-)
Regards,
Lance