The Engineering Practices I Advocate for on Every Project I Join

by Arif Ikhsanudin, Backend Developer

Some practices are context-dependent — they make sense for certain team sizes, certain stages, certain domains. Others are close to universal. Here's the short list I push for regardless of where I land.

Why I Have a List at All

Contracting across different teams and organizations teaches you something quickly: a lot of the dysfunction is the same. Different products, different stacks, different industries — but the same categories of pain showing up in different shapes.

That repetition has given me a working list of practices that, in my experience, pay back with interest on almost every project. Not dogma — starting points. Things I advocate for early, explain the reasoning behind, and adjust based on what I find.

Some teams already have these in place. When they do, the work is easier and the outcomes are better. When they don't, introducing them tends to reduce friction faster than almost any technical change.

Automated Tests for the Things That Can't Break

I'm not a test coverage zealot. A 90% coverage number on tests that verify implementation details is less useful than 40% coverage on tests that verify the behaviors the business depends on.

The question I ask: what are the things in this system where, if they broke silently, we'd have a real problem? Payment calculations. Authorization logic. Data transformation rules. The core state machine of whatever the product does.

Those things need automated tests, and they need tests that verify the observable outcome, not the internal mechanics. Tests that say "when I give this input, I get this output" survive refactoring. Tests that say "this method was called with this argument" don't.

I'd rather have twenty meaningful tests than two hundred brittle ones. The first set gives you confidence. The second gives you a chore.

Structured Logging With Correlation IDs

The first time you're on-call for a system that produces unstructured logs with no request tracking, and you're trying to trace a specific user's session through three services, you understand immediately why this matters.

Structured logging — JSON, consistent field names, a correlation ID that follows a request from entry to exit — is the difference between a fifteen-minute diagnosis and a three-hour one. On a system under load, it's often the difference between finding the cause and not finding it at all.

Getting this right early costs almost nothing. Adding it to a system that's already in production and logging in fifty different formats is painful and slow.

I push for this on day one of any new service. On existing systems, I push for it incrementally — at minimum, adding a correlation ID to new services and making sure it propagates across calls.

Explicit Error Contracts

Every service has an implicit contract for what it returns when something goes wrong. "Implicit" is the problem. Implicit contracts get violated, because nobody actually documented them, and the callers make assumptions that turn out to be wrong.

When I design or review a service interface, I ask: what does this return on failure, and does the caller have enough information to respond usefully?

A good error response includes:

  • A stable, machine-readable error code (not just an HTTP status)
  • A human-readable message that's useful for debugging
  • Enough context to identify what specifically failed without log-diving

This matters especially in systems where one failure cascades through multiple services. If the root cause error is swallowed somewhere in the middle and replaced with a generic "something went wrong," debugging becomes an excavation.

Dependency Review Before Adoption

Every dependency is a surface of risk you don't control. It might introduce a vulnerability. It might break its API. It might stop being maintained. It might have a license that creates legal complications.

None of these risks are reasons to avoid dependencies — that would be impractical and often counterproductive. They're reasons to evaluate before adopting.

My quick checklist before pulling in a new library:

  • When was the last commit? Is the project actively maintained?
  • How many open, unresolved security issues are there?
  • What would replacing this look like if we had to?
  • Does the license work with the project's requirements?

This takes ten minutes. It has saved me from adopting dependencies that looked convenient but came with real problems attached.

Decision Records for Non-Obvious Choices

When the team makes a decision that isn't immediately obvious — why this database over that one, why this architecture over the alternatives that were considered — I push to write it down. Even a paragraph: the context, the alternatives, the reasons for the choice.

The most common pushback: "We all know why we made this decision." The problem surfaces six months later, when two people on the team have different memories of why, and a third person who joined afterward has no idea.

Decision records don't need to be elaborate. A comment in the relevant code, a section in the architecture doc, a ticket in the backlog marked "context." The format matters less than the existence of the record.

Code Review With Explicit Purpose

Code review processes that exist as a gate — "someone has to approve before merge" — are better than nothing. Code review processes that exist with explicit purpose are considerably better.

The purpose I advocate for: catching correctness problems before they ship, propagating knowledge across the team, and maintaining the quality standards the team has agreed on. Not liking my way of doing it.

The distinction matters because it changes what reviewers focus on and how they give feedback. A review process oriented toward correctness produces different comments than one oriented toward personal preferences. And it's considerably less demoralizing for the author.


The practices worth advocating for are the ones that compound — small investments in discipline that pay back in reduced friction across every future change.

Scale Your Backend - Need an Experienced Backend Developer?

We provide backend engineers who join your team as contractors to help build, improve, and scale your backend systems.

We focus on clean backend design, clear documentation, and systems that remain reliable as products grow. Our goal is to strengthen your team and deliver backend systems that are easy to operate and maintain.

We work from our own development environments and support teams across US, EU, and APAC timezones. Our workflow emphasizes documentation and asynchronous collaboration to keep development efficient and focused.

  • Production Backend Experience. Experience building and maintaining backend systems, APIs, and databases used in production.
  • Scalable Architecture. Design backend systems that stay reliable as your product and traffic grow.
  • Contractor Friendly. Flexible engagement for short projects, long-term support, or extra help during releases.
  • Focus on Backend Reliability. Improve API performance, database stability, and overall backend reliability.
  • Documentation-Driven Development. Development guided by clear documentation so teams stay aligned and work efficiently.
  • Domain-Driven Design. Design backend systems around real business processes and product needs.

Tell us about your project

Our offices

  • Copenhagen
    1 Carlsberg Gate
    1260, København, Denmark
  • Magelang
    12 Jalan Bligo
    56485, Magelang, Indonesia

More articles

Why Developers Need Time to Refactor Code

Refactoring often feels like unproductive work. But skipping it is like ignoring weeds in a garden—they’ll choke everything else eventually.

Read more

Rollback Is Not Failure. Not Having One Is.

Teams that treat rollback as an admission of failure avoid building rollback capability — which means when a bad deployment happens, recovery takes far longer than it should. A defined, tested rollback path is a prerequisite for confident deployment.

Read more

Your Unit Tests Are Testing the Wrong Thing

Most unit test suites are heavily weighted toward testing implementation details rather than behavior. When the implementation changes — even correctly — the tests break, and the suite becomes a maintenance burden instead of a safety net.

Read more

Dubai Has No Local Backend Talent Pipeline — Every Hire Is a Global Search

You posted a backend role in Dubai. Half the applicants are in India. A quarter are in Europe. The ones already in the UAE want AED 40K per month. Nobody is local and cheap.

Read more