Module 7: Strategy To Roadmap

Saying NO at the strategic level

Description

product-thinking-for-engineers-guide (module 7) already taught you to say no tactically: when the quarter's capacity runs out, you have to cut the backlog somewhere, and that lesson taught you to do it with opportunity cost, not with whoever shouts loudest. This lesson teaches a different, earlier NO: the one said before capacity is even the problem, because the bet —no matter how much capacity is left over— doesn't belong to the game the strategy chose to play. They're two different conversations, and confusing them is one of the most costly mistakes in communicating a correct decision poorly.

Connection to the module. Lessons 3, 4, and 5 built the criterion and applied it to Mercado's complete backlog. This lesson stays with the three bets that criterion rejected —lowestPriceMatch, fasterCheckout, improvedSearch— and asks something the code never answered: how do you explain to a real team why "no" is the right answer, when two of those three bets had the best RICE in the whole backlog?

An everyday analogy: the rejection letter from a magazine with an editorial line

A magazine with a clear editorial line —say, a science magazine for a general audience— constantly receives well-written, well-researched articles, on topics that would undoubtedly interest a lot of people, but that simply don't fit that line: a political opinion column, a restaurant review, a sports feature. A good editor doesn't respond "we don't have space this month" when the truth is "this isn't what we publish" — that excuse, though more comfortable to give, leaves the author thinking they can try again next month, and leaves the whole editorial team without a clear criterion for the next similar decision. The editor who does it well says, precisely: "this article is well written, but it doesn't fit our editorial line, which is X" — a specific reason, not a convenient excuse.

Saying no at the strategic level is exactly that well-written rejection letter. The bet can be objectively good —like fasterCheckout, with the second-best RICE in the backlog— and still not fit Mercado's editorial line. The difference between a good NO and a bad one isn't whether it's said or not —the filter already decided that—, it's whether the reason accompanying the NO is the real reason, or an excuse that's easier to swallow in the moment.

Worked example: the NO memo, with the exact reason for each rejection

We extend strategicFilter with a small function, noReason, that turns the filter's result into the exact sentence explaining why a rejected bet doesn't enter the roadmap — distinguishing, precisely, between "competes on something we rejected" and "doesn't reinforce anything we chose."

function riceScore({ reach, impact, confidence, effort }) {
  return (reach * impact * confidence) / effort;
}

function strategicFilter(backlog, strategy) {
  return backlog.map((bet) => {
    const reinforces = bet.servesDimensions.filter((d) => strategy.winOn.includes(d));
    const conflicts = bet.servesDimensions.filter((d) => strategy.avoid.includes(d));
    return {
      feature: bet.feature,
      servesDimensions: bet.servesDimensions,
      reinforces,
      conflicts,
      inStrategy: reinforces.length > 0 && conflicts.length === 0,
      riceScore: Number(riceScore(bet.rice).toFixed(2)),
    };
  });
}

// Pedagogical model: turns strategicFilter's result into the written
// reason for the NO -- distinguishes "competes on a dimension we
// rejected" (conflicts) from "doesn't reinforce any dimension we bet
// on" (neutral).
function noReason(bet) {
  if (bet.conflicts.length > 0) {
    return 'competes on ' + bet.conflicts.join(', ') + ', the dimension the strategy decided NOT to fight on';
  }
  return 'doesn\'t reinforce any dimension where the strategy chose to win (' + bet.servesDimensions.join(', ') + ' falls outside winOn)';
}

const mercadoStrategy = { winOn: ['curatedDiscovery', 'sellerTrust'], avoid: ['price'] };

const backlog = [
  { feature: 'fasterCheckout', servesDimensions: ['convenience'], rice: { reach: 8000, impact: 2, confidence: 0.8, effort: 2 } },
  { feature: 'recommendations', servesDimensions: ['curatedDiscovery'], rice: { reach: 5000, impact: 1, confidence: 0.5, effort: 3 } },
  { feature: 'sellerTools', servesDimensions: ['sellerTrust'], rice: { reach: 1200, impact: 2, confidence: 0.8, effort: 2 } },
  { feature: 'reviews', servesDimensions: ['sellerTrust'], rice: { reach: 6000, impact: 0.5, confidence: 0.8, effort: 1 } },
  { feature: 'improvedSearch', servesDimensions: ['catalogBreadth'], rice: { reach: 9000, impact: 1, confidence: 0.5, effort: 3 } },
  { feature: 'lowestPriceMatch', servesDimensions: ['price'], rice: { reach: 9500, impact: 3, confidence: 0.8, effort: 3 } },
];

const filtered = strategicFilter(backlog, mercadoStrategy).sort((a, b) => b.riceScore - a.riceScore);
const rejected = filtered.filter((b) => !b.inStrategy);

console.log('=== The NO memo: each rejected bet, with its exact reason ===\n');
rejected.forEach((b) => {
  console.log('  ' + b.feature + ' (riceScore=' + b.riceScore + '): ' + noReason(b));
});

What to expect. Running the file with Node produces exactly this output:

=== The NO memo: each rejected bet, with its exact reason ===

  lowestPriceMatch (riceScore=7600): competes on price, the dimension the strategy decided NOT to fight on
  fasterCheckout (riceScore=6400): doesn't reinforce any dimension where the strategy chose to win (convenience falls outside winOn)
  improvedSearch (riceScore=1500): doesn't reinforce any dimension where the strategy chose to win (catalogBreadth falls outside winOn)

Every line of this memo is a well-written rejection letter, not an excuse. lowestPriceMatch isn't rejected with "there's no time this quarter" — it's rejected with the exact reason: it competes on the dimension Mercado decided not to fight on, and that decision has been documented since module 2. fasterCheckout isn't rejected with "it's not a priority right now" — it's rejected because, in all honesty, it doesn't reinforce any of the dimensions where Mercado chose to win. The difference between these two sentences and a generic "not now" is huge for whoever receives them: a "not now" invites trying again next quarter with the same argument; an explicit strategic reason tells whoever proposed the bet, precisely, what would have to change —not on the calendar, but in the strategy itself— for that bet to ever belong.

Deep dive: why "there's no time" is the most dangerous excuse

Of the two ways to say no —"it doesn't fit the strategy" or "there's no capacity this quarter"— the second seems kinder in the moment, but it's the more dangerous one over the medium term, for a very concrete reason: it implies the bet is going to get built, just later. If lowestPriceMatch gets rejected with "there's no room in the quarter," it stays on the backlog, waiting for the next prioritization cycle, where its riceScore of 7600 —the highest of all— is going to put it back at the top of the list, with nobody remembering, the second time, why it was rejected the first. The capacity excuse doesn't close the conversation — it postpones it, and reopens it at exactly the worst moment: when the strategic filter is no longer running, only the RICE ranking.

Stating the real strategic reason, instead, takes the bet out of the capacity conversation entirely. It's not that lowestPriceMatch "lost" to other bets over limited resources — it's that it never competed for those resources, because it doesn't belong to the game. That distinction, well communicated, avoids the exact cycle Melissa Perri describes in Escaping the Build Trap: teams that revisit the same popular bet quarter after quarter, with nobody documenting why it was rejected the previous time, spending the same evaluation effort over and over.

Common mistakes

Not saying NO to the popular but out-of-strategy bet. What happens: a bet with high RICE and a lot of team enthusiasm —like lowestPriceMatch or fasterCheckout— gets left "under review" indefinitely, with no explicit rejection, because directly saying no to something popular generates uncomfortable friction. Why it happens: it's socially easier to leave a decision ambiguous than to communicate a clear rejection of something several team members genuinely defend with enthusiasm and real data. How to spot it: if a bet rejected by strategicFilter keeps showing up, quarter after quarter, on the "candidates to evaluate" list without anyone having formally closed it, that's this exact mistake's pattern. How to fix it: use this lesson's memo as a template — every rejected bet needs a written, communicated reason, not a silence that, over time, gets interpreted as "still undecided."

Saying no without giving the strategic reason, letting it sound like a whim. What happens: the rejection gets communicated with no explicit reason —"we decided not to do this"— letting whoever proposed the bet assume it was an arbitrary decision, personal taste, or internal politics. Why it happens: articulating the full strategic reason takes more effort than simply communicating the verdict, and under time pressure, the verdict feels sufficient on its own. How to spot it: if someone asks "why not?" after a rejection and the answer includes no reference to the strategy —winOn dimensions, avoid, or Mercado's competitive position—, the rejection wasn't communicated, only announced. How to fix it: adopt this lesson's noReason structure in any real conversation: name the specific dimension in conflict or the dimension that isn't reinforced, not a generic judgment of "it's not right for us right now."

Using "we don't have time" when the real reason is "it doesn't belong." What happens: to avoid the strategic conversation —potentially longer and harder to defend with hard data— the team justifies the rejection with the quarter's capacity constraint, even though the real reason is that the bet fell out in the strategic filter, not in the capacity cut. Why it happens: the capacity constraint is an objective, easy-to-verify fact (available effort minus committed effort), while strategic belonging requires a more qualitative judgment someone could question. How to spot it: for any rejection communicated as "lack of time," ask whether that bet would have passed strategicFilter in the first place — if the answer is no, the real reason was never capacity. How to fix it: always separate the two conversations, as this module does against product-thinking-for-engineers-guide's module 7: first, does it belong to the strategy? — if not, the conversation ends there, with no need to talk about capacity. Only among the ones that do belong does it make sense to discuss whether there's time for all of them.

Exercises

Exercise 1 — Write the complete memo yourself. Using noReason as a template, write the rejection reason, in one sentence, for a hypothetical bet socialSharingBadges with servesDimensions: ['convenience'], against Mercado's strategy.

See solution

"socialSharingBadges doesn't reinforce any dimension where the strategy chose to win (convenience falls outside winOn)." It follows exactly the same pattern as fasterCheckout and improvedSearch in this lesson's example: it doesn't compete on price (no conflicts), but it also doesn't contribute to curatedDiscovery or sellerTrust — it's a neutral bet, reasonable in the abstract, but with no place on this quarter's roadmap under the current strategy.

Exercise 2 — Distinguish the strategic NO from the tactical NO. A colleague rejects sellerTools saying "there's no time this quarter, we already committed all our capacity to reviews and recommendations." Is this a strategic or tactical rejection? Would the answer change if they'd instead said "this doesn't fit our bet on seller trust"?

See solution

The first rejection is tactical, not strategic: sellerTools did pass strategicFilter (it reinforces sellerTrust, with no conflicts) — the problem isn't belonging, it's the quarter's limited capacity, exactly the kind of decision product-thinking-for-engineers-guide (module 7) teaches you to resolve with opportunity cost, not with this module. The second hypothetical rejection (that sellerTools "doesn't fit seller trust") would be false and confusing, because sellerTools precisely reinforces that dimension — mixing the two conversations here would create a contradiction: rejecting a bet by claiming it doesn't serve the same dimension it actually does serve, instead of honestly saying the reason is capacity, not belonging.

Exercise 3 — Draft the memo for the founding team. Using this lesson's three worked-example rejections, write a paragraph addressed to Mercado's founding team, explaining why the quarter's roadmap doesn't include lowestPriceMatch or fasterCheckout, despite having the two best riceScore values in the whole backlog.

See solution

A sample answer: "Our backlog this quarter includes six candidate bets. Two of them —lowestPriceMatch and fasterCheckout— individually have the best expected performance by RICE of the whole set. We're not going to build them this quarter, and the reason isn't capacity: it's that neither one belongs to the strategy we chose. lowestPriceMatch competes directly on price, the dimension we explicitly decided not to fight on since module 2 of our strategy, because no player our size beats a generic megastore on scale there. fasterCheckout, while it doesn't compete on anything we've rejected, also doesn't reinforce curated discovery or seller trust —the two dimensions where we did choose to bet heavily. Instead, this quarter we're building reviews, sellerTools, and recommendations: three bets with lower individual RICE, but that together deepen exactly those two dimensions, also reinforcing the seller-network and purchase-data moats we identified in module 6. It's not that we're ignoring efficiency — it's that efficiency, alone, doesn't answer whether we're playing the right game."

Summary and next step

This lesson took the three bets rejected by the strategic filter and gave them an explicit, written reason, distinct from an awkward silence or a capacity excuse — noReason distinguished "competes on what we rejected" (lowestPriceMatch) from "doesn't reinforce what we chose" (fasterCheckout, improvedSearch). You also saw why the "there's no time" excuse is the more dangerous of the two ways to say no: it leaves the door open for the same popular bet to come back, with no memory, in the next prioritization cycle.

Before moving on you should be able to: distinguish a strategic rejection from a tactical one in a real conversation, and write the exact reason for any rejection without resorting to a capacity excuse when the real reason is belonging.

Lesson 7 closes the full circle: it takes the bets that did pass the filter and connects them, explicitly, to the RICE machinery you already know from product-thinking-for-engineers-guide — the exact bridge between this module and the roadmap's next step.

Resources

  • Melissa Perri, Escaping the Build Traporeilly.com/library/view/escaping-the-build/9781491973767. Perri documents, with real cases, the cost of teams that never formally close out a rejected idea — the same idea comes back, quarter after quarter, consuming evaluation time with nobody remembering why it was already dismissed before. In English.
  • Marty Cagan (Silicon Valley Product Group), "Product Strategy" — svpg.com/product-strategy-overview. Cagan argues that much of a product strategy's value lies precisely in enabling confident no's to objectively good ideas — this lesson's central argument. In English.
  • Roger Martin, "Decoding the Strategy Choice Cascade" — rogermartin.medium.com/decoding-the-strategy-choice-cascade-475d40555eb1. Martin insists that the cascade's choices must be explicit and communicable, not implicit — a NO nobody can explain with the strategy's exact words isn't, yet, a real choice. In English.