This post is about the ruby library we are building - Datamappify, please go check it out.
At Locomote we are building a relatively large web application using Rails. Before we began to lay the foundation, we knew very well that if we wanted the project to be maintainable we had to architect the system with extra care and attention. More specifically, we can't rely on simply using ActiveRecord which combines behaviour and persistence as our domain models.
We began our search for something that would help us decouple our application from the domain layer down to the form handling. We've found a couple of gems that are close to what we were after - Curator, Minimapper, Edr and later on Reform. They are all wonderful gems but unfortunately none of them has everything we need.
Here are the things we need:
- Decouple domain logic and data persistence.
- Decouple models and forms.
- Support ActiveRecord (or at the very least, ActiveModel) so we can still use many of the awesome gems like Devise, SimpleForm and CarrierWave.
- Support attributes mapped from different data sources (e.g. remote web services from third-party vendors).
- Support lazy loading so that attributes stored on remote data sources will not get triggered upon loading the entities.
All things considered, we bit the bullet and started working on Datamappify.
Before I go into details and examples, here is an extremely simplified overview of Datamappify's architecture:
As you can see, Datamappify is loosely based on Repository pattern and Entity Aggregation pattern.
Datamappify has three main design goals:
- To utilise the powerfulness of existing ORMs so that using Datamappify doesn't interrupt too much of your current workflow. For example, Devise would still work if you use it with a UserAccount ActiveRecord model that is attached to a User entity managed by Datamappify.
- To have a flexible entity model that works great with dealing with form data. For example, SimpleForm would still work with nested attributes from different ORM models if you map entity attributes smartly in your repositories managed by Datamappify.
- To have a set of data providers to encapsulate the handling of how the data is persisted. This is especially useful for dealing with external data sources such as a web service. For example, by calling UserRepository.save(user), certain attributes of the user entity are now persisted on a remote web service. Better yet, dirty tracking and lazy loading are supported out of the box!
接下去有不少代码,请翻墙后上我 blog 继续阅读。:D