Wed Jan 14, 2004 8:55 am
I remember reading something Kent wrote, where he recommends that
people wait as long as possible to introduce a RDB into a project,
even if you know for sure you'll need one. The rationale being that
you can move a lot faster not having to worry about schema changes and
data migration. And once you do introduce the RDB, your schema will be
more mature, and you'll be less likely to have to deal with huge
schema refactorings.
"Designing Objects for Relational Databases" in Chapter 6 might
challenge this somewhat. After all, having to deal with the mapping
layer every day is sure to bring into focus the issues Eric mentions -
without that, the trade-offs a RDB forces on your model would be
abstract until the day you actually plug in the RDB.
Opinions? Also, is there anyone here who's tried late introduction of
a RDB, and if so, how did that work out for you?
SteveConover
Not having to deal with a relational database until later would be nice but
I am not sure how practical that is.
Object/relational mapping and other database-related issues are pretty
critical and you should address them sooner rather than later in a project.
Also, some organizations a very database-centric. For example, one client I
worked with insisted on designing the database schema up front.
Having said that it is nice if the domain model is decoupled from the
database schema so that you can do a lot of development and testing without
the database. The in-memory tests run a lot faster. And you do not not have
keep the database schema up to date at all times.
For example, you can write a new method and add a new field to a class and
test it before having to add a column to the appropriate table.
I wrote a couple of articles on this topic. One article covers developing a
domain model with EJB CMP:
http://www.theserverside.com/articles/article.jsp?l=TwoLevelDomainModel
The other covers JDO:
http://www.theserverside.com/articles/article.jsp?l=JDODomainModel
ChrisRichardson
I introduced an RDB in week 7 of a 10-week project. It was arduous and
it could have been worse. I had already designed data access through
repository-like interfaces I call "stores". I had a single store for my
lone aggregate root class.
The only difficult part -- the thing that cost me two days -- was
managing JDBC connections and transactions. Swapping implementations of
the Store interface was actually quite straightforward, if tedious.
JBRainsberger
JBRainsberger wrote this experience up as a brief story here:
http://domaindrivendesign.org/articles/archive/rainsberger_jb_2003_10.html
EricEvans
Actually, that's a different experience, but with similar results.
JBRainsberger
Ah. I stand corrected. But this new one sounds quite interesting. Could you
say a little more about it?
EricEvans
Start here:
http://groups.yahoo.com/group/extremeprogramming/message/87475
JBRainsberger
Thanks guys, this is the kind of thing I was looking for.
It sounds like opinions are divided over this, which is what I had
guessed. The best option would be to somehow anticipate the O/R
issues you will run into to begin with, while still waiting to
introduce a database until "later". That obviously violates DTSTTCPW,
and I question whether it can be done effectively anyway.
SteveConover
Here's one specific issue I had.
I implemented queries using the Specification/Predicate design, so I had
a method on my ObjectStore called select() taking a Selector as a
parameter. A Selector is essentially a Predicate as defined in the
Jakarta Commons Collections project. (In fact, it delegates to a
Predicate under the covers, but that's not important.)
I did this to keep the query interface flexible. I had essentially five
different ways to query the aggregate root of my object model, and this
design allowed me to implement the five corresponding transaction
scripts by extracting everything except the creation of the Selector
into a superclass. Very nice.
Now it comes time to switch to JDBC. The Selectors operate on
reconstituted objects, rather than defining a specification for the
query, so I considered moving the Selector factory behavior into the
ObjectStore itself. This would mean that clients would specify the
Selector by some label, then the ObjectStore would be responsible for
instantiating the appropriate Selector. I didn't like that solution,
because it required work.
Instead, I got some expected load numbers from my client. 800 records,
you say? Let's try it... I selected all 800 records from the database
using a SelectAll Selector (it checks each record and answers "yes" to
the question "Put it in the container?"), and it ran in 300 ms. The
resulting user interaction was not noticeably slower, so the client
accepted the feature as is.
My worry is that, down the line (if we ever add more features to this
project, and we might), as the aggregate root gathers more dependent
objects (each an entity in its own right), the obvious performance
penalty for this design will begin to cause real problems, and we'll
have to deal with it then, anyway. The good news is that anything could
happen between now and then, including the whole project could be wiped
out. In that case, I'll be glad I didn't worry about it.
Summary: I'm glad I didn't bother anticipating the O/R issues, for
otherwise I'd have built stuff I didn't need.
JBRainsberger
I take the opposite point of view. If you expect to be in the position of
migrating production data someday, as new releases are released, it behooves you
to get some repetitions with it, get good at it, and refactor/improve your
approach to it every chance you get. Same goes for O/R mapping - it's a
complex, time-consuming, difficult problem that is risky to try to shoehorn in
at the last moment.
RandyStafford
EarlyVsLateIntroductionOfRDB is mentioned on: ThreadView