They ask us for quality.
What is “quality”?
“Well, free of defects.”
(Oh it’s a lot more than that.)
What is a “defect”?
“Well, when it doesn’t work like we expect it to. Like we agreed it should.”
Trust me, you didn’t specify how it works. That’s my job, as a developer.
To organize all that “what,” all that “how,” until it’s so incredibly specific that it can be done without thought — it can done by a machine.
Programming is hard.
Yet that is only the beginning.
You want more than you wrote down in that user story.
Quality is also: user experience. The software is up, it’s responsive, it’s clear, it’s pretty, it’s fast enough, it does enough at the same time. It works smoothly with all the other software.
And then there’s everything you didn’t write down that you want it NOT to do.
Don’t show my data to anyone but me.
Don’t do useless work, or evil work.
Don’t get inconsistent no matter the input.
Quality is doing all these unnamed things and not doing all these other unnamed things.
all from this tiny user story that I turn into actions by the computer.
Software is hard.
Yet that is only the middle.
You want more than you’ve written down YET.
Next week, you’ll ask me to change it again, so that this feature works another way while every other feature ever mentioned (or never mentioned) stays in place.
And while the landscape changes, while the tech we build atop updates and upgrades and moves underneath us. Keep that modern, too!
Quality is continual change.
Software development is hard.
How am I supposed to do all this?
To keep all this straight? So even a machine can understand?
Clean Code. Test-driven development. Functional programming. Microservices. Refactoring. Pair programming. Think about security.
How does that help?
I’ve been developing software for 20 years, and I think I finally figured it out.
The one thing, the key factor that leads to quality software
That makes a 10x developer
That a good architect or lead developer or high-level IC has.
It’s not a programming language.
Not some agile process.
The good news is, you can get some of it.
The bad news is, you have to get it over and over.
The golden key to excellence is: a strong mental model of how the system works in context.
How it works on the tech, sure, you need that. Bigger: how the software works within the business it serves. How it interconnects with the rest of software. How it fits in the customer’s life.
And how it works with you, in a symmathesy with the team. The flow from your head to deployment to results.
You might say, well duh Jess, of course we have to understand what we’re building —
But we don’t. We can’t. Our business and software and tech stack and customers are complex waaay beyond what we can model fully in our heads. And they’re always changing. The tech updates, the people move and change.
And when you start a new project, you start over.
This mental model is never something we have and keep. We grow it. We keep growing it.
This is not easy. But it is powerful.
Understanding leads to quality in all its forms.
Of course an inaccurate or missing mental model of the system leads to bugs. Usually the kind where “I didn’t know I needed to look over there.”
More: understanding our software in context makes a user experience.
“The customer wants to enter a credit card so that they can pay.”
Knowing how credit card payments work means, I can tell them when they mistyped one digit. There’s a checksum function for that.
Understanding that this customer is in a public place, I can display fewer of those digits.
Understanding that authorization takes a while, I can show a loading screen, which is responsive.
Understanding that they’re paying for something that won’t be shipped right away, I can warn them that a debit card will place a hold on funds in their account.
Understanding the confidentiality of this data means that if I must store it, I put that in a separate service from everything else. I can find boundaries.
Boundaries give me a piece of the system that I can actually model.
They let me focus my understanding. Microservices help when they give us boundaries around a manageable amount of software. (Don’t forget to understand the inside and the in-between.)
How do we build up this mental model?
Engineering disciplines, done in the spirit of their invention, lead to understanding.
Clean code reflects our mental model, it gives it back to us when we return to that piece of the program.
Test-driven development makes us state what the code needs to do before we write it. And it forces us to leave boundaries.
Refactoring says, update the code to our current understanding before we change it.
Pair programming and mob programming push us to put our beliefs and decisions into words, to make them solid. And we spread them among the team, develop a reconciled mental model that we all share.
Functional programming makes it clear what code won’t do, within boundaries.
Domain driven design is my favorite discipline, because it aims directly for understanding, shared by developers, business, and the code itself: Explicit boundaries and clearly defined meaning with and between them.
Thinking about security — this one surprised me. It turns out starting with security leads to questions that lead to understanding. Like, what is this string? sixteen digits? not just any digits. How sensitive is it? Must we keep it? How long? What errors can happen?
These questions deepen our understanding of the system outside and inside
That’s how engineering disciplines work.
In the end, we create software out of understanding.
The code is only as strong as our shared mental model of how the software works in context.
Aim for that, and quality will be yours.