Dejavu has some overarching design choices baked in that may not be obvious; they guide lots of little decisions rather than being one big feature or module. Here are the ones I'm actually self-aware of:
Paying the Price
Any ORM that works with multiple databases (and other storage types) makes many, many decisions about "extended functionality". API choices must be made about features that one database offers that, say, a CSV file doesn't. A common answer to this complexity is to simply offer the Lowest Common Denominator of functionality; that is, don't offer any feature unless all backends offer native support for it. Instead, the approach I've consistently taken in Dejavu is to let the Model layer (not the Storage layer) guide the feature set, and design the API without regard to database support. Each feature is implemented as well as possible for all backends. In some extreme cases, some features may not be fully available for all backends. That's OK.
This means that you can write your application without thinking about storage-layer performance tweaks. Not that you can forget about performance entirely! There are well-known, generic "rules to follow" when designing any model. But my dream is that you, the application developer, will never again say to yourself, "I will write this application using Postgres; I know it's faster because of feature X". Most often, in my experience, you would be wrong, and those who deploy your application will pay the price for your choice. What Dejavu encourages is that the deployer is free to choose the backend that best suits *their* live data, on *their* machines. In this way, they pay the price of their own choice, not yours.
This means a couple of things for Dejavu's design. First, it means a strict separation between the Model layer API and the Storage layer API. If a feature makes you worry about which backend you should use, it does not belong in the Model layer API. Dejavu, therefore, will never store the "real table names" (storage layer) as attributes of Units (model layer). Field sizes (storage layer) are not defined by Unit Properties (model layer); at best, the Unit may provide "hints" about such things to the storage layer.
Second, it must be easy for deployers to switch backends, and analyze the resultant performance issues, so they can test which combination is best with their data. Part of my motivation for writing Dejavu was to see which chunks of my own dataset could work better as a "burned set" (loaded once and kept in RAM for the life of the process) and which worked best in a normal RDBMS (mostly on disk). The ability to use and even chain multiple backends within the same app is a strong determinant of Dejavu's design.
My hope is that this frees developers and deployers in new, important ways. It shifts the expectation of responsibility; when you give deployers the choice of backends, they will either 1) thank you for the opportunity to tweak their own install, or 2) pay you to tweak it for them. Performance issues are then not a bug, but an opportunity (for either party or both). In the rare cases where it is a bug, the fix probably rightly belongs in Dejavu itself, and all deployers of all apps built with Dejavu can benefit.
