Conventional Comments: A standardized approach for code review communication

December 28, 2025

angry dev

How much time does your team waste decoding the intent behind a review comment?

"You should refactor this." Is it blocking? A suggestion? A passing remark? The developer hesitates, the reviewer gets frustrated that their feedback is ignored. The MR drags on. The problem isn't technical: it's a communication problem.

Conventional Comments offers a simple solution: make the implicit explicit. A structured format that clarifies the intent, criticality, and context of each comment.

In this article: the methodology, before/after examples, and the metrics we observed after adoption by a development team.


Understanding the Problem

How the Merge Request Became Essential

To understand current challenges, a historical detour is in order.

1980s–2000s: the centralized era. With RCS then CVS, one file = one lock. Sequential work was the norm, reviews happened via emails and meetings. SVN improved things with atomic commits, but branches remained slow and painful. Result: no culture of systematic review.

2005: the Git revolution. Instant branches, 100% local work, intelligent merges. The paradigm shifted. Feature branches exploded, parallel work became massive. But with this freedom came a new risk: loss of code coherence.

2010+: the rise of platforms. GitHub, GitLab, Bitbucket introduced the Pull/Merge Request. Discussion in the code, decision history, automated CI, formal approvals. The MR became the mandatory gateway for any change. ‎

Key insight: The easier branches become to create, the more critical structured review becomes.

Today, teams collaborate asynchronously. Discussions in merge requests are the living documentation of technical decisions. Without face-to-face interaction, tone and intent are easily misinterpreted. Reviews also serve as a learning vector: onboarding juniors, challenging senior approaches.

The Communication Gap

Yet traditional review comments suffer from recurring patterns that sabotage their effectiveness:

Emotional friction: "This code won't work in production" without context generates anxiety, not collaboration. The developer becomes defensive.

Ambiguity on criticality: "Consider extracting this logic": blocking or optional? The developer wastes time on non-critical items, or ignores important feedback. Frustration on both sides.

Endless discussions: Without a clear framework, a simple question escalates into an endless thread. The MR stays blocked for days.

Lack of recognition: 12 critical comments, 0 praise. Good work goes unnoticed. Motivation erodes.

False consensus: To avoid conflict, some approve with a superficial "LGTM". Technical debt accumulates silently.


The Solution: Conventional Comments

Before:

"You should extract this logic"

After:

suggestion (non-blocking): Extract the validation logic

Instantly: it's a suggestion, it's not blocking. No more ambiguity.

Format

Each comment follows this structure:

<label> (decoration): <subject>

[optional discussion]

Element

Role

Example

label

Type of comment

suggestion

decoration

Modifies criticality (optional)

non-blocking

subject

The point raised

Extract the validation logic

discussion

Context, reasoning (optional)

Detailed explanation, links, etc.

Labels

The specification defines several labels. Here are the ones we use:

Label

Usage

Blocking

Example

praise

Highlight positive aspects

No

praise: Excellent error handling pattern

question

Understand a decision

No (awaits response)

question: Why async here?

suggestion

Propose an improvement

No (author decides)

suggestion: Use Zod for validation

issue

Necessary change

Yes (must be resolved)

issue: Memory leak in this listener

thought

Share an idea or reflection

No

thought: An Observer pattern would be relevant

nitpick

Trivial change

No

nitpick: Remove the console.log

todo

Small necessary and trivial task

Yes (must be resolved)

todo: Add email format validation

Decorations

Decorations adjust the criticality of a label:

Decoration

Meaning

Example

(non-blocking)

Merge can proceed, author decides

nitpick (non-blocking): Add JSDoc

(if-minor)

Fix unless effort is disproportionate

issue (if-minor): Switch to async


Concrete Examples

Let's revisit the problems identified above and see how Conventional Comments solves them.

Ambiguity on Criticality

const data = await fetchUser(userId);
if (!data) {
  throw new Error('User not found');
}

Before

"You should use a Result type instead of throw"

After

suggestion (non-blocking): Consider a Result type for error handling

With a Result<T, E>, this would avoid try/catch and make errors explicit
in the type system. Not necessary for this MR if the rest of the codebase
uses throw.

Reference: https://swan-io.github.io/boxed/result

→ The intent is clear: non-blocking suggestion, the developer decides.

Emotional Friction

const users = [/* ... */];
users.forEach(user => {
  sendEmail(user.email, template);
});

Before

"This code will explode in prod with 10,000 users. Not good at all!"

After

issue: Risk of email API overload with large volumes

With 10k users, this synchronous approach will timeout.

Suggestions:
- Use `p-limit` to limit concurrency (e.g., 10 parallel max)
- Delegate to a queue (AMQP) for async processing

Happy to help, I've already implemented this with p-limit.

→ The problem is articulated with solutions, not blame.

Judgment Disguised as Question

async function processOrders() {
  const orders = await fetchOrders();
  for (const order of orders) {
    await processPayment(order);
    await sendConfirmation(order);
  }
}

Before

"Why aren't you using Promise.all()? Do you even understand async in JS?"

After

question: Reason for sequential rather than parallel processing?

I'm wondering if there's a dependency between processPayment and sendConfirmation.
If they're independent, we could improve perf with `Promise.all()`.

If it's intentional (rate limit?), a comment would help document this.

→ Curiosity rather than judgment, open dialogue.

Lack of Recognition

Before

An MR receives 12 comments: 10 issues, 2 todos, 0 praise.

After

praise: Excellent architecture with the Repository pattern

The domain/infrastructure separation makes this code highly testable.
The interfaces are clear and strict typing prevents runtime errors.

praise: Comprehensive tests including edge-cases

The timeout and retry tests are particularly valuable.

issue: Potential memory leak in the WebSocket listener
[... other comments ...]

→ Balancing criticism and recognition maintains motivation.


Implementation and Measurement

Adopting Conventional Comments isn't enough: you need team rules and tracking to anchor the practice.

Team Rules

Rule

Why

Sincere praise mandatory

Identify positive aspects. Fake praise erodes trust.

Only comment author resolves

Prevents premature merges. Dev responds, reviewer validates and resolves.

Reference the fix commit

"Fixed in abc123" → reviewer verifies directly.

Document exceptions

Urgent merge? Create a ticket and mention it in the thread.

Example: notification after fix:

# Reviewer
issue: userId variable not validated

# Developer
Fixed in abc123: added Zod validation with z.string().uuid()

Example: documented exception:

suggestion (non-blocking): Refactor toward hexagonal architecture

@dev: Merging to unblock the release, ticket TECH-456 created.

Tracking Metrics

Three indicators to evaluate adoption:

Metric

Calculation

Target

Adoption rate

Conventional comments / Total

80%+ after 3 months

Praise ratio

Praise / (Issue + Nitpick)

Min 0.2 (1 per 5 critiques)

Resolution time

Merge date − Creation date

20-30% reduction

Expected evolution: Praise increasing, Issues decreasing, Questions stable.

Automation

Manual tracking is tedious. I created a CLI tool to automate collection from the GitLab API.

Example output

╔════════════════════════════════════════════════╗
║             ⏱  MR Resolution Time              ║
╚════════════════════════════════════════════════╝

    12d┤
    11d┤
    10d┤
     9d┤
     9d┤━━━━━━━┓
     8d┤       ┃
     7d┤       ┃
     6d┤       ┃
d    5d┤       ┃             ┏┓
a    5d┤       ┃             ┃┃         ┏━━┓                   ┏━━━━━┓
y    4d┤       ┃         ┏━┓ ┃┃         ┃  ┃        ┏━━━━━┓    ┃     ┃
s    3d┤       ┃   ┏━━━━━┛ ┃ ┃┗━━━━━━━━━┛  ┃        ┃     ┃    ┃     ┃     ┏━━━━┓
     2d┤       ┃  ┏┛       ┃ ┃             ┃        ┃     ┃    ┃     ┃     ┃    ┃
     2d┤       ┃  ┃        ┗━┛             ┗━━━┓    ┃     ┃ ┏┓ ┃     ┃     ┃    ┃
    19h┤       ┗━━┛                            ┗━━┓ ┃     ┗━┛┗━┛     ┗━━━━━┛    ┃
     0 ┤                                          ┗━┛                           ┗━
       └┬───────┬──┬┬─────┬─┬─┬┬─┬───────┬──┬───┬──┬─┬─────┬─┬┬─┬─────┬─┬──┬┬────┬▶
          11-10     11-1711-20     11-26  12-0112-04 12-0812-11 12-1512-18 12-22
                                     date (utc)
Curve smoothing by applying an Exponentially Weighted Moving Average (EWMA)

    6d┤
    6d┤━━━━━━━┓
    5d┤       ┃
    5d┤       ┃
d   4d┤       ┗━━┓
a   4d┤          ┃
y   4d┤          ┗━━━━━━━━┓ ┏━━┓       ┏━━┓
s   3d┤                   ┗━┛  ┗━━━━━━━┛  ┗━━━┓
    3d┤                                       ┃
    2d┤                                       ┗━━┓ ┏━━━━━┓    ┏━━━━━┓
    2d┤                                          ┗━┛     ┗━━┓ ┃     ┗━┓   ┏━━━━┓
    2d┤                                                     ┗━┛       ┗━━━┛    ┗━
    1d┤
   19h┤
    9h┤
    0 ┤
      └┬───────┬──┬┬─────┬─┬─┬┬─┬───────┬──┬───┬──┬─┬─────┬─┬┬─┬─────┬─┬──┬┬────┬▶
           11-10     11-1711-20     11-26  12-0112-04 12-0812-11 12-1512-18 12-22
                                          date (utc)
╔════════════════════════════════════════════════╗
║          💬 MR Comments Distribution           ║
╚════════════════════════════════════════════════╝
Global Statistics
─────────────────
┌─────────────────────┬────────┐
│ (index)             │ Value  │
├─────────────────────┼────────┤
│ Total MRs           │ 58     │
│ Total Comments      │ 966    │
│ Average Comments/MR │ 16.7   │
│ Min Comments/MR     │ 3      │
│ Max Comments/MR     │ 80     │
│ Median Comments/MR  │ 9.5    │
└─────────────────────┴────────┘
Evolution of the number of comments per MR over time (still applying EWMA to smooth the curve)

c  51 ┤
o  47 ┤
m  44 ┤━━━━━━━┓
m  41 ┤       ┃
e  37 ┤       ┃
n  34 ┤       ┗━━┓
t  30 ┤          ┃
s  27 ┤          ┗┓
/  24 ┤           ┗━━━━━━━┓
M  20 ┤                   ┗━┓
R  17 ┤                     ┗━━┓       ┏━━━━━━┓
   14 ┤                        ┗━━━━━━━┛      ┗━━┓ ┏━━━━━━━━━━━━━━━━━━━━━┓
   10 ┤                                          ┗━┛                     ┗━━━━━━━
    7 ┤
    3 ┤
    0 ┤
      └┬───────┬──┬┬─────┬─┬─┬┬─┬───────┬──┬───┬──┬─┬─────┬─┬┬─┬─────┬─┬──┬┬────┬▶
          11-10     11-1711-20     11-26  12-0112-04 12-0812-11 12-1512-18 12-22
                                date (utc)
╔════════════════════════════════════════════════╗
║       📋 Conventional Comments Analysis        ║
╚════════════════════════════════════════════════╝
Global Overview
───────────────
┌─────────────────────────┬─────────┐
│ (index)                 │ Value   │
├─────────────────────────┼─────────┤
│ Total Comments          │ 966     │
│ Conventional Comments   │ 736     │
│ Unconventional Comments │ 230     │
│ Adoption Rate           │ 76.2%   │
└─────────────────────────┴─────────┘
Label Distribution
──────────────────
┌────────────┬────────────┐
│ (index)    │ Percentage │
├────────────┼────────────┤
│ Praise     │ 1.4%       │
│ Question   │ 54.6%      │
│ Suggestion │ 14.9%      │
│ Issue      │ 21.3%      │
│ Nitpick    │ 7.9%       │
└────────────┴────────────┘
Praise Ratio
────────────
┌──────────────────────────────────┬────────┐
│ (index)                          │ Value  │
├──────────────────────────────────┼────────┤
│ Praise Count                     │ 10     │
│ Critique Count (issue + nitpick) │ 215    │
│ Ratio (praise/critique)          │ 4.7%   │
└──────────────────────────────────┴────────┘

Interpretation:

  • Adoption 76% → majority of the team uses the format

  • Praise ratio 4.7% → 10 praises for 215 critiques, room for improvement

  • Questions 54% → high ratio, may be explained by onboarding or skill-building context

ℹ️ Tip: Filter out bots (dependabot, rennovate, ...) to analyze only human reviews.


Challenges and Limitations

The method isn't without pitfalls. Some traps to avoid:

Empty Formalism

The label doesn't replace the explanation. issue: Badly named variable without context remains useless.

Always explain the "why": userData would be more explicit than data for the business context.

Generic Praise

praise: Nice fulfills the rule but undermines its spirit. Vague praise erodes trust.

Be specific: praise: Excellent use of the Builder pattern for the UserDTO

Non-blocking Abuse

If 90% of comments are (non-blocking), the review no longer adds value.

Dare to block when justified.

Initial Resistance

The format may seem bureaucratic at first.

Lead by example rather than impose. Visible benefits in others' reviews encourage adoption.


Conclusion

The problem was never technical: it's a communication problem. Conventional Comments doesn't reinvent the review, it makes the implicit explicit.

For developers: no more guessing whether a comment blocks the merge. For reviewers: a framework to structure feedback without seeming condescending. For teams: less friction, more learning.

It's not a silver bullet. The format doesn't replace empathy or judgment. But it's a concrete first step toward more effective and more human reviews.

To get started: try it on your next MR. A suggestion (non-blocking): or a sincere praise: . Observe the reaction.


Resources


This article is inspired by a real implementation of Conventional Comments in a fullstack development team. All examples are based on actual situations encountered, with identifying details modified.