How We Build: Engineering Tenets at OEES

Every engineering team has principles, but a lot of them are never written down. They live in code review comments, in the way a senior engineer sighs at a pull request, in "we tried that once and it didn't end well." That works when everyone has been around long enough to absorb them. It works much less well when the team grows, and it doesn't work at all for the AI agents that now write a meaningful share of our code. Agents can't pick up a sigh, humans work better when communication is clear and information accessible.

I've written ours down. This is my attempt to put into words how I think we try to build software at Octopus Energy España: what we value, what we avoid, and why. Some of it comes from things we've got right, and more of it, honestly, from things we've got wrong.

A few things to know before you read on. These aren't laws, they're defaults: stuff we do unless there's a good reason not to. Each tenet comes with a rule, the reasoning behind it, and when to break it. If you are to break one, you should say so and say why, be ready to defend your thinking. Silent exceptions are how principles quietly die, how things disorganise and we lose sight of our north stars.

These apply to everyone who ships code here, human or otherwise.


1. Technology serves the business

Rule: Every technical decision must trace back to how it serves our customers and the business mission.

Technology exists to serve people, and in our case it does that through a business. We don't build things because they're interesting. We build them because they make energy fairer, simpler, and cheaper for our customers. If the optimal way of serving the business changes, it's us who adapt, not the other way around.

This does cuts both ways: it's also our responsibility to call out the business when it drifts from its own mission or makes decisions that will hurt it. Serving the business doesn't mean silently executing bad ideas.

Break it when: Never in spirit. In practice, some work (security, maintenance, paying down debt) serves the business indirectly. Make that link explicit instead of assuming it's obvious.


2. Create customers or cut costs

Rule: Know whether your work creates or keeps customers, or whether it's a cost. Invest in the first and minimise the second.

Peter Drucker put it bluntly in The Practice of Management: "There is only one valid definition of business purpose: to create a customer." From that he concluded that a business has only two functions that produce results, marketing and innovation. Everything else is a cost.

For engineering, this gives us a sorting test. Work that makes our product easier to choose, easier to stay with, or better than the alternatives is marketing in Drucker's sense, even if it's a billing fix or a faster sign-up flow. Work that creates new value for customers or new ways for us to operate is innovation. Both deserve our best thinking.

Everything else (internal plumbing, integrations, admin tooling, compliance) is necessary but is a cost. That doesn't make it unimportant. It means it should be done as simply, cheaply and boringly as possible (see #7), so that our time and creativity go where they produce results.

Before starting any piece of work, ask: does this help us create or keep a customer? If you can't answer, find out before writing code.

Break it when: Cost work is blocking results work. Paying down debt, hardening security, or fixing a broken pipeline can be the highest-leverage thing you do, but be honest that you're doing it to unblock results, not for its own sake.


3. Languages are tools, not identities

Rule: Choose the stack by fit for the problem, and be fluent enough to judge whatever ships.

The engineering principles matter more than the tech stack. With AI writing a growing share of our code, the craft has shifted back towards its purer form: thinking clearly about problems, systems, and trade-offs. Syntax is the cheap part now.

Cheap is not free, though. You can't review, debug, or secure code you don't understand, whether a colleague or an agent wrote it. We don't marry languages, but we never ship what we can't read.

Break it when: Consistency outweighs fit. A slightly worse tool the whole team knows usually beats a slightly better one only one person understands.


4. You own what you ship

Rule: If you merged it, it's yours, regardless of who or what wrote it or when it breaks.

"The agent wrote it" is never an explanation, and neither is "I copied it from Google" or "it was in the ticket." Owning code means understanding what it does, how it fails, and who it affects. It means being the person who gets called after hours and the person who fixes it.

For agents, this means not presenting work as done until it has been verified: tests run, edge cases considered, assumptions stated. For humans, it means reviewing agent output with the same scepticism you'd apply to a confident new hire.

Break it when: You don't. Ownership can be handed over explicitly, but it can never be absent.


5. Don't be an idiot: the postmortem test

Rule: If you'd be embarrassed explaining a decision in a postmortem, don't make it.

Michael Scott's advice to Dwight Schrute still holds: if you're about to do something and realise an idiot would do it, don't do it. The trouble is that nobody thinks they're the idiot in the moment, so we make it concrete. Imagine the thing has gone wrong and you're explaining your reasoning to the team. If "I didn't think it would matter" or "it was quicker" is the best you have, stop.

This applies to deploying a product, architecting a system, and writing a line of code, or failing to write one.

Break it when: Never. Every other tenet has exceptions. This one is how you decide whether an exception is justified.


6. Simple beats clever

Rule: Choose the simplest solution that solves the actual problem.

Complexity is a cost we pay forever: in maintenance, onboarding, security surface, and the number of ways things can break at 3 a.m. Simple systems are easier to change, easier to secure, and easier to hand over to a colleague or an agent.

Gall's Law sums it up: complex systems that work tend to evolve from simple systems that worked, and complex systems designed from scratch rarely work at all. Start simple and earn complexity when reality demands it.

Break it when: The problem is genuinely complex. Then make the complexity explicit, isolated, and documented. Don't spread it across the codebase.


7. Boring by default

Rule: Use proven, boring technology for everything except what differentiates us.

Django, Ruby on Rails, PHP, and PostgreSQL built the web. They aren't exciting; they're reliable, well documented, and full of solved problems. Every novel technology we adopt spends some of our limited capacity for dealing with unknowns.

We spend that capacity deliberately, where OEES actually competes. Kraken handles the energy core. Commodity problems get commodity solutions. Custom builds are reserved for what makes us better than the alternative.

Break it when: The boring option measurably can't do the job, or the problem sits at our competitive edge. "It's more fun" doesn't qualify.


8. Reversibility sets the speed

Rule: Move fast on two-way doors and slow down on one-way doors.

Most decisions are two-way doors: if we get them wrong, we walk back through. A UI change, an internal tool, a feature behind a flag. Decide quickly, ship, and learn.

Some decisions are one-way doors: moving customer money, regulated processes (billing, switching, settlement), deleting data, public commitments, database migrations that can't be rolled back. These deserve proper review, testing, and a second pair of eyes, however urgent the deadline feels.

The most common mistake is treating every decision the same way: too slow on reversible ones, too fast on irreversible ones. Before starting, ask which door you're walking through.

Break it when: You can turn a one-way door into a two-way one (feature flags, staged rollouts, backups, dry runs). Do that first; it's almost always worth it.


9. Ship it, then listen

Rule: For two-way doors, an MVP is the default and customer feedback is the spec.

Perfect is the enemy of good. Something in customers' hands today teaches us more than a polished plan does next quarter. When we treat customers well and build a real relationship with them, they become our most willing beta testers, and that's a privilege, not a risk.

Listen carefully, though. Customers know their problems better than anyone. They don't always know the right solution. Build for the pain they describe, not necessarily the fix they prescribe.

Break it when: You're behind a one-way door (see #8). Nobody wants an MVP of their energy bill.


10. If it isn't observable and written down, it isn't done

Rule: Work is finished when we can see it running and someone else can understand why it exists.

Shipping code is half the job. The other half is knowing when it breaks and making sure the next person (or agent) doesn't have to reverse-engineer your thinking.

Observable means logs that answer real questions, alerts on things that matter, and a known answer to "what happens when this fails?" Written down means the decision, the trade-offs, and the reasoning are captured somewhere findable: a README, a spec, an ADR. Agents can't ask you what you meant six months ago, and neither can your colleagues once you've moved on.

Break it when: It's a genuine throwaway (a one-off script or a spike). Label it as such, and delete it when you're done.


Final thoughts

If you squint, all ten tenets say the same things: build simple things that customers actually need, own them completely, be honest about the risks, and leave everything easier to understand than you found it. Most of the other stuff is detail - not to be discarded necessarily, but put it in its place.

The tenets are meant to be argued with. A principle nobody ever challenges is either obvious or ignored, and I'd rather ours were neither. If one of them is wrong, or stops being true as we grow, we should change it. We should propose an edit, make our case, and if it holds up, this document will get better. The same goes for agents: if following a tenet would clearly produce a worse outcome, we must flag it rather than obey blindly.

What shouldn't change is why we're doing this. We're here to make energy fair, clean, and simple, and to give our customers service good enough that they tell their friends. Good engineering isn't the goal. It's how we earn the right to pursue whatever the goal is that day.

← back to all posts