blog.absurd:li - press play on tape
October 7th 2009
Tagged ruby, rails, models, soa, services, REST, bdd, tdd, thrift, XML RPC, SOAP, rpc

On sharing your models and still keep the database a secret

Your rails application is useful to someone. Now he wants to do more, depend on the data it handles and use it in other parts of his business. The simplest thing to do would be to give him access to your database and just let him have the data, right?

As it turns out: not really. While this is a good short term solution, it will certainly bite you in the long run. Not everyone accessing your data does so in a way that preserves your invariants and integrity constraints. And even though I think that ActiveRecord has found a sweet spot in specifying business rules you need to realize that it wont tolerate other gods beside it. Constraints and higher level rules specified in your Ruby code will only be maintained if you access the data through Ruby code.

The solution to this is obvious: Don’t share your database, share your access layer. Every access to the database has to go through your models. And those will be the keeper of invariants, the maintainer of .. you get my drift.

Here’s the short list of options you have to go about this:

Share model code

This is the first idea that you will have and probably not the best. Somehow bad ideas always come up first.

Following this idea, you would share your model code between various projects (using git submodules or the like) and access the database from all projects, going through the model code.

This has a number of downsides:

  • Your model code will change over time. That generates deployment issues: How will you update your projects all at the same time? If you don’t, you are back at square one.
  • Worse: Your database will need to change. But if you do that, all your model code (or the part that is not generated anyway) will possibly become invalid. So doing a migration means updating all your code at the same time. So you stop the world and do the update…
  • Another minor issue, if you are doing BDD/TDD like me: Where do you keep the tests for your model code? In the project that uses the code, because that project depends on the features that the test demands? Or in your model code project, since the code is there?

If I were you, I would not go down that road.

Distribute the data

Enterprise Rails does mention a few ways to distribute your data to the application that needs the data. The idea is to create a books database (and a books model) that is then used by the ‘book processing system’ locally. Why share when you can own it?

Because sharing is really what makes applications interesting to whomever uses it. And sharing things in a good way really is what application architecture is about.

So data distribution doesn’t work, since there will always be some overlap in data access.

Provide model access as a service

The remaining solution then is: Provide access to your model layer through small services that you publish. Access the model through them and only that way.

When the model changes, the service can stay the same. This solves the deployment issues I’ve shown with the first solution. And because it decouples the consumer of the service from the data, essentially where the data is located doesn’t matter anymore.

Your service will provide an interface for data access. This will hide complexity, allow you to provide abstraction. Its just a good idea™.

And to end on a practical note

I am getting a lot of mileage out of thrift these days. Being able to create service points and not limit myself to one particular language at the same time just has this innate beauty to the language geek in me.

Thrift lets you create services that look like instances of objects on both sides. It will handle marshalling and unmarshalling for you. The internal architecture of thrift really convinces me. It is hackable / more on that later on.

I am really not convinced of REST/SOAP/XML RPC. I don’t want to clutter my controllers with XML generating code. And even though I am using REST style controllers these days (as a way of structuring my application), I don’t want those be an API at the same time. I am really afraid of ending up with the ‘Big Generic Interface To Everything™’ and not being able to change it anymore when I need to. It ties things together that want to be free!

Thrift is small and neat. I can create a service within the space of an hour but still am able to do so explicitly.