Every prioritization framework turns a messy backlog into a ranked list. That's the appeal, and it's also the danger. A ranked list looks objective, even when it rests on numbers someone typed into a spreadsheet five minutes before the planning meeting.

If you're a tech lead or engineer, you've probably sat through that meeting. Someone shares a sheet, the top three items get committed for the quarter, and nobody asks how much the order depends on the formula or the weights. This post compares the three most common scoring methods (RICE, ICE and weighted scoring), shows where each one misleads, and then runs all three on the same backlog in about 50 lines of Python, so you can watch them disagree.

About the numbers: every backlog item, score and weight below is made-up example data for a fictional invoicing app. They're picked to make the arithmetic easy to follow, not taken from any real product.

RICE

Formula: Reach × Impact × Confidence ÷ Effort

  • Reach: how many people or accounts the item affects in a set period (for example, users per quarter). Use real units.
  • Impact: how much it moves the needle for each person reached, usually on a fixed scale: 3 (massive), 2 (high), 1 (medium), 0.5 (low), 0.25 (minimal).
  • Confidence: how sure you are about the other estimates, as a percentage.
  • Effort: total work, usually in person-months.

Good for: comparing items with very different audiences, and forcing an honest conversation about reach and effort in real units. Engineers tend to like RICE because effort sits in the denominator where everyone can see it.

Where it misleads: reach dominates. A small improvement to a high-traffic page can outscore a major fix for your most valuable segment. Impact is still a judgment call, so the scale only helps if the team agrees what "2" means. Write a one-line guide for each level and keep it next to the scores.

ICE

Formula: Impact × Confidence × Ease, each scored 1–10. Some teams average the three instead of multiplying.

Good for: speed. You can triage a long list of growth experiments or small ideas in one meeting.

Where it misleads: all three inputs are subjective, and 1–10 scales drift from person to person. One person's 7 is another's 5. Multiplying exaggerates the gaps, while averaging smooths them out, so pick one and stick with it. ICE also has no reach term, so it can't tell "big for a few" from "small for many" unless you build that into Impact.

Weighted scoring

Formula: choose criteria (for example customer value, strategic fit, effort, risk), give each a weight, score each item on each criterion (say 1–5), and sum weight × score.

Two details matter, and both are classic bugs:

  1. Direction. Some criteria are "higher is better" (value) and some are "lower is better" (effort, risk). Lower-is-better criteria have to be inverted before summing, or a high-effort item gets rewarded. This is one of the most common silent bugs in homemade scoring sheets. No error, just a wrong answer.
  2. Normalization. Normalize the weights so they total 100%, and convert scores to a common 0–1 range, so the final number is comparable (for example, 0–100) and adding a criterion doesn't silently inflate everything.

Good for: decisions that involve strategy and trade-offs your team wants to make explicit, like a quarterly roadmap.

Where it misleads: the weights are the decision. Whoever sets them sets the outcome, and weights chosen after scoring tend to be reverse-engineered to protect a favorite. Agree on criteria and weights before anyone scores an item.

The example backlog

Three fictional items for a made-up invoicing app:

  • A: Bulk invoice export. Broad but modest value.
  • B: Late-payment reminders. High value for the customers who need it, cheap to build, but less certain.
  • C: Multi-currency support. Wide reach, strategically important, expensive.

Here are the inputs (all example data):

Item Reach/qtr Impact Conf. Effort (pm) ICE: I / C / E Value Fit Effort (1–5)
A 2,000 1 80% 2 6 / 8 / 6 3 4 3
B 500 3 50% 1 9 / 5 / 8 5 3 2
C 5,000 0.5 100% 4 4 / 9 / 4 2 5 4

For weighted scoring the criteria are customer value 40%, strategic fit 30% and effort 30% (lower is better).

Score it in Python

Spreadsheets hide formulas in cells. A short script makes every assumption visible and diffable. Save this as score_backlog.py (standard library only, Python 3.8+):

# score_backlog.py -- RICE, ICE and weighted scoring on one backlog. # All numbers are made-up example data.  backlog = { "A: Bulk invoice export": dict( reach=2000, impact=1, confidence=0.8, effort=2, # RICE inputs  ice_impact=6, ice_conf=8, ease=6, # ICE inputs (1-10)  value=3, fit=4, cost=3, # weighted inputs (1-5)  ), "B: Late-payment reminders": dict( reach=500, impact=3, confidence=0.5, effort=1, ice_impact=9, ice_conf=5, ease=8, value=5, fit=3, cost=2, ), "C: Multi-currency support": dict( reach=5000, impact=0.5, confidence=1.0, effort=4, ice_impact=4, ice_conf=9, ease=4, value=2, fit=5, cost=4, ), } def rice(i): return i["reach"] * i["impact"] * i["confidence"] / i["effort"] def ice(i): return i["ice_impact"] * i["ice_conf"] * i["ease"] # criterion -> (weight, higher_is_better) CRITERIA = {"value": (0.4, True), "fit": (0.3, True), "cost": (0.3, False)} def weighted(i, criteria=CRITERIA, lo=1, hi=5): total_w = sum(w for w, _ in criteria.values()) score = 0.0 for name, (w, higher_is_better) in criteria.items(): x = (i[name] - lo) / (hi - lo) # scale 1-5 to 0-1  if not higher_is_better: x = 1 - x # invert "lower is better"  score += (w / total_w) * x # renormalize weights to 100%  return round(100 * score, 1) def ranking(fn, **kw): scores = {k: fn(v, **kw) for k, v in backlog.items()} return sorted(scores.items(), key=lambda kv: kv[1], reverse=True) if __name__ == "__main__": for label, fn in [("RICE", rice), ("ICE", ice), ("Weighted", weighted)]: ranked = ranking(fn) print(f"{label:9}", " > ".join(f"{k[0]} ({s:g})" for k, s in ranked)) 

Run it:

$ python3 score_backlog.py RICE A (800) > B (750) > C (625) ICE B (360) > A (288) > C (144) Weighted B (77.5) > A (57.5) > C (47.5) 

Same backlog, same team, and two different winners. RICE puts A first. ICE and weighted scoring put B first. All three agree C comes last.

Note the line x = 1 - x. Delete it and rerun: C's weighted score jumps from 47.5 to 62.5, tying B for first place, and A falls to last, because the most expensive item is now being rewarded for its cost. That's the direction bug from earlier, and it's exactly the kind of thing that hides in a spreadsheet cell nobody reviews.

What the disagreement tells you

The tempting move is to average the ranks and call it a day. Don't. That hides the most useful information on the page: why the methods disagree.

Here the answer is reach versus intensity. RICE rewards A's larger audience (2,000 users against B's 500). ICE and weighted scoring reward B's high value and low effort, and neither gives reach its own term. So the real question for the meeting isn't "A or B?" It's "Do we care more about how many customers this touches, or how much it matters to the ones it touches?" That's a strategy question. It deserves an open discussion instead of being settled by whichever spreadsheet someone brought.

It's also worth checking how close the RICE call actually is. A beats B by 800 to 750. Bump B's confidence from 50% to 60% and B scores 500 × 3 × 0.6 ÷ 1 = 900 and takes the lead. When a single input moving one notch flips the order, the ranking isn't telling you much, and the useful next step is to go get evidence for that input (a quick customer survey, a usage query) rather than argue about the formula.

Stress-test the weights

Before you present a weighted-scoring result, check whether it depends on the weights. Raise and lower each criterion's weight by 50%, renormalize, re-rank, and record each item's best and worst rank. Save this as sensitivity.py next to the first file:

# sensitivity.py -- does the weighted ranking survive +/-50% weight changes? from score_backlog import backlog, weighted, ranking, CRITERIA best, worst = {}, {} for name in CRITERIA: for factor in (0.5, 1.5): # -50% and +50%  crit = dict(CRITERIA) w, higher_is_better = crit[name] crit[name] = (w * factor, higher_is_better) ranked = ranking(weighted, criteria=crit) print(f"{name:5} x{factor}:", " > ".join(f"{k[0]} {s}" for k, s in ranked)) for pos, (k, _) in enumerate(ranked, start=1): best[k] = min(best.get(k, len(backlog)), pos) worst[k] = max(worst.get(k, 1), pos) for k in backlog: print(f"{k[0]}: best rank {best[k]}, worst rank {worst[k]}") 

Output:

$ python3 sensitivity.py value x0.5: B 71.9 > A 59.4 > C 53.1 value x1.5: B 81.2 > A 56.2 > C 43.7 fit x0.5: B 82.4 > A 54.4 > C 38.2 fit x1.5: B 73.9 > A 59.8 > C 54.3 cost x0.5: B 77.9 > A 58.8 > C 51.5 cost x1.5: B 77.2 > A 56.5 > C 44.6 A: best rank 2, worst rank 2 B: best rank 1, worst rank 1 C: best rank 3, worst rank 3 

B stays first in all six scenarios, and A stays ahead of C. The A–C gap does narrow to about five points when strategic fit is weighted 50% higher, which is worth knowing if someone argues for a strategy-heavy quarter.

How to read results like these:

  • Stable items (rank barely moves): stop debating the weights for these.
  • Sensitive items (rank swings): the decision depends on one criterion. Debate that criterion directly instead of the whole list.

This turns the classic "your weights are wrong" argument into a narrower question you can actually answer. And since the scores now live in a file, you can put them in the repo next to the roadmap doc and review changes to weights the same way you'd review a config change.

So which should you use?

Situation Use
Triage a long list of small ideas or experiments quickly ICE
Compare items with very different audiences and costs RICE
Make strategic trade-offs explicit for a roadmap review Weighted scoring
A high-stakes or contested decision Two methods plus a sensitivity check

Whichever you use, a few rules hold across all of them:

  • Write a scale guide before scoring.
  • Agree on weights before scoring.
  • Score as a group, or have people score independently and then compare.
  • Treat disagreements between methods as the agenda, not noise.
  • Remember that the output is an input to the decision, not the decision itself.

If you'd rather not maintain the script

Not everyone in the planning meeting wants to run Python. We packaged the same logic into the PM Prioritization Calculators workbook ($12, Google Sheets and Excel). It runs RICE, ICE, weighted scoring with "lower is better" criteria, a weight-sensitivity tab and bottoms-up opportunity sizing on one backlog, then flags items where the methods disagree: PM Prioritization Calculators.

Disclosure: we make and sell that workbook. You don't need it for anything in this article. The two scripts above will do the same job.

A PM-focused version of this guide first appeared on the AI Spec Kit Substack.

Which framework does your team use, and has it ever picked a winner everyone quietly disagreed with? We'd like to hear how you settled it.

This article was written with the help of AI tools, then reviewed and edited before publishing.