Fri Sep 5, 2003 11:30 am
An idea I'm toying with, and on which I'd appreciate the thoughts of
this group, is representing the domain using XML Schema (XSD). The
application I'm working with is built with the .NET framework, which
has some very good XML tools; and so this feels like a good fit.
My thought is that I could represent entities in XSD; defining their
attributes and relationships to other entities all at this generic
level. For example, using XSD I could define that this XML is to be
used for representing a customer with a first name of "John" and a
last name of "Doe":
<customer>
<firstName>John</firstName>
<lastName>Doe</lastName>
</customer>
Further, I could have a company attribute that relates the customer
to a company entity. I believe I could even go so far as specifying
the maximum number of characters allowed for each attribute.
Essentially all of the entity objects could be represented in one or
multiple XSD files.
Using the XSD I could use code generation techniques for building
the domain objects, the backend database, repository objects, etc.
Beyond this, I would have a generic schema that could be used for
building other features that require generic knowledge of all
entities and attributes.
This seems like a sound idea to me, and provides for some nice
expandability. Using code generation I can have the benefits of a
non-hardcoded schema, but performance will not suffer as much as if
I were looking to XML files at runtime for schema information.
Any thoughts regarding this? Has anyone else here attempted such an
architecture, if so what kinds of issues did you run into? Any book
recommendations that would help with this (I'm already looking into
an O'Reilly XML Schema book as well as a book entitled "Code
Generation in Action." Not to mention "Domain Driven Design.")?
Thanks for any input,
JordanMatthiesen
An XML schema can describe the data attributes and relationships of
Entities and
ValueObjects, but it cannot capture their behavioral
responsibilities. In this it is similar to the database -- one
implementation form that should reflect aspects of the model (or if it does
not, then it should be treated as a separate bounded context). A common use
of this kind of schema is for integration (maybe as a "published language").
As far as generating the objects based on the schema, people do try things
like that. The advantage is that you are guaranteed to be consistent
between the objects and the XML. But regeneration can be a problem unless
you keep your objects dumb data containers. And it takes the attention away
from the process of model behavior and rules.
Another approach would be to generate the XML schema from the objects. It
might require attaching some extra metadata, but would give a similar
benefit in terms of consistency and eliminating redundant work.
EricEvans
Thanks for the response. The main thing I'm looking at using XSD
for are purely schema related items; a generic way of knowing how
entities are related and what attributes they make available, as
well as what
ValueObject details. Behavior would most likely be in
a Service layer. Sorry that I didn't make that more clear in the
first post.
Entity objects and
ValueObjects would be data containers, with the
most logic in them likely being for performance, using Lazy Load
(loading entities from the repository only when the data is
needed). I think Repositories could be generated to an extent, but
they would probably have more complex logic related to data
retrieval than could be derived from the schema (for example: a tree
structure stored in the database may not be a direct mapping to the
object references in the entities; it could be the same, but most
likely wouldn't be).
JordanMatthiesen
I've been on teams that have built systems that are very similar
to what you describe. I also know of a few others that are doing
similar things. (All in .NET).
There are a few major complications:
Meta Data Schema Is Limiting
The meta-data schema and corresponding code generation can impose too
many constraints on your domain object evolution. For example, you
may want to express simple constraints on object properties in the
meta-data. The constraint syntax will probably not be sufficient over
time. Do you know extend the framework or do you implement the
business rule in another way?
Testing and Refactoring are Hard
Automated unit tests can be quite slow, as the generated code may
want to persist to a database, file, etc. It also can become quite
hard to write isolated tests. This impediment can cause some to
abandon unit tests or make it hard to add unit tests later.
Refactoring is harder as refactoring the generated code requires a
change to the code generator.
There are other problems that I've encountered, but the most
significant complication is that a meta-data format is static in
nature. It encourages a "noun" based view of the domain
model. I think a domain model is both the data of the objects and the
corresponding behavior. Though you can put these in a service layer
(as you mentioned) or some other design, it breaks down the
encapsulation of an object oriented domain model.
I prefer an approach where you write your domain objects in code and
let them evolve as appropriate for the domain. Most times, such
approaches are intended to support persistence (particularly
object/relational mapping) and run-time metadata about the object.
I've found that C# attributes work well for marking all kinds of
meta information right in the source code. This, combined with
reflection, allows you to build other objects that will persist the
domain, etc.
ChrisSepulveda
It sounds like it would be best to leave the domain
objects as actual objects, but maybe generate an XSD
from them to facilitate other tasks such as tools for
generic reporting. I could easily use reflection to
get data from the objects and their attributes to
generate a good XSD.
I'd like to keep some sort of vendor/platform agnostic
schema (versus just having a database or .NET IL
Types). Code generation sounds like it would hinder
the development and evolution of the core objects in
the domain.
I'd like to avoid the overhead of reflection at
runtime for some features, and definitely don't want
the overhead of parsing the XSD; so I still think I
may incorporate some code generation. I'd look at
using the code generation for functionality that would
require lots of setup and redundant work that can
easily be templated, probably for little subpieces of
the domain, and service layer, and more for the
interface layer.
Thank you for the response,
JordanMatthiesen
>I'd like to keep some sort of vendor/platform agnostic
>schema (versus just having a database or .NET IL
>Types). Code generation sounds like it would hinder
>the development and evolution of the core objects in
>the domain.
If you want to be more platform neutral, why not use Java? (I use C#
a lot and accept that its use is way to the right of being platform
or vendor neutral.)
>I'd like to avoid the overhead of reflection at
>runtime for some features, and definitely don't want
>the overhead of parsing the XSD; so I still think I
>may incorporate some code generation. I'd look at
>using the code generation for functionality that would
>require lots of setup and redundant work that can
>easily be templated, probably for little subpieces of
>the domain, and service layer, and more for the
>interface layer.
Why do you want to avoid reflection? Are you concerned with
performance? I've used reflection extensive and have yet to find it
is the performance bottleneck when actually profiling an application.
I wouldn't avoid reflection for the assumption of performance
considerations as preemtptive optimiztation is dangerous, in my
opinion. If you have profiled such performance problems, that's
different.
Code generation can be appropriate at various times. I would suggest
being really judicious though, as it can become a "fixture" that is
expensive to refactor and thus becomes an impediment for accomodating
the certain changes that always come up.
ChrisSepulveda
> If you want to be more platform neutral, why not use
> Java? (I use C#
> a lot and accept that its use is way to the right of
> being platform
> or vendor neutral.)
>
The use of the .NET framework was a business decision
in our case and in evaluation we found it fit our
goals better (I wasn't too involved in the evaluation
process, so I can't elaborate). When I say platform
I'm mainly referring to development environment (.NET
framework, Java, etc.), however the main concern is
being database platform neutral. Ideally our app.
would work under Oracle as well as Microsoft SQL
Server.
> Why do you want to avoid reflection? Are you
> concerned with
> performance? I've used reflection extensive and have
> yet to find it
> is the performance bottleneck when actually
> profiling an application.
> I wouldn't avoid reflection for the assumption of
> performance
> considerations as preemtptive optimiztation is
> dangerous, in my
> opinion. If you have profiled such performance
> problems, that's
> different.
Honestly, I haven't done any performance profiling on
reflection and suspect that it really is a minimal
hit. It could be slightly more difficult to maintain,
but not necessarily more so than a code generator used
to output the code for compilation. :) I'll keep an
open mind and not elliminate it as an option yet.
> Code generation can be appropriate at various times.
> I would suggest
> being really judicious though, as it can become a
> "fixture" that is
> expensive to refactor and thus becomes an impediment
> for accomodating
> the certain changes that always come up.
>
> Chris
Yes, these are worries I've heard/had as well. I'd
hate to put a lot of work into a tool that ends up
being trashed a short time later because it forced us
to be too rigid and created more work than it actually
saved.
Thanks for the great advice Chris,
JordanMatthiesen
Hi Jordan-
I have some direct experience with the relationship between domain
models and XML Schemas, so maybe I can speak to your idea a bit.
For the past year I used an XML database called Ipedo as the database
for a J2EE application (prototype) with a reasonably complex and
behaviorful domain model. My domain objects are persisted as xml
documents conforming to an XML Schema that I defined in Ipedo.
One major problem I forsee with what you suggest IMHO is the same
problem you always have with auto-generated code - you can't then
modify the generated code if you plan to ever re-generate it (and of
course the XML schema will need to change many times over its life).
Modifying auto-generated anything is often very difficult to manage.
In my case, if I had generated Java objects from an XSD I most
definitely would have needed to modify those objects if I intended to
use them as a "domain model". That's because, as Eric pointed out in
his reply to you, domain objects usually have quite a lot of
behavior. There is no provision in XML Schema for representing
behavior. I think this the most important issue of all, frankly.
Also, I don't think XML documents is a suitable storage format for
all kinds of application data (not that you were necessarily saying
that you would intend for all data to be stored in XML documents).
Furthermore, I have the need to map my domain model into xml instance
documents conforming to potentially many different XML Schemas, so in
some sense my domain model is my canonical "schema" and using XSD for
that isn't an improvement.
Finally, the structure of my domain model is quite different in some
cases from the XML structures into which the domain objects are
persisted. In other words, the mapping between my domain model and
XML Schema/instance documents is potentially complex. I'm sure some
tools can handle this case.
I have to say that I do think that Object/XML mapping is different
and in some respects easier than Object/Relational mapping for a
variety of reasons. To that extent its kind of appealing use XSD as a
database schema for at least some kinds of data.
So, in summary, I have done parts of what you suggest but in practice
I have found that, if you are committed to the use of behaviorful
domain models, generating "domain objects" from an XSD is really not
possible, especially if you ever plan to re-generate them. I don't
see why using .NET would change any of that either.
But your mileage may vary :-).
DaveMuirhead
Can an object that doesn't directly implement responsibilities implied in the
Ubiquitous Language truly be considered a domain object? Responsibility-driven
design would have you encapsulate state and behavior as a rule, and separate
them only as an exception. Separating all meaningful behavior into services
leaves you with mere data objects that cannot truly be considered domain
objects, in my opinion.
RandyStafford
Jordan-
When I said:
"So, in summary, I have done parts of what you suggest but in
practice I have found that, if you are committed to the use of
behaviorful domain models, generating "domain objects" from an XSD is
really not possible, especially if you ever plan to re-generate
them..."
I was implying that I don't think domain objects that have no real
behavior are really domain objects. At best they're java beans or
data buckets or structs or something.
We just don't agree on what a domain object is. That's all.
Best regards,
DaveMuirhead
There's possibly a middle ground where domain objects with rich
relationships and behavior (functional locality) are accessed and
manipulated through a service layer that presents a particular view or
implements particular use cases on that domain model. If these services
have to be invoked in a distributed architecture, than DTOs are required
to span the address spaces effectively. These are the objects that just
carry data, no behavior. Service implementations often choreograph
collaborations simply through exchanged message protocols where the
partners in the collaboration are the only ones that have access to the
domain model. This isn't so much a domain modeling issue as it is a
reality of distributed architectures. Unfortunately the distribution
boundary can change making all those hand-crafted DTOs and the mediators
that attach them to the domain objects very difficult to change.
JimAmsden
>There's possibly a middle ground where domain objects with rich
>relationships and behavior (functional locality) are accessed and
>manipulated through a service layer that presents a particular view
or
>implements particular use cases on that domain model. If these
services
>have to be invoked in a distributed architecture, than DTOs are
required
>to span the address spaces effectively. These are the objects that
just
>carry data, no behavior. Service implementations often choreograph
>collaborations simply through exchanged message protocols where the
>partners in the collaboration are the only ones that have access to
the
>domain model. This isn't so much a domain modeling issue as it is a
>reality of distributed architectures. Unfortunately the
distribution
>boundary can change making all those hand-crafted DTOs and the
mediators
>that attach them to the domain objects very difficult to change.
I've used service layers and domain layers and have used the
following guidelines for separating code into each.
A Domain layer should only contain data and behavior that is inherent
to the domain (business logic) rather than technology or specific
implementation (incidental logic). For example, the rules for
calculating shipping charges would exist at the domain layer, the
rendering of the invoice to a printable version would not.
The service layer maps to user features (use cases is one metaphor),
or more specifically user tasks. There should be a discrete goal,
accomplished by a deterministic series of steps that will accomplish
the goal. The task will be implemented by coordinating the
collaboration of a series of domain objects and possibly other
objects external to the domain (other API's, libraries.)
Things get interesting when the domain objects require "help" from
objects that are not really part of the domain. For example, the
calculation of shipping charges may depend on a specific vendor's
rate tables. I wouldn't want to "bake" this
information into the domain layer, but it will require some external
dependency for the domain layer, increasing coupling.
As a side note, Service layers are nice entry points for automated
acceptance tests.
ChrisSepulveda
Admittedly I'm very new to domain driven design and
still learning lots. In thinking of entity and value
objects I think of mere data containers, objects used
to represent entities such as contacts and the data
related to them. The entity objects would consist
primarily of attributes (properties) and wouldn't have
business logic in them. Other objects in the domain
layer would utilize the entities and
ValueObjects and
pass them to other layers. Persistence, business
logic, etc. would be handled by other objects.
What other responsibilities would entities implement?
Would it be appropriate to have more complex
behavioral logic in them? I think I'd better brush up
on the introductory chapters of the DDD book, as I'm
sure I misunderstood a few parts. Thanks,
JordanMatthiesen
I think the video store rental example from Martin
Fowlers "Refactoring" book is a reasonable, simple example of a
domain model. In the example, a rental knows how to calculate its own
charges. This and other elements of the rental system provide an
example of a mix of data and behavior in the objects.
Also, I mention the video store rental system because it is a good
example of a point I made in an earlier post. If you start with the
implementation that Fowler originally has, consider how you might
write a code generator to support persistence, for example. Now, with
each step in the refactoring (in the book), there would probably have
to be a parallel refactoring made in the code generator / persistence
framework. In my experience, it would be expensive to maintain both
the domain model and the persistence framework and I probably
wouldn't (haven't) done a good job with either.
ChrisSepulveda
RepresentingTheDomainInXSD is mentioned on: ThreadView