This is about work, so the usual disclaimers about opinions being my own, etc. apply here.

I have an interesting problem in front of me at the moment: I’ve need to come up with a way to be notified when a user connects to, or disconnects from, a PostgreSQL database. This is not something that’s supported by PostgreSQL out of the box1, so my options are limited to building something that sits outside the database. I can think of two ways that I can do this: have something that sits in front of the database which acts as a proxy, or have something that sits behind the database and generates the notifications by parsing the server log.

A database proxy is probably the better option in the long run. Not only will it allow us to know exactly when a user connects or disconnects — since they will be connecting to the proxy itself — it could potentially allow us to do a few other things that have been discussed, such as IP address whitelisting. It might be a fair bit of work to do, and would require us to know the PostgreSQL wire protocol, but given how widespread PostgreSQL is, I’m suspecting that this could be done once and not need many changes going forward.

Despite these advantages, I find myself considering the log parsing approach as the recommended solution. It’s probably a more fragile solution — unlike the wire protocol, there’s nothing stopping the PostgresSQL devs from changing a log message whenever they like — and it would not allow us to do all the other stuff that we’d like it to do. But it will be faster to build, and would involve less “hard programming” than the alternative. It can be knocked out quite quickly with a couple of regular expressions.

Weighing the two options, I find myself wondering why I’m preferring the latter. Why go for the quick and easy solution when the alternative, despite requiring more work, would give us the greatest level of flexibility? It’s not like we couldn’t do it: I’m pretty confident anyone on the team would be able to put this proxy service together. It’s not even like my employer is requiring one particular solution over another (they haven’t yet received any of the suggestions I’m planning to propose, so they haven’t given a preference one way or the other). So what’s giving me pause from recommending it?

No decision is completely made in a vacuum, and this is especially true in the mind of the decider. There are forces that sit outside the immediate problem that weigh on the decision itself: personal experience mixed with the prevailing zeitgeist of the industry expressed as opinions of “best practice”. Getting something that works out quickly vs. taking the time to build something more correct; a sense that taking on something this large would also result in a fair amount of support and maintenance (at the very least, we would need to be aware of changes in the wire protocol); and just a sense that going for the proxy option would mean we’re building something this is “not part of our core business”.

Ah, yes, the old “core business” argument. I get the sense that a lot of people treat this one as a binary decision: either it’s something that we as a business does, or it’s not. But I wonder if it’s more of a continuum. After all, if we need to block users based on their IP address, is it not in our interest that we have something that does this? At what point does the lost opportunity of not having this outweigh the cost of taking on the development work now to build it? If we build the easy thing now, and later on we find ourselves needing the thing we don’t have, would we regret it?

This is a bit of a rambling post, but I guess I’m a little conflicted about the prevailing approach within the tech industry of building less. It’s even said that part of the job is not only know what to build, but when NOT to build. I imagine no-one wants to go to the bad old days where everyone and their dog was building their own proprietary database from scratch. I definitely don’t want that either, but I sometimes wonder whether we’ve overcorrected in the other direction somewhat.

  1. I didn’t look at whether this is doable with hooks or extensions. ↩︎