Clojurize the Data, Not the Database
anvil.io
anvil.io
Databases are different — accept it. I use PostgreSQL and Redis — there is really little they have in common and I use them for completely different purposes. I can't see how you could stuff all that into a single abstraction. I mean, in my Clojure code I use SQL transactions in one part of the program and Redis' optimistic locking (WATCH/MULTI/EXEC) in the other. They are _different_ and they are supposed to be different.
I also believe that the whole story about how difficult it is to "switch databases" is a red herring. If your code isn't a pile of spaghetti, then your database access functions are grouped together, not spread all over the place. This usually means that instead of abstracting the database with a generic database API, you abstract the database with your API, which only performs the operations you need.
If you do that, then a) switching databases isn't that difficult, b) your "database DSL" becomes your DSL, not somebody else's.
As a practical example, my code has a namespace called "distributed" which abstracts distributed synchronization using Redis. I can call (distributed/register-server), or (distributed/dequeue-job). The functions are very short, and really consist of redis-clojure calls with minimal database logic. Now that is a DSL I like.
ActiveRecord seems like a local maximum, and I'd be very curious to see what comes up in the next decade.
Let me tell you, I'm sick of writing ORMs, I'm sick of using buggy, abstraction-leaking ORMs. I'm sick of the need for ORMs. Relational DBs should provide ORM as a native, first-class abstraction. The fact that every programming language has ORMs, and that people are starting to adopt Mongo over say, postgres purely because it doesn't need ORM and has a nicer query interface is telling.
Relational DBs need to get with the times.
EDIT: It seems like a simple idea, but I'm wondering if the execution has failed or if it was adoption or if this is truly an original idea.
The problem is that all those inconsequential differences between data stores are really important. The article explicitly says "Scalability and performance are outside the scope of this", but in real-world software, scalability and performance matter a lot. When we'd tried out Hibernate for a past employer, performance dropped by 80% - data operations were now taking 5x as long to complete. You can recover much of that by tuning your mappings, but by then, you're pretty much writing SQL anyway, and your app wouldn't work with any database other than the one you tuned for.
Also, nearly every app needs its own data abstraction layer, one that works with the particular operations and domain objects of the app rather than tuples and records and tables. At this point, there's little reason to go through another abstraction layer, adding complexity and slowness to your program, when your calls to the data store are already localized to one module.
It turns out we have general-purpose libraries for dealing with data already. We call them "programming languages". If there is some way to simplify the problem in the general case in such a way that data manipulation no longer requires a full programming language, nobody's really proved it. If your do create an "ORM" or some other mapper that is somehow simpler than using a full conventional language, than ipso facto your mapper or whatever is too simple to handle the full complexity of the problem.
I'm not 100% convinced this nut is completely impossible to crack, but I am sure it would take accommodations on both the data and the programming side (much of the pain of this process is self-inflicted with bad paradigms and bad programming, but probably not 100%), and it sure as heck isn't as easy as it looks when you just look at it. One of the ideas in my head is to take a crack at this problem myself, but I've been telling that one to shut the hell up and go back to hiding in the corner.
ODBC, for one, would seem to have had the same aims:
https://secure.wikimedia.org/wikipedia/en/wiki/Open_Database...
I think this is very arguable. For the cases where you want to do some query optimization, thats what the Clojurize protocol's prompt function is intended for.
(prompt
[adapter expression]
"Execute a native database expression")I think there's definitely a place for libraries that add things like validation to models. But the more functionality you include, the more specific your library needs to be.
[edit] OT to this thread: didn't clojure-dbm have some similar ideas to Clojurize? I remember forking it from your github repository early last year some time and doing some cool stuff with it.