← Notes

Engineering leadership · Delivery · Code review

Staying hands-on while leading delivery

Hands-on leadership does not mean taking every difficult ticket. It means staying close enough to the code and production path to make sound decisions, while giving the team clear ownership of the work.

7 min read by Anas Amin

Leadership and coding are one feedback loop

Architecture, planning, review, and deployment are often treated as separate responsibilities. In practice, each one corrects the others. A deployment exposes operational constraints. Those constraints change an architecture decision. The decision changes how work should be sliced. Code review shows whether the slice was clear enough.

A lead who never touches that loop can make decisions based on diagrams that no longer match the system. A lead who keeps all hard implementation work has the opposite problem: the team waits for one person and never gains ownership.

Write down the decision before the task list

A short decision note is usually enough. State the problem, the constraints, the chosen approach, the alternatives that were considered, and what would cause the choice to be revisited. The purpose is not documentation volume. It is to stop the same argument from restarting inside every pull request.

Keep the decision close to the codebase or delivery workspace. Link it from the work that implements it. If the implementation reveals a wrong assumption, update the decision instead of quietly drifting away from it.

  • What user or operational problem are we solving?
  • Which constraints are fixed, and which are only preferences?
  • What is deliberately outside this change?
  • How will we know the decision is wrong in production?

Break work down by risk, not by technical layer

Separate backend, frontend, database, and deployment tickets can look tidy while hiding the fact that nothing works until all four finish. A thin vertical slice gives the team an earlier integration point and makes unclear contracts visible.

Start with the part that can invalidate the plan: an external API, a migration on real-shaped data, a permission boundary, a slow query, or an unfamiliar deployment target. Proving that boundary early is more useful than completing the easiest files first.

  1. Name one user-visible or operator-visible outcome.
  2. Identify the riskiest assumption inside that outcome.
  3. Create the smallest vertical slice that can test it.
  4. Add acceptance notes, edge cases, and rollback needs before assignment.
  5. Give one person ownership of the slice while making dependencies explicit.

Choose hands-on work that improves the team

The lead should not automatically take the most visible feature. Better hands-on work often sits at a boundary: the first implementation of a pattern, a risky integration, a production defect with unclear ownership, or tooling that removes repeated friction.

After proving a pattern, leave an example and hand the next use to someone else. If only the lead can extend it, the code did not create leverage. It created another dependency.

  • Prototype the uncertain part. Use a narrow branch or spike to prove feasibility, then turn the result into team-owned production work.
  • Build the first reference path. Implement one complete example when the team needs a concrete pattern more than another document.
  • Debug across boundaries. Step in when the failure crosses application, database, network, and deployment layers, then share the diagnosis.

Review the contract before the style

A useful review starts with behaviour. Does the change match the task? Does it preserve tenant and permission boundaries? What happens on retry, cancellation, or partial failure? Can it be deployed and rolled back safely?

Style and naming still matter, but automated tools should handle mechanical rules where possible. Human review time is better spent on assumptions, domain behaviour, data changes, security, and operational cost.

  • Ask for a smaller pull request when unrelated decisions are mixed together.
  • Write comments that explain the risk, not only the preferred edit.
  • Separate blocking correctness issues from optional improvements.
  • When a pattern repeats, improve the shared rule, test, or example instead of leaving the same comment again.

Keep deployment inside the definition of done

A feature is not finished when it works on a developer machine. The work item should name configuration changes, migrations, health checks, logs, rollback steps, and any manual action needed in the target environment.

The lead does not need to press every deployment button. The lead does need to make the path understandable and ensure more than one person can operate it. Pair on the first release of a new path, record the result, then rotate ownership.

A simple operating loop

One loop from decision to production learning
StageConcrete outputQuestion to answer
DecideShort decision noteWhy this approach under these constraints?
SliceSmall vertical work itemsWhat can be delivered and checked independently?
ImplementReference path or owned feature sliceWhere is direct lead involvement most useful?
ReviewRisk-focused feedback and testsDoes the behaviour hold at its boundaries?
ReleaseRunbook, health signal, and rollback pathCan the team operate this change safely?
LearnUpdated decision, task template, or shared patternWhat should be easier next time?

Warning signs

The balance is wrong when every technical question waits for the lead, pull requests remain open because one reviewer is overloaded, or the lead works on hidden emergency code that nobody else understands. It is also wrong when architecture decisions have no contact with production behaviour.

  • Move routine decisions into examples, tests, and short decision records.
  • Give review ownership to the engineers closest to the area, with a clear escalation path.
  • Keep a small amount of direct implementation work, chosen for learning and risk reduction.
  • Review incidents and deployments with the team, then change the working system rather than relying on memory.