Security. Adding security as an afterthought normally leads to insecure systems. Always analyze your security requirements, perhaps you decide that some parts do not need strong security, but at least you have done the analysis.
Yes, but some customers don't state it in their requirements because they either think it is an obvious requirement, or because they have not thought about it at all.
No matter what, as an ethical software developer you should always consider security during system development.
> Applications of Zero One Many. If the requirements go from saying “we need to be able to store an address for each user”, to “we need to be able to store two addresses for each user”, 9 times out of 10 you should go straight to “we can store many addresses for each user”, with a soft limit of two for the user interface only, because there is a very high chance you will need more than two. You will almost certainly win significantly by making that assumption, and even if you lose it won’t be by much.
I agree in general, but for the address example in particular I can't remember how many times I have to provide a shipping address and a billing address, or residential address and mailing address, etc. I also can't remember any time interacting with a system that asks for 3 or more addresses.
On some online stores in Brazil you can have more than one shipping address, for example to send a purchase straight to parents, siblings, etc... and can select any of them on checkout.
These situations are so common I've started building join tables for such data rather than simple foreign keys by default if there's even a wiff of the possiblity that there might be multiples. The downsides are so small and the upside is huge.
YAGNI only applies for a "top-level" applications. For libraries used by third parties (e.g. the standard library of a language) you want clients do be able to do things you haven't imagined, so different trade-off are in place. For software which cant easily be updated, like mars rover software, you also have to prepare for all eventualities up front.
I don't agree with the article that you should always select a relational database up front. Should Calculator really use a relational database to persist configurations? This is exactly where YAGNI applies.
> By this I mean, if you need a database at all, you should jump to having a relational one straight away, and default to a relational schema, even if your earliest set of requirements could be served by a “document database” or some basic flat-file system.
Emphasis added.
So the author probably agrees with you that a calculator doesn’t need a database.
The calculator on Windows does persist a few settings, for example windows size and whether "scientific" or "standard" mode is selected. This could be saved in a config file or some other storage format. Windows has a simple per-application key-value store for such settings. A relational database would be overkill and increase overall complexity.
I’m laughing a bit at the calculator example though because, in 2021, if the calculator started to be configurable from within the UI out have any kind of persistence (eg keeping your calculation history from session to session) my very first inclination would be to grab SQLite and skip right past plain text/YAML/.ini etc files.
YAGNI is is also postponing abstractions, flexibility and extension points until the application requires it. But for a library you need to design the abstractions up front because you don't know the requirements of the users, and it is difficult to change later.
> I don't agree with the article that you should always select a relational database up front. Should Calculator really use a relational database to persist configurations? This is exactly where YAGNI applies.
I don't think this is where yagni applies at all. Either way, if you want to start storing data, you will need to evaluate it. Yagni stops us from saying "but what if, but what if, but what if!"
To decide whether we should allow storage to be a yagni exception, we need to look at what we do first. So the question is, how often are we writing Calculator, and how often are we writing an app to help organise a business?
I think the balance is on the latter side. So when we're trying to decide how to store our data, if we have strong reasons to prefer a simple text file, then we should. But by default, we should go for sqlite or something bigger.
Timestamps needs to come with a huge warning. If you want to have a created_at timestamp for every record, go for it. HOWEVER be very, very careful about how you use this field. The semantics of created_at are the time at which the record entered the database, that it is, nothing more, nothing less. Trying to use created_at to represent something that happened in the real world bites so many developers. Users will want to tweak the value of the field since there was a delay between the event occuring and the event getting input into the system. Also once you start supporting data imports, backups, and restores, its clear that created_at has nothing to do with when the event was actually created.
Honestly I still lean away from automated timestamps just because the knowledge of when a record entered the database is not that useful and the danger of some developer using the field incorrectly is too high.
created_at/update_at are nowhere near a proper logging solution and just give developers the illusion that they have one.
First, I'd rename the column to something like "record_created_at" to empahsize its the recording of the record and not the actual creation date.
Second, if I was going to do a default version, I would probably use two fields, the above record_created_at and an additional "created_at" field. By default they would be the same, however the understanding would be that created_at is potentially available to the user, settable by import, and record_created_at should be treated as immutable.