Giving Feedback That Engineers Actually Hear

A practical framework for delivering technical and behavioral feedback that drives change. Covers the SBI model, timing, peer feedback, performance reviews, and how to have the conversations that most managers avoid.

Engineers receive feedback constantly—code reviews, 1:1s, post-mortems, architecture reviews—but much of it fades into silence. Feedback that lands is rare. This page details how to give feedback that engineers *actually hear*, meaning they understand, act on, and remember it. It applies when you’re mentoring a junior engineer, reviewing a pull request, or leading a team-wide retrospective. The goal is not just to deliver feedback but to ensure it sticks.

Delivering Feedback That Sticks

Feedback is effective when the recipient can answer: *What should I change? Why does it matter? How do I start?* The process begins with clarity and ends with action. The most common failure is feedback that arrives as a list of comments, but vanishes into email or Slack. The engineer reads it once, nods, and forgets. To fix this, focus on three phases: *preparation, delivery, and follow-through*.

Prepare the Feedback Before Sharing

Before sending a comment, ensure it is specific, actionable, and tied to context.

For example, instead of “Consider error handling,” write:

> In src/api/user.service.ts, the getUserById function returns null on failure but does not log or propagate the error. Add a logger.error call before return null, and consider re-throwing the error after logging. This will help catch missing users during onboarding.

This version includes:

Choose the Right Medium for the Message

Feedback is not one-size-fits-all. Match the medium to the depth and urgency of the message.

MediumBest for
GitHub PR commentCode-level feedback, with links to files, lines, and builds
Slack messageQuick, contextual, collaborative feedback
EmailDetailed, multi-part feedback with references, history, and expectations
In-person 1:1Deep, reflective feedback on growth, behavior, or project direction

For code reviews, use GitHub-style PR comments with inline code suggestions. When commenting on a file, use the native file diff view to pin feedback directly to code. Clicking a comment should jump to the line, and the comment should show the surrounding code context.

When reviewing a complex change, add a summary comment at the top of the PR with:

Example:

## Summary: Add user session persistence via Redis

This PR adds Redis-backed session storage to the API service. Sessions are now persisted across server restarts and scaled horizontally.

✅ Implemented session middleware with Redis integration  
✅ Added session cleanup task (runs every 5 minutes)  
✅ Added `session:ttl` config key in `config/app.json`  
✅ Tests pass in CI (see logs)

### Checklist
- [x] All tests pass  
- [x] Documentation updated  
- [ ] Performance benchmarks added  
- [ ] Monitoring alerts configured  

### Related
- #142: Session lifetime requirements  
- docs/session-handling.md

This structure gives the reader immediate context and a clear path forward.

Structure Feedback for Memory and Action

Feedback that sticks must be scorable and repeatable. Use a consistent format so engineers can internalize it.

A proven structure is the "What, Why, How" format:

> What: What change is needed? > Why: Why does it matter? > How: How should it be implemented?

Example:

> What: Move config/app.json to config/*.json and use environment-specific overrides. > Why: Currently, app.json is duplicated across environments, leading to configuration drift. With this change, we can have config/development.json, config/production.json, and config/staging.json, each overriding the base. > How: Use fs.readJsonSync('config/app.json') to load base config, then merge in config/${env}.json using deepmerge. Add NODE_ENV check in server.js.

This format makes feedback self-contained. The engineer can act on it without additional conversation.

Deliver Feedback with Context and Evidence

Feedback without evidence is opinion. To make feedback credible, include logs, traces, and real data.

When reviewing a performance issue, include a trace of a request from a monitoring tool. For example:

{
  "traceId": "a5c3b1d2-8e4f-9a7b-1c6d-2e8f3a4b5c6d",
  "spans": [
    {
      "name": "GET /api/users",
      "duration": 124,
      "startTime": 1450,
      "tags": {
        "http.method": "GET",
        "http.status_code": 200,
        "user.id": "1234",
        "db.query.count": 3
      },
      "logs": [
        {
          "timestamp": 1500,
          "message": "Querying users from DB"
        },
        {
          "timestamp": 1580,
          "message": "Fetching user profiles (3 queries)"
        }
      ]
    }
  ]
}

In the feedback, link to the trace and write:

> The /api/users endpoint takes 124ms, but 60% of that time is spent fetching profiles. Consider caching user profiles in Redis, or batching the three profile queries into one. The trace shows three DB queries, each taking ~15ms, suggesting a bottleneck in the user profile service.

This connects the feedback directly to observable reality.

Follow Up on Feedback with Triggers and Reminders

Feedback that is not followed up becomes noise. Set up triggers to ensure action.

After sending feedback, assign the PR to the author and set a due date.

Use pull request templates to guide authors and reviewers. A standard template includes:

## Description
<!-- Describe the change in a few sentences -->

## Related Issues
<!-- Link to issues, tickets, or specs -->

## Implementation Notes
- [ ] Added tests
- [ ] Updated documentation
- [ ] Performance impact measured
- [ ] Configuration changes required

## Review Checklist
- [ ] Code style matches project standard
- [ ] All tests pass
- [ ] Documentation updated
- [ ] CI artifacts attached

This ensures reviewers don’t miss steps and authors know what to expect.

When feedback is given in a 1:1, record the session and share a summary within 48 hours. Use the same "What, Why, How" structure.

Example summary email:

> Subject: Follow-up: 1:1 on career growth — next steps > > What: You want to grow into a senior role over the next 6 months. > Why: You’ve shown strong technical depth but need more ownership and cross-team collaboration. > How: > - Lead one architecture review per quarter > - Mentor one junior engineer > - Write a decision record for a major design choice > - Share a talk at a team meetup > > Please update your career plan doc with these goals by Friday. I’ll check in at the next 1:1.

Handle Feedback That Fails

Even with good practices, feedback can silently fail. Recognize and act on common failure modes.

Failure Mode 1: Feedback is read but never acted on.

Example watch script to check for overdue feedback:

#!/bin/bash

# Run daily via cron

echo "Checking for overdue feedback..."
for pr in $(git log --since="7 days ago" --grep="feedback:" --format="%H"); do
  pr_url=$(git log -1 --format="%B" $pr | grep "https://github.com" | head -n1)
  pr_author=$(git log -1 --format="%an" $pr)
  pr_title=$(git log -1 --format="%s" $pr)

  # Check if feedback was given more than 5 days ago
  feedback_date=$(git log -1 --format="%ad" --date=short $pr)
  days_since_feedback=$(date -d "$feedback_date" +%s | awk -v today=$(date +%s) '{print (today - $1) / 86400}')

  if (( $(echo "$days_since_feedback > 5" | bc -l) )); then
    echo "Overdue feedback: $pr_title ($pr_url)"
    echo "Author: $pr_author"
    echo "Feedback given $feedback_date"
    echo "Send reminder to $pr_author"
  fi
done

Failure Mode 2: Feedback is misunderstood or misinterpreted.

Example:

> Before: > ``ts > function calculateTotal(items) { > let total = 0; > items.forEach(item => { > total += item.price * item.quantity; > }); > return total; > } > ` > > After: > `ts > function calculateTotal(items) { > const total = items.reduce((sum, item) => sum + (item.price * item.quantity), 0); > return total; > } > ` > > The reduce` version is more idiomatic and slightly faster. Use it in all price calculations.

Failure Mode 3: Feedback is ignored in favor of other priorities.

Each feedback item includes:

Use kubectl to query feedback status from a Kubernetes-based feedback tracker:

kubectl get feedbacks -o wide --show-labels

Example output:

NAME           STATUS     OWNER      DUE DATE     LABELS
user-auth-v2   in-progress  jen        2024-08-15   priority=p1,area=auth
api-pagination  done         alex       2024-07-20   priority=p0,area=api
cache-strategy  new         maria      2024-09-01   priority=p2,area=performance

Make Feedback a Continuous Practice

Feedback is not a one-off activity. Integrate it into routines.

Use a feedback log in a shared document. Each entry includes:

This creates a living record of team growth, decisions, and learning.

Feedback that engineers *actually hear* is not just delivered—it is anchored in context, structured for action, and followed up with care. It becomes part of how the team works, not just how it communicates.

This page was rewritten on 17 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.