Production engineering guide for engineering culture metrics covering patterns, implementation strategies, and operational best practices.
Engineering culture metrics track how effectively an engineering organisation collaborates, evolves, and sustains technical excellence. They measure the health of processes, practices, and mindsets—not just the output of engineering, but the culture that produces it. Use these metrics when diagnosing stagnation, onboarding new teams, or evaluating the impact of a new practice like code reviews or decision records.
A code review is not complete when a PR is merged. It is effective when it reduces defects, spreads knowledge, and improves design. To measure this, capture the following data points:
Use git log --since="2 weeks ago" --format="%ad %h %s" --date=short to extract PR creation timestamps. Correlate with pull request metadata from GitHub, GitLab, or Bitbucket via their public APIs. The average time from PR creation to first review should be under 12 hours.
A review is shallow if only one reviewer examines the PR. Measure this by counting the number of review comments per PR. A metric of ≥3 comments per review indicates meaningful engagement.
Track the average time from first comment to merge. A common failure is the "reviewer who never replies"—a reviewer adds comments but does not respond to follow-up questions. Use this query in PostgreSQL:
SELECT
pr.id,
COUNT(r.id) AS comment_count,
AVG(EXTRACT(EPOCH FROM (r.created_at - pr.created_at))) AS avg_time_to_first_comment,
AVG(EXTRACT(EPOCH FROM (pr.merged_at - r.created_at))) AS avg_time_from_first_comment_to_merge
FROM pull_requests pr
JOIN reviews r ON pr.id = r.pull_request_id
WHERE pr.created_at >= NOW() - INTERVAL '3 months'
GROUP BY pr.id
HAVING COUNT(r.id) > 0;
A high-quality review includes questions, suggestions, and clarifications. Extract these from comment bodies using regular expressions. A review is high quality if it includes at least one of:
Use grep -E "Why not|Consider adding|Can we simplify|Suggestion: refactor" on the review comment JSON output from the Git platform API.
Decision records are effective when they are written, found, and used. Track adoption through these signals:
Count all decision.md files (or DECISION-*.md) in the docs/decisions/ directory. Use find docs/decisions -name "DECISION-*.md" | wc -l and divide by the number of engineers.
Use git log --grep="Merge pull request" --oneline to detect when a decision was referenced in code. A decision is “used” if it appears in a commit message, PR description, or code comment with #DECISION-123.
git log --all --grep="#DECISION-123" --oneline
The time from DECISION-123 creation to first use should be under 48 hours.
A decision record should be cited in at least two other documents: a codebase README, an architecture document, or a team onboarding guide. Use grep -r "#DECISION-123" docs/ and verify links via linkchecker or curl to check link validity.
A decision is mature if it includes:
proposed, accepted, implemented, decommissioned)A common failure: the decision is written but never updated after implementation. Use git log --oneline --reverse docs/decisions/DECISION-123.md to detect when the status field was last updated.
Documentation is not a product—it is a practice. Measure its health through frequency, completeness, and discoverability.
Track how many components have a README.md, CONTRIBUTING.md, and DEPLOYMENT.md in the root of their repository.
find . -name "README.md" -exec sh -c '
for dir; do
if [ -f "$dir/CONTRIBUTING.md" ] && [ -f "$dir/DEPLOYMENT.md" ]; then
echo "$dir"
fi
done
' _ {} +
A team is documenting well if 90% of their repos have all three files.
Use find . -name "*.md" -exec stat -c "%y %n" {} + | sort -r to list all markdown files by last modification time. A documentation file is “stale” if it hasn’t been updated in the last 90 days.
A common failure: documentation is written once and never revised. Use git log --since="90 days ago" --name-only docs/ to identify which docs are actively maintained.
A documentation set is effective if internal links are followed. Use grep -r "\[.*\]\(.*\)" docs/ to extract all links and check for broken ones via curl --fail -I on each URL.
curl -I https://example.com/docs/quickstart | grep "HTTP/2 200"
A failure mode: a link points to docs/ but is not accessible at https://example.com/docs/.
Communication is the glue of engineering culture. Measure how well teams talk and write across the organisation.
Track two metrics:
Use grep -r "Agenda" docs/meetings/ to extract meeting agendas. A meeting is effective if the agenda is completed in 80% of its duration.
After a meeting, a summary should be published within 24 hours. Use find docs/meetings -name "*.md" -newermt "1 day ago" to check for timely summaries.
Measure how often emails are replied to within 24 hours. Use grep -r "Re:" mail/ and check the Date: header in each email.
A common failure: the reply is a single line with no context. Use grep -E "^Re:.*[A-Za-z]" mail/ to detect replies with subject lines that don’t include the original subject.
Track how many open issues in a project are in needs discussion, awaiting feedback, or review pending states. Use jira-cli search --jql "status = 'Needs Discussion' OR status = 'Awaiting Feedback'" to extract the backlog.
A failure mode: the team uses Jira but never updates the status field. Use psql -c "SELECT COUNT(*) FROM issues WHERE status = 'Needs Discussion' AND updated_at < NOW() - INTERVAL '1 week';" to detect stale issues.
Career ladders are not just documents—they are living guides. Measure their impact through usage and alignment.
Count the number of engineers who have a personal career-plan.md file that references the official ladder. Use find . -name "career-plan.md" -exec grep -l "Ladder Version" {} +.
A career plan is aligned if it includes:
Use grep -r "Next Step" docs/careers/ and verify that each step has a corresponding milestone.
Track how often engineers submit feedback on a ladder version. Use git log --grep="Feedback on Ladder" --oneline to detect feedback submissions.
A failure mode: the ladder is updated, but no one reviews the changes. Use git log --since="1 month ago" docs/careers/ladder.md to check for adoption of new versions.
The rhythm of engineering is revealed through the flow of work items through the system.
Measure the time from “started” to “done” for engineering tasks. Use jira-cli status --project ENG --from="last quarter" to extract all tasks, then calculate the average time between status = 'In Progress' and status = 'Done'.
Track how many tasks are in “In Progress” at the same time. Use psql -c "SELECT COUNT(*) FROM issues WHERE status = 'In Progress';" and correlate with the number of engineers.
A common failure: WIP exceeds team size. Use psql -c "SELECT COUNT(*) FROM issues WHERE status = 'In Progress' AND updated_at > NOW() - INTERVAL '1 hour';" to check for real-time WIP.
A task is blocked if it has a comment with “blocked” or “waiting on.” Use grep -r "blocked\|waiting on" issues/ to detect blocked tasks.
A failure mode: a task is blocked but no one responds. Use git log --since="2 weeks ago" --grep="blocked" --oneline to detect unattended blockers.
A review is complete only when a reviewer marks it “Approved” and the author merges. But many PRs are “approved” but never merged. Use git log --grep="Approved" --oneline and check for merged_at IS NULL in the database.
A decision is written but never cited. Use grep -r "DECISION-" docs/ and check for #DECISION-123 in code, PRs, and issues.
A file exists but is not linked from the project’s main README.md. Use grep -r "docs/.*\.md" README.md and verify that each file is referenced.
A meeting summary is incomplete if it lacks a list of action items. Use grep -r "Action:" docs/meetings/ and check for @assignee or #label.
A plan is created once and never updated. Use find docs/careers -name "*.md" -exec stat -c "%y %n" {} + and check for updates in the last 60 days.
A task is “started” but not actively worked on. Use git log --since="1 week ago" --author="[email protected]" --oneline to detect when work is interrupted.
Use standard tools to collect and report metrics. No platform-specific hooks, no vendor-locked formats.
Run git log --oneline --since="1 month ago" --grep="metric" to record metric updates.
Generate a daily report via curl -X POST https://metrics.example.com/report -d @metrics.json using a standard JSON format:
{
"date": "2024-03-15",
"metrics": [
{
"name": "avg_time_to_first_review",
"value": 7.2,
"unit": "hours"
},
{
"name": "avg_time_from_first_comment_to_merge",
"value": 18.5,
"unit": "hours"
},
{
"name": "decision_records_per_100_engineers",
"value": 14.3
}
]
}
Use jq to validate incoming metric data:
echo '{"date": "2024-03-15", "metrics": []}' | jq '.metrics |= . + [{"name": "new_metric", "value": 100}]'
Use psql -c "SELECT COUNT(*) FROM metrics WHERE date = CURRENT_DATE AND status = 'failed';" to detect when metric collection fails.
When a metric exceeds a threshold, send an alert via curl to a Slack webhook:
curl -X POST https://hooks.slack.com/services/ABC123/DEF456 -d '{
"text": "Cycle time exceeded 48 hours for 3 consecutive days",
"attachments": [
{
"title": "Cycle Time Report",
"text": "Average cycle time: 52.3 hours"
}
]
}'
The pattern is consistent: collect data via standard tools, store it in a common format, and validate it with simple, repeatable commands. The culture emerges not from a tool, but from the habits of reading and acting on these metrics.
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.
We use cookies for analytics (Google Analytics) and advertising (Google AdSense) to improve your experience and support free content. Privacy Policy