Hacker News new | ask | show | jobs
by jiggawatts 638 days ago
Yeah, this article is the poster-child for "engineering for an unlikely future at the expense of the certain present".

> If you ever change your HTTP serve

Yeah, that ain't happening. You also won't replace your database engine or queue either. If you do for some reason, it'll be a partial rewrite of you app no matter what. You can't abstract over these things in a useful way, the common denominator isn't rich enough for useful applications.

> You'd have the same problem if this code lived in a setup module

Moving code from file A to file B does nothing to it. This is the fallacy of assuming that the name of the thing changes the thing, and is in the same vein as having a "secure" network where it's secure because it is called that in a spreadsheet of subnets.

> our HTTP handler is orchestrating database transactions

Transactions are deeply linked to requests. If you try to abstract this away, you won't be able to read your code any more because you won't be able to see the control flow in... the controller.

> You cannot call this handler without a real, concrete instance of an sqlx Sqlite connection pool.

Faking a database is a fool's errand. It's a lot of work at best, and a subtle source of false negatives or positives in your tests at worst. Database engines have very complex behaviours such as concurrency, transactions, locking modes, type conversions, collation, and so on. Why try to emulate this!? Just use a local database file for testing!

A bigger concern with the repository pattern is that without eternal vigilance, it'll block the use of high-performance code.

For example, with the Author repository, retrieving authors is all-or-nothing. The blog author used sleight of hand to hide this by having a single "name" field along with a primary key. Okay, what if there are 287 fields, and a bunch of foreign keys? Now what? Do we read in the 1 name field along with 286 unrelated fields just to throw all that work away? That's 0.35% useful work performed per call!

Similarly, he returns single authors, one at a time. How do you returns collections in response to queries? As Iter? A Vec<Author>? What if it's an async streaming response!? If you try this, you'll quickly discover that there is no general portable pattern across different DB providers and every approach has some downside. That downside can be "OOM panic" or similar.

I've been doing a lot of work recently to clean up legacy ASP.NET apps and my #1 trick to directly invoke Entity Framework directly in the controllers (HTTP handlers). I select just the required columns, run the queries as async, and where possible/useful I stream back the results instead of trying to hold them in memory at once.

I've seen 5-10x speed ups compared to SOLID pattern code with everything broken out across dozens of interfaces, abstractions, and layers scattered across a bunch of projects. All this with a 30x (no joke) reduction in lines of code, dramatically faster builds, faster deployments, and readable code that can actually be maintained by one person. I reduced one project that had several thousand lines of code to one page, the same kind of thing as the "bad" everything-in-main example in this blog post.

Was I bad and wrong?