Twenty Things That Were Exhausting to Explain to Software Developers
A growing list of things about data, software, and reality that apparently aren't technical enough to be technical requirements.
These are all real things I have had to inform at least one colleague or ex-colleague when working with software. Sometimes, I've not been in the position to inform the person directly but really really bloody should have done.
I have intentionally not included topics/items where when I've explained, or covered it, it's been understood and taken on board without much fuss. Everything here is something specific where I have started with not getting believed, or understood. And depending on topic and team, it's taken hours to even months or years of time trying to get it through.
I've also obfuscated, combined or changed some details to keep the individuals less identifiable.
So now, it's on the internet. In the hope that others might encounter someone who have read this list beforehand.
- Audit means Audit. Assume any real “audit” feature needs to withstand scrutiny in court. And honestly, you want anything to do with your software out of courts whenever possible. Don’t let your software record keeping be drawn in.
- Logs have to be write/append only. No you can’t generate log values using your normal database entries on the fly, *not store the log* and expect that to remain consistent over time. No, if a linked record has changes, which showed in the log, if that linked record is then disassociated with the other record, the *original messages from the log* need to remain there.
- Users need as much traceability and control as we get as software makers - if you give them a total in their shopping cart, they want to know what things in the basket add up to that total, and the option to remove items from that basket. And to know the stuff they can’t control eg tax and how that adds to the total. Seems ridiculously obvious in this context but in specialist systems, often for STEM or STEM adjacent workers I am constantly fighting for variants of this same need.
- The file paths changing between two initially identical collection of files when creating a zip will create two *different* zip files. No you cannot claim they are the same upload.
- A file being in a binary format doesn’t mean it isn’t decodable. Goodness me this should not be obscure knowledge in the day of ChatGPT. It's not an encryption format. I was doing this stuff with friends in the 2000s to solve puzzle hunts for fun.
- People will use the data you gave them in other systems. If you say no, and they need it, they’ll do it anyway, you just won’t know about it. There are whole *worlds* of Excel, PowerBI, screenshots, docs, and other workarounds going on. And it gets more varied in the age where someone can ask a LLM to assist them creating tools for processing or scraping data that isn’t quite what they wanted.
- Make the data storage represent what the user needs to do with it. Use temporal formats for temporal data. Use relational tools for relational data. Eg, if you create a scoring mechanism for something, people who use that score tend to also want to know what the score was over time. That means *storing* it in persistent storage at a frequency that makes sense, not getting a cron job every day to repeat the numbers to retain them.
- A deletion is an event, not an absence. If something was deleted, who deleted it, when, and what it contained may matter. “It’s gone” is often not an adequate record. Yes, you can follow data regulations like GDPR *and* adhere to this. Don’t be a jerk.
- Permissions are part of the data model. “The UI hides it” is not access control.
- Conversely, making your UI and API behaviour consistent with the authorisation model is table stakes. Don’t let a user click a “delete” button and accept their request and make it disappear using animations if you never checked if that event was authorised.
- Timestamps need provenance. Which timezone? When was the event recorded versus when did it happen? Was the clock trustworthy? These are different fields.
- An ID is not an explanation. A UUID may identify a thing, but users need meaningful labels, context, and relationships to understand it.
- Reproducibility is a feature. If the same inputs and configuration cannot produce the same result later, you need to preserve the version, inputs, assumptions, and environment - not just the final number.
- A dashboard is not a source of truth. Charts round, filter, aggregate, and change. Users need a route from the headline number to the underlying records.
- “We can reconstruct it” is not the same as having retained it. Reconstruction depends on current code, surviving dependencies, and assumptions that may later be unknowable. I can point to the jira tickets where this one has driven me potty.
- Error messages are user interface. “Something went wrong” transfers debugging work to the person with the least access and context. Please please please map these out, test them as much as the shiny them changes and explicitly be intentional about what you’re expecting someone to DO with that message after reading it.
- Bulk actions need reversibility and receipts. If someone changes 10,000 records, they need to know exactly what changed and have a safe way back. Even if it went perfectly, you still need the receipt, and you need to give that to the people who have governance responsibility over the areas the bulk action covered.
- Data retention needs a policy, not vibes. Keeping everything forever creates risk; deleting things casually destroys accountability. Both need deliberate rules.
- An API is a promise. It is an agreement between people and systems about what will be done or shared. If people build workflows around it, quietly changing fields, meanings, pagination, or ordering breaks real work - even if your own UI still works.
- APIs have UX. Developers are users too. It’s just not necessarily animations or colour or typography.
Feel free to get in contact if you want to share your own!