I strongly disagree. Making invalid state unrepresentable is important.

> wastes space > premature optimisation

A timestamp is a witness of when the email was verified. Since if they’ve verified can be calculated from it, having both is not only redundant but allow invalid states to be represented.

Cases like email verified are often followed by the need to know when. Say an expiry system. Going from bools, you are faced with the hard choice of how to migrate existing state.

Databases also warrant more care as a source of persistent state - accessed by multiple versions of your software. If you don’t have this persistency, then it matters less.

> any other fields that happen to be strings or numbers or blobs were changed > implement proper event logging

Event logging is orthogonal to your database state. If your business logic needs dirty flags or timestamps they should be stored in the database, not queried.

And if you do need it for other fields, adding the bool is the perfect time to ask yourself if what you need is a timestamp.

> way we don't start with floats rather than ints "just in case" we need fractional values later on

Floats are a subset of int, and a natural migration. A bool can be calculated from a timestamp, but not the other way.

> Cases like email verified are often followed by the need to know when.

And often not. That's the point. Avoid premature optimization. (FWIW, I've never encountered a system in my life where a successful email verification then expired after a period of time.)

> having both is not only redundant but allow invalid states to be represented.

That's a different topic. That's about what to do when you know you need the timestamp. The article is about using a timestamp when you don't have a timestamp requirement.

> they should be stored in the database, not queried.

I don't know what that means. Everything in the database is queried. And you can store your events in the database, in one or more event log tables.

> Floats are a subset of int, and a natural migration.

I think you meant to say the opposite, but even that's not true because of precision. And so too are enums a natural migration from booleans. That's the point -- start simple and extend as needed.