Never use the database driver directly

The two most used stacks today are probably MEAN and LAMP.

In both cases these are dynamic languages (love them or not, that’s another post) with or without a web framework, connected to a DB. In  the first and more current stack, the DB is mongo – a document based DB, the second and more senior one, is powered by mysql, a great, small, open source SQL DB. Be it one or the other, it seems that more often than not, we see code like this:

const MongoClient = require('mongodb').MongoClient; MongoClient.connect("mongodb://localhost:30000,localhost:30001/integration_test_?w=0&readPreference=secondary", function(err, db) {   test.equal(null, err);   test.ok(db != null);   db.collection("replicaset_mongo_client_collection").update({a:1}, {b:1}, {upsert:true}, function(err, result) {     test.equal(null, err);     test.equal(1, result);     db.close();     test.done();   }); });

or

$conn = new mysqli($servername, $username, $password);
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

Sometimes, things get even worse with the usage of third party drivers that sits on top of the core driver. Now, not only you depend on the underlying driver, you’re now depending on the third party which depends on it. These third party drivers, or add-ons, can stopped being developed and thus limit you even further.

So here we go, all the reasons to use your own, or an open abstraction layer:

Your database (and or its driver) will be updated or discontinued

This is a fact. your database will either be upgraded or discontinued. The drivers for the next version may or may not work with the current version and vice versa, but not for all future updates. Once that happens, you can’t upgrade, unless the the new drivers happen to match exactly to the older version (what are the chances?). If the current database have security and or performance issues, you have to update your entire code base and to perform a full load test with the new drivers. While you might still want to keep your old versions of, well, everything, this might not always be an option. Add to this that some versions will seize to work on certain operating systems or software versions (node version, python, PHP, C++ compiler, Java libraries and so on). Now you’re locked to a certain OS and\or certain software version. no updates, no new libraries that works with the capabilities of the new versions. no security updates unless, again, you’ll update you entire code base. if you’re running a micro services ecosystem, you’ll have to update them all as they’re all probably using the same driver to get to the same database.

Testing is now way harder

If you’re committed to a driver and a database, you must have this database (and driver) for every project you’re developing. Testing? You’ll need not only to install the database in a specific version (yes, docker) but also that driver, and the whole data-set. That’s making testing hard and hard to check into CVS. not impossible – true, but very uncomfortable.

Can’t change databases

Along the way you (or someone else on the team) might decide that the database you’ve been using is too slow, too hard on resources, too hard to index or any other issue. Since you’re tied to a driver and a database version, you can’t move without, this time, not only updating the drivers, but now you must update your entire logic. The whole CRUD operation. Change Databases on a running project? forget about that.

Cross updating

The drivers we have today usually connect to a single endpoint, the better ones? They Connect to a cluster. But two clusters? Not really. If you want to move a production load from MongoDB stored on AWS to CosmosDB stored on an Azure cluster, there is no way to do so without bringing down your production environment. If you have real customers, this is not very likely to happen. Consequences? You’re now locked into a Database vendor.

Can’t understand database schema

Well of course you can! You wrote it! Now. What about later? what about your team? what does user_engine_id means? is that another id? is that the user’s browser id? rendering agent? billing? No clue. in 3 months, I’m not sure that even the writer will know. Sure, you can litter the code with comments, which is another evil, or just do the right thing.

The solution

Always – Always use an abstraction layer between your code the the database.

  1. If the database version update – you only need to update your library. Your code will benefit from the underlying upgrade and you only have to check one piece of isolated code – the abstraction library.
  2. Testing is now a breeze – the only thing you need is a test version of this library. No need for a driver, nothing to install and any test data set can be now easily checked into CVS.
  3. Change a database? Easily done. Assuming the abstraction layer was done correctly. You can now switch from SQL to NOSQL, or different engines
  4. Cross update? A well written layer can balance the load of two or more endpoints. This is not trivial, and most likely will needed to be done in house, but, the benefits are obvious.
  5. No need to understand the schema! full documentation is now available – as code.

If you can  – use an existing solution. it’s obvious. BUT – make sure that this abstraction covers everything you need. If it’s just a simple abstraction that can’t be ported to other databases – you’re not doing yourself any favors. If needed – write it yourself.

Leave a Reply

You must be logged in to post a comment.