Full stack developer
How I write software: tests first and parts you can replace.
TDD, SOLID, continuous integration and a handful of other rules I do not negotiate. Each one with its reason, a case where it applies and the public text that defines it.
- Tests TDD, test pyramid
- Design SOLID, hexagonal, KISS and YAGNI
- Delivery CI/CD, semantic versioning, twelve factors
The rules I do not negotiate
Not fussiness: each one pays for itself the first time something has to change while the program is already running with people inside it.
A small job and a large one are written the same way. The difference is how many times you will come back: software that solves a company process gets touched every few months because the process changes, and what decides whether that is cheap or ruinous was decided on day one, when someone chose where to put each boundary.
- A test before the code If I cannot write the test, I do not yet know what I am asking the program to do. Writing it first is the shortest way to find out.
- One reason to change per part Single responsibility and dependencies pointing inwards: the use case does not know whether PostgreSQL, a file or a third-party API sits behind it.
- Boring wins No dependency gets in without explaining which problem it solves today. What is not needed does not get written.
- Errors are stated, not hidden An API answers a failure in a format the other side can read, with its code and its reason, not with a 200 and a loose string.
- Delivery repeats identically Configuration outside the code, repeatable deployment and a numbered version: the production server is not a handmade artefact.
- Security is reviewed with a list Before calling anything done, the usual pass: authentication, permissions, user input, dependencies and logs.
What I do not do
Most of the work of keeping something cheap to maintain consists of what was left out.
I do not start by choosing a framework. First comes the process to solve and the data to store; the tool comes afterwards, and sometimes the answer is that none is needed. This site is the example: plain PHP, no database, no dependencies and no build step, because nothing it does called for one. It can be read end to end and it is served by a web server and nothing else.
I do not write code “for when we need it”. An abstraction layer with only one implementation is not flexibility: it is one more part to maintain and one more indirection to read. When the second one shows up, it gets extracted, and by then the tests are already written and the change is mechanical.
And I do not leave the interface for last. What you see has its own method, its own contrast and focus rules, and it is not improvised the afternoon before delivery.
Glossary of the craft.
The terms as they are used, with a case where I apply each one and the public text that defines it. So you do not have to take my word: you can check.
Questions.
Isn’t writing the tests first slower?
On day one, yes. The arithmetic changes as soon as something already in production has to be touched: without tests, every change means checking by hand what used to work, and you pay that every time. With tests you pay it once.
Can you apply SOLID without a framework, in plain PHP?
SOLID is not a library, it is where the boundaries go. You can do it badly with the most modern framework and well with a handful of files: what matters is that the logic does not know where the data came from or which screen it is going to.
What test coverage do you aim for?
I do not chase a percentage. A high number with tests that check nothing gives false comfort. What I want is for the things that hurt when they break —the calculation, the permission, the money— to be covered, and for every production bug to leave a new test behind it.
And if the project already exists with none of this?
You start where you are going to touch. Before changing a part, you write tests that pin down what it does today —even if what it does today is odd—; with that net, the change stops being a gamble. Rewriting the whole thing is almost never the answer.
Who decides when something is finished?
A list written before starting decides, not the feeling that it looks about right: tests pass, the error is reported in its format, the screen works with a keyboard and a screen reader, the version is numbered and the deployment ran the same script as always.
Sources.
Everything claimed here is described in a public text. These are them, with their body and their date.
- ISO/IEC 25010:2023 · Product quality model ISO/IEC JTC 1/SC 7 · 2023-11
- RFC 9110 · HTTP Semantics IETF · 2022-06
- RFC 9457 · Problem Details for HTTP APIs IETF · 2023-07
- OWASP Top 10 OWASP Foundation · 2021
- OWASP Application Security Verification Standard OWASP Foundation
- Semantic Versioning 2.0.0 semver.org
- The Twelve-Factor App Heroku
- Conventional Commits 1.0.0 Conventional Commits
- Continuous Integration Martin Fowler
- Hexagonal Architecture Alistair Cockburn
- DORA · software delivery research DORA (Google Cloud)
Where to go next.
- The stack, tool by tool What each language, database and systems piece does, and how each one gets chosen.
- The applications I have built Where all of this can be seen working, with links to try it.
- And the method on the other side Interface, accessibility and brand system: the rules for what you see.
Shall we talk?
Does this way of working suit you?
Tell me what you have in hand and I will tell you where I would start.

