How I build
Standards, not preferences
Most software doesn’t fail because someone picked the wrong framework. It fails because nobody decided what should happen when the database is down, the third-party service is slow, or the person using it has no signal.
These are the rules I hold myself to across every product in this studio. They are deliberately unfashionable, and each one is here because ignoring it has cost me something.
-
01
Fail soft, and never lose the thing that matters
Every system has a piece of data it must not drop. Find it, write it down first, and treat everything after that as an enhancement. An enquiry on this site is stored in the database and appended to a file before any email is attempted, so a dead mail server produces a logged warning rather than a lost customer. The visitor only sees an error if every one of those routes failed.
-
02
Boring technology, chosen on purpose
The right stack is the one that will still install in four years. Sometimes that is a modern application framework with a proper type system; sometimes, as with this site, it is plain PHP with no build step, where deploying is copying a folder and there is nothing to break in an upgrade. What is never acceptable is a dependency nobody can justify, added because it was the default.
-
03
It works before the JavaScript arrives
Pages render and forms submit without a line of client-side script running. Scripts then add the things that genuinely improve it — inline validation, a mobile drawer, motion — and if one fails to load, nothing essential goes with it. This is also, incidentally, why the site is fast: there is no framework to download before a paragraph of text can appear.
-
04
The server is the only thing that gets believed
Anything a browser sends is a suggestion. Totals are recalculated server-side from the underlying lines, money is stored as whole cents rather than floating-point numbers, and headers that claim to identify a visitor are ignored unless the machine that sent them is on a list I wrote myself. Trusting a forwarded header blindly is how a login lockout stops locking anybody out.
-
05
Decisions are written down with their reasoning
Every product here keeps a decision log: what was chosen, when, and why the alternatives were rejected. It costs a few minutes and it stops the same argument being had three times, six months apart, by a person who has forgotten the constraints — usually me.
-
06
Security is a default, not a phase
Output is escaped as a habit rather than a review item. Every form carries a token that cannot be replayed. Database rules deny access first and grant it deliberately. Passwords are hashed and live outside the repository. None of it is exciting, and all of it is cheaper to do on the first day than the day after something happens.
-
07
Built on a phone first
Screens are designed at the smallest realistic width before anything else, with touch targets sized for someone using a thumb outdoors. Desktop is the adaptation. A layout that only works on the machine it was written on is not finished.
-
08
“Done” means verified
Not “the code is written” — checked, on the real thing, with the evidence recorded. Automated tests where they earn their keep: money arithmetic, access rules, anything that must survive being run twice. Everything else gets looked at by a human, because assertions catch geometry and never catch wrong.
-
09
No third parties watching your visitors
No analytics scripts, no advertising tags, no fonts fetched from someone else’s server. The visitor statistics behind this site are counted by the site itself and use no cookies at all, which means loading a page here reports your visit to nobody. Privacy law is easier to comply with when there is nothing to disclose.
The long version is in the journal
Working notes on the decisions above — including the ones that went wrong and what they cost to put right.