Thank you Richard for your long reply!
No problem.
The "service" approach is used to abstract the database totally from
the rest of the application.
Essentially below the waterline, everything is custom, you get an
implementation-specific PersistenceService, which returns only
implementation-neutral types (models).
The database ORM is effectively wrapped by whatever you are using.
The benefit of doing that is that the datamodel can change in a
drastic way, but the rest of the app is unaffected since a service is
used to access the information.
Well the implementation of everything below service layer is not
trivial.
The problem is that in fact the datamodel can change (eg another data
source provider, forced by the government, so no discussion is
possible about the database schema). By changing the datamodel, the
objectmodel however should not change. What does change is the
translation between the data- and objectmodel.
I understand. This is a strategy to re-use all code above the service-layer,
and make it pretty much 100% implementation neutral. But this becomes
only implementation neutral from a *type* or *interface* perspective. If the
schema is very different from the original reference (i.e. totally different
table relationships) several problems creep in:
- first you will lose a lot of performance without leaning heavily on Hibernate
style performance features (like in memory object caching).
- you are also probably limiting your ability to perform unusual queries
against the DB, as the implementation of the service layer has to
translate the relationships, which means that query implementations will
be limited
- you are doing a lot of CPU-intensive model translation in the context
of your application
However, in Rails, when changing the datamodel the objectmodel is
changed automatically (which is in most cases a good thing).
Well that would be a *feature* of rails. Though Rails does have features
for working with legacy databases, like defining getters in models and
mapping them to differently named table fields. Though if relationships
change there is not a lot you can do there.
But if the model changes (eg other combination of attributes to
achieve the same functionality) the controller will likely have to
change...
So that's what my question is about. Is there any way in Rails to
define an 'interface' to a model, so I can use this interface in the
controllers. When the model changes because the data model changes,
the controllers should not be affected.
Well you kind of can. This is close to the Java model you describe, but
there is no service, or distinction between service models, and controller
-used models.
1. You can just define arbitrary models with no relationships
2. map the models to the implementation specific table schema, using
a simple vendor specific configuration code and/or file
3. Do Model.find(:foo) at the controller level and tease the relationships
and data conversion together using model helpers (that use vendor
specific libraries or mixins)
4. The models will present a consistent interface to controllers and views
5. It will also perform like an absolute dog, Rails isn't meant for this
kind of in-code model mapping, and you are likely to be pulling back
bigger result sets than necessary
Depending on the size of the source database, you could simply
create a second database (possibly even in memory) and translate
the implementation specific database into the reference database.
Not a perfect solution, keeping the reference database (that the
models look at) up to date is a problem.
There is also the "I hate the people I work with, and in 2 weeks time
I am going travelling the world" approach:
- do implementation specific metaprogramming
- use metaprogramming techniques to dynamically alter your models
& relationships to match the implementation database
- quake in fear at the insanely ambitious use of metaprogramming,
but keep your fingers crossed, as *it just might work*
There is also the other Rails approach:
1 - writing controllers & views is simple, just make a bespoke implementation
for each schema model, and keep the tests intact
2 - refactor controllers and views to use the new models
3 - bill accordingly
regards,
Richard.