Engineering service
Java and Spring Boot backend development
The services that hold orders, scheduling, stock and payments, built to keep running while someone works out what went wrong.
What we build
Most of what we deliver is a backend service that something else depends on. An API that a mobile application talks to. A processing service that consumes events and updates state. An integration layer sitting between a system of record and three things that need to read from it. The visible part is usually somebody else's; our part is the bit that has to be correct.
In practice that means modern Java on Spring Boot: REST endpoints and event-driven consumers, Spring Security for authentication and authorisation, JPA and Hibernate over a relational database with versioned schema migrations, and a test suite that runs against a real database rather than a wall of mocks. We use the boring parts of the ecosystem deliberately, because the boring parts are the ones that still work in four years.
Why Java, still
Java gets chosen here for reasons that survive contact with a production incident. The tooling for seeing inside a running system is mature: heap and thread dumps, flight recordings, and metrics that do not require you to have predicted the failure in advance. The language has long support horizons, so a service written today is not a rewrite in three years because a runtime went out of maintenance. And in South Africa specifically, the hiring pool for Java is deep, which matters when you eventually want to bring the work in-house.
None of that makes Java the right answer to every problem. If a job is a scheduled data transformation that runs nightly, we will say so rather than wrap it in a service. The point is not the language, it is that the thing keeps working.
How we work inside a codebase
Tests that mean something. Coverage percentages are easy to game and tell you very little. We write tests around the paths that carry money and risk: the ones where a wrong answer costs somebody real money or loses a record. Those run against a real database in a container, because the bugs that hurt tend to live in the gap between what the ORM says will happen and what the database actually does.
Migrations that go both ways. Schema changes are versioned and applied by the application, never by hand against a production database at eleven at night. Where a change cannot be reversed cleanly, that gets written down before it ships, not discovered afterwards.
Configuration and secrets kept out of the build. The same artefact runs in every environment, configured from outside. Credentials never enter the repository, and rotating one does not require a redeploy.
Observability from the first commit. Structured logs with a correlation identifier that survives across service boundaries, metrics on the handful of numbers that actually indicate health, and alerts that fire on symptoms a person can act on rather than on every transient blip.
The shapes this work usually takes
A new service, from nothing. You have a process that has outgrown spreadsheets and manual coordination, and it needs to become software. We scope it, build it, and hand it over.
A codebase that has outgrown whoever built it. Something works, mostly, but nobody currently on the team wrote it and everyone is nervous about changing it. We take it over, get it under test, and make it safe to modify before we change any behaviour.
A service that has stopped coping. It was fine at the old volume and is not fine now. This is measurement work before it is engineering work: find where the time actually goes, fix that, and resist the urge to rewrite the parts that were never the problem.
What you are left holding
Runbooks for the things that go wrong, architecture notes explaining why the structure is the way it is, environment setup that someone new can follow, and a handover session with your team. If you stop working with us, nothing should break. That is the deliverable.
Have a Java service that needs building, or rescuing?
Tell us what the system does and where it hurts. The first conversation is with the engineer who would do the work, and if Java is the wrong answer for your problem we will tell you that instead.