* Don't store UUIDs as strings.
* Don't use random UUID variants for your primary key (or don't use UUIDs for your primary key).
* Don't use a random column in your clustered index.
3,093 karma · joined October 10, 2016
---
C++ can remain irrational longer than you can remain sane.
---
There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.
- C. A. R. Hoare (RIP)
* Don't store UUIDs as strings.
* Don't use random UUID variants for your primary key (or don't use UUIDs for your primary key).
* Don't use a random column in your clustered index.
Today I finished picking tomatoes from my tomato plants and pulled them up to avoid them rotting in the field as the temperature goes down. It was curious to see how the root systems varied both between the two tomato varieties I had planted, the location of the plant in relation to surrounding grass, and the type of soil they ended up in.
If people started using the term "data serialization" to mean taking parallel data and making it serial (for an English speaker, a perfectly reasonable meaning) would you say that this is what data serialization also was?
The term object-relational mapping refers to the very specific concept of taking relational databases and letting you access them as if they were a database of objects. Specifically, in which you had objects which held one-to-one or one-to-many or many-to-one references to other objects etc. This is a graph. The object-relational mismatch deals with the fact that relational databases and graphs are fundamentally different such that there isn't a well defined way to represent all kinds of one as the other and vice versa. Moreover, there is a performance penalty to attempting to pretend that your relational database is a graph database, and querying the relational data in ways which would make sense for a graph database.
In the case of SQLAlchemy ORM (not Core) when I worked with it back in 2018 now you could select all users from a table, or all orders. But if you wanted to select the most recent order for each user, it's much harder and requires breaking more abstractions than if you were to do it using a query generator. This is because SQLAlchemy ORM expected you to represent your data as a graph:
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String, nullable=False)
orders: Mapped[list["Order"]] = relationship(back_populates="user")
If you _just_ use the ORM you would write something like: users = session.query(User).all()
most_recent_orders = []
for user in users:
if user.orders:
most_recent = max(user.orders, key=lambda o: o.created_at)
most_recent_orders.append((user, most_recent))
This is the n+1 query problem, and the performance would tank.To avoid this, you have a few options, the simplest seems to be to add a virtual fiend to your User object which holds the most recent order:
User.most_recent_order = relationship(
Order,
primaryjoin=Order.user_id == User.id,
order_by=Order.created_at.desc(),
uselist=False,
viewonly=True
)
session.query(User).options(selectinload(User.most_recent_order)).all()
But this still isn't performant, as there's going to be a double-select, one for the users, and one for the orders (filtered by the users).If you want to do this performantly, with one final query, you end up needing an alias:
RankedOrder = aliased(Order,
select(
Order.id, ...,
func.row_number()
.over(partition_by=Order.user_id, order_by=desc(Order.created_at))
.label("rnk")
).subquery()
)
session.execute(
select(User, RankedOrder)
.join(RankedOrder, RankedOrder.user_id == User.id)
.where(RankedOrder.rnk == 1)
)
All this and you don't get users with their corresponding order contained within, you get an abstraction leaking sequence of tuples and their corresponding orders.This is just one single mildly non-trivial example. All this extra boilerplate just to get performance.
Meanwhile if you use just Core:
ranked = select(
orders.c.id, ...,
func.row_number().over(
partition_by=orders.c.user_id,
order_by=desc(orders.c.created_at)
).label("rnk"),
).subquery()
query = (
select(users, ranked)
.join(ranked, ranked.c.user_id == users.c.id)
.where(ranked.c.rnk == 1)
)
Which looks like literally the final "ORM" code.This is what I mean when I say ORMs are either not actually ORMs or their users aren't using the ORM part for the most part.
I didn't say you didn't want a query generator, or to have some way of mapping things automatically to native types so you are not effectively dealing with native database types.
What you don't want, which is what object relational mapping means / was designed to solve, is to force your relational data into being represented as a graph of objects when you operate on that data within your application.
To finalize:
ORMs use query generation, but they are not the originators or the only source of query generators
ORMs often provide additional validation, but they are not the originators or the only source of validation
ORMs by their definition map your SQL data to your native types, but fundamentally they do it in a way which cannot be made performant at scale. You can map things to your native types in a way which is performant but this would definitionally not be an ORM
I'm not saying that you won't experience hardware failures, I am just saying that you also need to remember that if you want your product to keep working over the weekend then you must have someone ready to fix it over the weekend.
A lot of the writing also has this feeling to a lesser extent.
My advice is always to write something first and then (if you insist) get AI to proofread and make editorial suggestions. This seems like it was written by AI from some prompt and notes, and then modified in a few places.
It just adds a bunch of weird fluff.
Although nobody seems to use the term ORM correctly any more so it's entirely possible that neither is peewee or sqlorm.
The story behind why ORM is nowadays no longer used correctly is kind of funny:
1. Query generator sounds primitive, like cavemen banging rocks together. Software engineers are scared of primitive technologies because it makes their CVs look bad.
2. Actual ORMs attempt to present a relational database as if it was a graph or document database. This fundamentally requires a translation which cannot be made performant automatically and often requires very careful work to make performant (which is a massive source of abstraction leaks in real ORMs). People don't realise the performance hit until they've written a chunk of their application and start getting users.
3. Once enough people encountered this problem, they decided to "improve" ORMs by writing new "ORMs" which "avoid" this problem by just not actually doing any of the heavy mapping. i.e. They're the re-invention of a query generator.
Don't force me to either get another AI to remove all the fluff, or to skim read.
There's an interesting article here, covered in a layer of AI slop.
Anecdotes aren't useless, but be very careful of _any_ conclusion you draw from them.
I don't necessarily think there was a problem with the comment they replied to.
English is a language in which words can have more than one meaning depending on the context they are used in.
"I am sick" meaning that I am not feeling well.
In the context of someone watching a performance: "This is sick!" as an exclamation that something they saw was impressive.
In the context of someone watching something gut wrenching: "This is sick!" as an exclamation that something they saw was horrible and unpleasant.
In the context of someone stepping in a puddle of vomit while walking around London: "This is sick!?" as a dismayed exclamation of realisation that what they stepped in was a puddle of vomit.
I can go on, and so can anyone who can speak English.
So, please stop this bullshit of "I want this word to mean this one thing that it has not meant at least the past 30 years."
It's extremely useful that we can agree on what words mean despite the fuzziness of English. You are intentionally trying to muddy the water.
I've not been using much LLM output recently, and generally I ask it to STFU and just give me what I asked as concisely as possible. Apparently this means I've seriously gotten out of practice on spotting this stuff. This must be what it looks like to a lot of average people ... very scary.
Advice for bloggers:
Write too much, write whatever comes out of your fingers until you ran out of things to write. It shouldn't be too hard to just write whatever comes out, if you save your self-criticism for later.
If you're trying to explain something and you run out of things to write before you manage to succeed at your goal. Do a bit more research. Not being able to write too much about a topic is a good indication that you don't understand it well enough to explain it.
Once you have a mess which somehow gets to the point, cut it way down, think critically about any dead meat. Get rid of anything which isn't actually explaining the topic you want.
Then give it to an LLM, not to re-write, but to provide some editorial suggestions, fix the spelling mistakes, the clunky writing. Be very critical of any major suggestions! Be very critical of anything which no longer feels like it was written by _you_.
At this point, edit it again, scrutinise it. Maybe repeat a subset of the process a couple of times.
This is _enough_ you can post it.
If you want to write a book, get a real editor.
Do not get ChatGPT to write your post.
There were 3 instances of cognito. RDS, DynamoDB and S3. The entire architecture diagram would only be legible on an A2 (heck, maybe even A1) page. And that was the high level diagram. The central A4 part of that diagram was a bunch of micro-services for handling different portions of this CRUD application.
This company could afford a system architect as well as a team of developers to work on this full time.
I was genuinely baffled, but this company was in an extremely lucrative industry, so I guess in this case it's fine to just take some of your profits and burn them.
On a "normal" arduino, an FTDI chip on the board handles the job of exposing a serial adapter to your computer over USB. The atmel chip on the other side of the FTDI chip runs your code and getting serial out from your firmware is a short codepath which directly uses the UART peripheral.
On a teensy, there is still a secondary chip, but its just a small microcontroller running PJRC code. This microcontroller talks over the debug pins of the main chip, and those pins aren't broken out (at least back when I last used a teensy). Despite covering the debug pins, this chip only handles flashing and offers no other functionality. Since there is no USB serial adapter, for hobbyists trying to use it for running code with an arduino HAL, the HAL has to ship an entire USB driver just for you to get serial over USB. And this itself means you can't use the USB for other purposes.
For advanced users, this makes debugging much harder, and god forbid you need to debug your USB driver.
It's kind of just a bunch of weird tradeoffs which maybe don't matter too much if you are just trying to run arduino sketches on it but it was annoying for me when I was trying to develop bare metal firmware for it in C.
Also, things like TPMs, Secure Boot, etc, are good security tools which can be used by an end user to get security guarantees over their device.
I use Secure Boot with Linux because, when done right, it means you can get full disk encryption without gaps (at best, without secure boot, you have an un-encrypted bootloader on a flash drive which decrypts your disk and boots your machine, and this is a clunky setup).
I use GrapheneOS's hardware attestation to alert me if something compromises my android phone's operating system.
Now it's true that these features are abused by companies like Google to force you to run a blessed Android build if you want to use e.g. Google Pay (which is the only mobile payment option in e.g. the UK). But it's important to separate the technology from the bad actors abusing it.
The NHS will accept you on waiting lists, if you're in one or two lucky regions, you have to wait a few weeks, otherwise you have to wait years. If you are in a very unlucky region, you can randomly get dropped from the waiting list, and effectively barred from ever getting back on it, because someone looked at the referral and diagnosed you as not having ADHD. Under the NHS you are not entitled to a second opinion (hence why you don't get to go back on the list).
So the NHS has this system called "Right to Choose" (RTC) where private care providers can register to offer services to NHS patients, charged to the NHS. You go to your GP and you say: "Hi, I noticed that if I go on the NHS waiting list for an ADHD diagnosis, it's uncertain if it will come before or after the heat death of the universe. Can you please refer me to this private provider of my choice instead?" And if your GP knows what RTC is, you get on the private provider's waiting list which is often between to 2w and 1y.
Cool, so that solves it right? Okay, but what happens once you're diagnosed? If you decide to go with the medication route (somehow it's either Meds or therapy but not both - what?), they give you a prescription. You take it to your local pharmacy to fulfil, and you fulfil it at the NHS prescription cost (currently just under £10 per prescription). You do this for a few months, trying different things until you find something that works for you. Now what?
Most providers will tell you to move to a "Shared Care Agreement". They contact your GP and say: "Hi, this person needs meds, they're stable on these meds, can you take over prescribing them." and for a while some GPs would be like: "Sure, that seems like the right thing to do in this situation."
Recently the advice has been for GPs to drop SCAs for ADHD medication. Why? I honestly have no complete picture. But the gist seems to be that it costs the GP practice time and money, that the NHS doesn't reimburse. IDFK. To me it sounds like people with ADHD are being used as a pawn in some idiotic game of chess between the regional NHS authorities and whatever higher-ups set the budgets for those regional NHS authorities. The current move is "People with ADHD get fucked+". I guess we're waiting for the reply from the higher ups. This is a conference chess game and who knows if the privately owned Royal Mail is going to actually deliver the letters in a timely fashion.
So now people who have been stable on medication for months to years are suddenly being told that they have 6 months to get an NHS diagnosis (which in most cases takes at least a year) or switch to a private provider that the practice likes (whose waiting list is now almost inevitably close to a year because everyone else is in the same shoes).
So now that you've successfully managed to deal with a bunch of bullshit, get a diagnosis, deal with the pains of titration etc, you are suddenly told you have 6 months before you'll undoubtedly become unproductive and struggle to hold your job.
And on the Nth day, the devil started creating Hell, and then stopped 5 minutes later because he realised that the UK already existed and would suffice.
Just for context, I run Postgres on an OpenBSD host (will probably be FreeBSD in the near future) to back an instance of davical which is a caldav server used by a total of two people.
I will keep tuning in mind if I ever actually use Postgres for anything significant but for now it seems like it would probably be wasted effort.
While I'd agree that Debian is boring, it still seems to me that Postgres isn't, even with this in place upgrade tooling. I still have to remember a specific upgrade command special to Postgres.
https://www.openbsd.org/faq/upgrade77.html
https://github.com/openbsd/ports/blob/master/databases/postg...
I have _one_ database, not a cluster. I back it up every day anyway.
You're telling me I have to specifically use Debian, and have a cluster, to get a good experience out of Postgres?
Doesn't sound very boring to me.
Surely you mean MySQL / MariaDB.
With Postgres I literally have to re-read docs every time there is a major version upgrade because I need to remind myself how to dump the database and re-import it into the new version because it's 2025 and Postgres still hasn't come up with a way to not have you do this.
Thought: Maybe we can organise and collectively hire this PR team to get Google, other big tech, and our governments, to look bad... And get shit done that way... If 2025 is the year of the PR spin, surely the only counter-measure is counter-spin?
Edit: Hold on, I think I just re-invented the concept of a political party.
My key take-aways (not to say there aren't plenty of others):
- Request: "Do not introduce Digital ID cards" - Response: "We will introduce a digital ID within this Parliament" - Not even an acknowledgement. Gotta love being governed by my mum who always knows best.
- "By the end of this Parliament, employers will have to check the new digital ID when conducting a ‘right to work’ check." followed by "For clarity, it will not be a criminal offence to not hold a digital ID" - now "not hold" might mean "not keep on your person at all times" or it might mean "not have one at all" which is ambiguous, but why does it matter if I have to be jobless without one?
- "This will help combat criminal gangs who promise access to the UK labour market in order to profit from dangerous and illegal channel crossings." - so rather than going after the criminal gangs, you're instead going after everyone who lives here to force them to own a phone in order to hopefully make it hard enough for someone who is here illegally to get a job... But as an EU citizen, I already have to present proof of my ILR to new employers. What difference will this make?
- "Digitally checkable digital credentials are more secure than physical documents which can be lost, copied or forged, and often mean sharing more information than just what is necessary for a given transaction." - Ah, they finally elaborated on a key point. So you will store a key on an HSM. And can it be any HSM? Because if it's a virtualized HSM then the credentials can be copied, but if its only an approved HSM, then now you make having a job in the UK strictly dependent on specific hardware from specific vendors.
Still no clarity on whether they will lock it down to Android builds which license GMS or not. Their constant mentions of google pay and apple wallet make me think the UK government will be formally endorsing a duopoly.
Thanks UK government, I hope they pay you well to screw me over.