Domanda

http://i.stack.imgur.com/YZXZN.png (I'm currently not allowed to embed images)

I could really use some help with my class model above. I'm ashamed to say that I have been one of "those" developers that learned object orientation at university, wrote the exams, aced them but then never set about implementing the principles in my real world code. I never truly sat down and considered my application design before beginning the codification of it. Thus my design and coding skills have been slowly dying and stagnating under the weight of monolithic legacy banking application development and maintenance. After years of this I've decided that it's definitely time for a change! I've been delving deep into the world of design patterns, DDD, NoSQL, DI, etc etc. The last 2 weeks have been a really intense experience for me, and at times I think I was nearly brought to tears at the sheer volume of best practices and tech that I had missed while working for large corporations and banks. I simply couldn't believe how far removed I had been from cutting edge tech and good design approaches for so long, and the sudden swathe of everything threatened to send me into a state of coding paralysis! I simply could not start coding, as I felt my design needed more tweaking, or I needed more studying on a particular topic. Enough is enough though, and I need to crack on and at least make a first iteration on the project.

Anyway, enough of the drama, on to my issue:

I have begun work on the model creation for my golfing app. Wanting to adhere somewhat to DDD and also wanting to make use of NoSQL (RavenDB), I set about with the following requirements.

  • My platform stack is Windows / IIS / MVC 3.0 / RavenDB
  • I need to find my aggregate roots! I have set about defining them as the only elements in my system that are capable of persisting in their own right. Everything else I've simply deemed a "sub-component" of the aggregates. Note that no real behaviour has yet been defined.
  • My aggregate roots will be the only classes to actually persist in my RavenDB doc store, and they will persist "as-is". Having large tree-like class structures would appear to be a best case scenario for RavenDB in terms of performance benefits realised.
  • I don't feel the need for a repository layer (been following some of Ayende's posts), as the RavenDB API feels fluent and quite lightweight. I'll be simply opening and closing my sessions via Custom Action Attributes on my controllers where required. I've seen that without the repository layer testing might be tricky, but surely I should be able to simply mock some "in-memory" domain objects?
  • Writes to the DB will happen in a separate service layer
  • At one point I stopped and asked myself: "Where on earth am I going to put my domain behaviour!?". The general consensus from searching the web would seem to indicate I should leave my domain (entities) void of any behaviour (business logic) and have it all handled in my service layer. But after reading some Eric Evans, I'm convinced that as much of my domain behaviour should exist right there... in the domain!

Questions - As a bona fide noob in the area of DDD and architectural design, am I at least on the right track, or am I destined for destruction? - Any thoughts, admonishments, constructive criticism and insights into the above would be greatly appreciated!

È stato utile?

Soluzione

To counter being overly academic about it all and be stuck in analysis too long: First make it work. Then make it pretty.

Put behavior near data as much as possible. Use services where you can't cleanly assign a responsibility to a class (e.g. should a 'transfer money' method be on an SavingsAccount class?). Services can be part of an aggregate.

Do use repositories (I don't agree with Ayende). You mention using a separate service layer for DB writes. Repository is a perfect interface to put that layer behind. It's also a perfect testing seam.

Didn't look at your class diagram thoroughly, but you may be overusing inheritance here and there. Favor composition over inheritance. Inheritance can rear it's ugly head quite quickly.

When choosing aggregate roots, an important criteria is life cycle. When the aggregate root dies, everything else in the aggregate dies also. The aggregate root is also in control, everything outside the aggregate passes through it. When in doubt just create a lot of them (single entity aggregate). With a document database you would typically store a document per aggregate, so that does matches somewhat with how you choose them. Store IDs of references to different aggregates.

Altri suggerimenti

So yeah, going down the rabbit hole will not increase your productivity in short term, but may help you mature as a developer in long term. There is so much to DDD, NoSQL, etc that you could spend years just learning.

If you want your next project to be successful, my advice would be to stick to what you know, and introduce new techniques gradually so that you can always feel in full control, and not depend on "best practices" someone has to put up for you.

Firstly, may I congratulate you on deciding to take the steps to try and become more professional. I despair at the lack of profession in this industry and sometimes feel like I'm walking amongst 80% cowboys/hackers 20% professionals.

To your question:

  • Have you read this article by Vaughn Veron? If not, you should. It provides an excellent guide to designing aggregates, which I think is underrated in its complexity.
  • Looking at your model, I'm not sure if you actually have defined aggregates? I can see you have identified aggregate roots, but the aggregates should have clear boundaries and be separate from other aggregates (i.e. don't have entities referencing other aggregate roots, let them reference their ID). The property name RefereeUserIDList hints that you are in fact doing this, but the diagram shows it holding reference to the actual 'User' aggregate root?
  • In terms of identifying aggregates & roots & the model design, I don't really think we can help you here as this is entirely circumstantial to the behavioural requirements. I will say though: try to base your design on behaviour, not data structure. It's a difficult mindset to shift to, but try not picturing the database structure.
  • I haven't read what Ayende has said about repositories, but as long as you can mock the Raven API (which I assume you can given he made Rhino mocks) then it shouldn't be a problem.
  • Possibly most importantly, do not put all your domain logic into the service layer. You'll end up with an Anemic domain model, which is the DDD equivalent to the anti-christ.
  • Personally when learning DDD I understood all of the principals but struggled when attempting to turn theory into practice. If I'm honest I'd say I've only really been successful with it since I understood the principals CQRS which compliments DDD. I'd really recommend watching some videos on the subject by Greg Young.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top