Skip to content
Bytes by Ying
Go back

Postgres...as an App?

Edit page

Overview

I’m still working on TinyDevCRM, and I’m getting really close to release. No, really, I mean it this time. I even released some API documentation that should match up with the final spec pretty closely.

Along the way, I’ve learned a good deal since I first started working on this project a few months ago. Much of this stuff I’ve distilled in a “Things I’ve learned this week” section of the weekly progress updates I’ve regularly published here. I’ll probably share a bit more about those lessons after shipping the MVP.

The biggest thing I’ve learned is just how much mileage you can get out of your everyday, “boring” tech stack. I’m not a terribly big fan of resume-driven development, because I think it gets in the way of self-reliance / independence, investing in things that don’t change, and focusing on my BATNA. I like tiny build sizes, tiny dependency trees, and tiny bugs, so that tech can get out of the way of solving problems.

Problem

No matter how you slice and dice it, all meaningful apps do need a database. If you don’t own a database, your data’s probably managed by somebody else. In a world where data is the new oil, that ruffles my feathers. I’m a software engineer, with data engineering experience. There’s no reason I can’t own my data.

Picking a database is important, even if they are, in the end, just fancy file managers. That’s how the biggest focus of my project ended up being Postgres. For me, Postgres offers the best combination of out-of-the-box features, extensibility, and reliability. If I have to incorporate a dependency, I’ll stretch it until it can’t reasonably stretch any more, and I’m lucky Postgres can stretch rather far.

In a jiffy, Postgres isn’t just a SQL-based, ACID-compliant OLTP database. It’s also a NoSQL JSON-backed document store, a time-series database, and a graph database, among other illusions. It might not do the job as well as the leading industry benchmark, for sure. But I wouldn’t be surprised if it was a #2 or #3 option in whatever shindig you wanted to piece together. It’s the Python of databases, a Swiss Army knife you can use to easily prove out a proof-of-concept or use at a small scale before having to hire another developer or consider using another stack.

So color me disappointed when I realized AWS RDS doesn’t allow you to do all that much with its Postgres deployment. To RDS, it’s more important things like data integrity or high availability work properly. That means no touching server internals, no root access to the server, and no installing custom extensions.

It’s disappointing because I really wanted to combine the safety of a managed solution like RDS with the extensibility granted by root access to the database and its internals. It’s not necessarily because I like hacking together my own solution. On the contrary, I think such a solution could offer the best global tradeoff for optionality between clouds, costs management, and maintainability, among other considerations.

Solution

As it turns out, it’s quite possible to have a hybrid RDS / bespoke solution. Postgres supports this nifty concept called “foreign data wrappers” (FDWs) where you can read/write to external data sources. This is actually part of the SQL standard, called SQL/MED, and implemented by other databases as well.

Depending on your risk tolerance, there’s different FDW extensions you can use. CSV files and Postgres are supported out of the box. MySQL and MongoDB wrappers are supported by EnterpriseDB, who I believe retain a number of core Postgres developers. Oracle and JDBC wrappers are developed by third-party individual contributors, and might not be as well maintained. Finally, if you want something made in-house, you can always roll your own FDW using Multicorn, and rewrite it using native C for performance if the concept sticks.

RDS supports postgres_fdw for Postgres for RDS. This means you can create references to Postgres tables in RDS from your bespoke Postgres database deployment.

There’s also this nifty project called PostgREST, which “lifts” existing Postgres resources into an HTTP context automatically. This means you don’t need to log in using a console to access your data. You can view it in the browser, and remotely connect to it using whatever clients fit your fancy. It’s also nice for other reasons. PostgREST cuts out the ORM middleman, unifies security at the data layer instead of fragmenting it between the app and the database, and runs stored procedures against the database by turning HTTP + PL/pgSQL into a sort-of RPC language.

Now, the full system design swims into view:

digraph {
    "aws" [
        label = "Postgres on AWS RDS"
        shape = "record"
    ];

    "postgres" [
        label = "Custom Postgres"
        shape = "record"
    ]

    "http" [
        label = "PostgREST"
        shape = "record"
    ]

    data -> aws [
        label = "  sql"
    ]
    aws -> postgres [
        label = "  postgres_fdw bridge"
    ]
    postgres -> http
    http -> "end user" [
        label = "  http"
    ]
}

This is Postgres as an app. All the complex logic you’d normally have to get a developer to write, or spend time writing yourself, is abstracted into the actual database, without abstracting away user freedom. It’s a 1:1 mapping of the data model from the SQL layer to the HTTP layer. This means you can use any number of cheap clients to connect to and interact with your data.

Tradeoffs

As with any system design, there’s benefits and downsides:

Pros

Cons

I’m working on a multi-stage CloudFormation deploy of this stack, so you (we) can try it for ourselves to see how it works and compares. Should be up in the next couple of days. Stay tuned.


If shipping software along this direction is something you’re interested in bringing to your organization, I’m looking for remote freelance / contract work and I’d love to have a conversation. Email is me@yingw787.com.


Edit page
Share this post on:

Previous Post
#lifeprotip: Haskell-inspired "lifting into structure" for individual shell commands within a Docker context
Next Post
The Services that makes the Cloud Worth It