界面已本地化;技能介绍与说明文档按所选语言由 AI 自动翻译,代码、命令、路径和专业术语保留原文,以原作者文档为准。
探索技能
数据与研究 · SKILL.md

engineering-tradeoffs

engineering-tradeoffs

【数据与研究】Evaluates competing engineering options using weighted decision matrices, reversibility analysis, and multi-criteria tradeoff frameworks to make defensible technical decisions under constraints.

独立 GitHub 快照 · 自动分类 · 以原作者文档为准

技能说明

GitHub

name: engineering-tradeoffs description: Evaluates competing engineering options using weighted decision matrices, reversibility analysis, and multi-criteria tradeoff frameworks to make defensible technical decisions under constraints. license: MIT compatibility: opencode metadata: version: "1.0.0" domain: coding triggers: engineering tradeoffs, decision making under constraints, build vs buy, speed vs quality, technology selection, weighted decision matrix, tradeoff analysis, two-way door decisions speed vs quality archetypes:

  • orchestration anti_triggers:
  • brainstorming
  • vague ideation
  • code golf
  • over-engineering response_profile: verbosity: medium directive_strength: high abstraction_level: tactical role: orchestration scope: orchestration output-format: analysis content-types:
  • guidance
  • examples
  • do-dont
  • diagrams related-skills: architecture-decision-records, design-pattern-selection, engineering-principles, technical-debt-management

Engineering Tradeoff Analysis

Senior engineer facilitating structured tradeoff decisions when requirements conflict and no option is perfect. This skill makes the model act as a disciplined decision analyst — surfacing hidden assumptions, quantifying competing priorities, and producing recommendations with explicit reasoning that stakeholders can challenge or endorse.

TL;DR Checklist

  • Write the conflict explicitly: "We want X but X requires A while Y requires B"
  • Classify all requirements: Non-negotiable → Strong Preference → Nice-to-have
  • Classify decision reversibility: Two-way door (act fast) vs One-way door (deep analysis)
  • Define success criteria BEFORE generating or evaluating any options
  • Generate at least 3 distinct options — never present a binary choice
  • Evaluate using weighted decision matrix with transparent scoring
  • Make a call and document the reasoning, not just the outcome

When to Use

Use this skill when:

  • The team faces a technical decision where every option has a meaningful downside
  • Requirements conflict (e.g., speed of delivery vs. long-term maintainability)
  • Evaluating build vs. buy decisions for infrastructure or libraries
  • Selecting technology stack, database engine, or messaging framework
  • Deciding whether to refactor now versus shipping and refactoring later
  • Choosing between architectural patterns (microservices vs. modular monolith, SQL vs. NoSQL)
  • Balancing correctness, performance, security, and development velocity

When NOT to Use

Avoid this skill for:

  • Trivial decisions — picking variable names, function signatures, or styling choices do not warrant tradeoff analysis
  • Post-decision documentation — use architecture-decision-records to document decisions that have already been made
  • Pattern selection — use design-pattern-selection when you know the pattern and need implementation guidance
  • Clear optimal choices — if one option clearly dominates on all criteria, skip analysis and proceed
  • Crisis-mode incident response — prioritize resolution over structured decision frameworks

Core Workflow

Step 1: Make the Conflict Explicit

Write out the tension in this exact form:

"We want [goal] but achieving it requires [option A's cost/benefit] while [option B's cost/benefit]."

Do not skip this step. Vague conflicts produce vague decisions. Examples:

  • "We want fast feature delivery but Rails development velocity is high while Go type safety reduces long-term bugs"
  • "We want eventual consistency for user feeds but PostgreSQL offers data integrity while MongoDB offers flexible schema evolution"
  • "We want to reduce vendor lock-in risk but custom-built payment systems cost more upfront than using Stripe"

Checkpoint: Can a stakeholder read this statement and understand exactly what is being debated? If not, rewrite it.


Step 2: Classify Requirements

Not all requirements carry equal weight. Categorize every requirement into one of three tiers:

TierDescriptionExamples
Non-negotiableMust be satisfied; deal-breaker if not metRegulatory compliance (GDPR, PCI-DSS), security baseline, hard SLA commitments
Strong PreferenceHighly desirable; strong penalty if unmetTeam's existing expertise, time-to-market < 3 months, sub-100ms latency target
Nice-to-haveDesirable but acceptable to defer or compromise onPreferred language, nice API ergonomics, future scalability beyond current needs

For each requirement, assign a weight from 1.0 (nice-to-have) to 3.0 (non-negotiable). This feeds directly into the decision matrix.

Checkpoint: Verify that at least one requirement is classified as Non-negotiable. If not, revisit with stakeholders.


Step 3: Classify Decision Reversibility

Apply Bezos's two-way door framework to determine analysis depth and urgency:

Two-Way Door (Reversible)        One-Way Door (Irreversible)
┌─────────────────────┐         ┌──────────────────────────┐
│ • Can undo later    │         │ • Difficult or costly to │
│ • Low permanence    │         │   reverse                │
│ • Fast decisions OK │         │ • Requires deep analysis │
│ • Act fast, iterate │         │ • Build consensus first  │
│ • Example: UI theme │         │ • Example: choosing DB   │
│   change, API route │         │   engine, data migration │
└─────────────────────┘         └──────────────────────────┘
  • Two-way door decisions: Move quickly (hours to days). Document reasoning lightly. Iterate after shipping.
  • One-way door decisions: Take time (weeks). Involve more stakeholders. Require detailed analysis with weighted scoring.

Checkpoint: Have you explicitly labeled the decision type? This determines how much effort is appropriate for analysis.


Step 4: Define Success Criteria BEFORE Evaluating Options

Before looking at any specific option, write down what success looks like. This prevents anchoring bias — the tendency to evaluate options against a preconceived favorite.

Success criteria should cover all three dimensions from the evaluation framework:

Technical: Correctness, Performance, Reliability, Scalability, Security Organizational: Team skill fit, Time to value, Operational burden, Vendor lock-in risk Strategic: Reversibility, Strategic alignment, Competitive differentiation

Write 3–7 success criteria. Each will become a column in your decision matrix.

Checkpoint: Would two independent engineers agree on these criteria? If not, the criteria need more objectivity.


Step 5: Generate at Least Three Options

Never present a binary choice (Option A vs. Option B). Binary framing is a cognitive bias that hides superior alternatives. Generate three archetypes:

ArchetypeDescriptionPurpose
Minimal ChangeIncremental improvement over current stateBaseline — shows what the easiest path looks like
Bold SolutionMaximum benefit, maximum cost/riskShows the ideal outcome if constraints didn't matter
Middle PathBalanced compromise with creative elementsOften the actual chosen solution; reveals tradeoffs clearly

For each option, briefly note:

  • What it is (one sentence description)
  • Key advantage
  • Primary risk or cost

Checkpoint: Do all three options address every Non-negotiable requirement? If one fails a non-negotiable, eliminate it and generate another.


Step 6: Evaluate Using Weighted Decision Matrix

Score each option against each criterion on a scale of 1–5 (1 = poor fit, 5 = excellent fit). Multiply by the criterion weight from Step 2. Sum weighted scores to rank options.

See the Decision Matrix Pattern in the Reference Guide below for the implementation.

Checkpoint: Do the ranked results feel right? If the top choice contradicts your team's intuition, revisit your weights — you may have misaligned priorities.


Step 7: Make a Call With Explicit Reasoning

Present the recommendation with this structure:

  1. Recommendation: The chosen option
  2. Primary rationale: Why it wins on the most heavily weighted criteria
  3. Acknowledged tradeoffs: What we're accepting as downside
  4. Fallback plan: What to do if assumptions prove wrong (especially for two-way decisions)
  5. Review date: When to revisit this decision

For one-way door decisions, write an Architecture Decision Record (architecture-decision-records skill). For two-way door decisions, a brief comment or PR description suffices.

Checkpoint: If you can't articulate the tradeoff clearly in one sentence, the decision isn't ready to communicate.


Reference Guide: Frameworks and Patterns

Framework 1: Technology Radicals Decision Framework (Forsgren et al.)

Classify every technical decision along two axes — Immutability (how hard is it to change?) × Configurability (can it be tuned without code changes?):

                    IMMUTABLE          CONFIGURABLE
                   ┌──────────────┬──────────────────┐
                   │   MODULAR    │     EMERGENT     │
  Immutability →   │              │                  │
                   │  Architecture│  Infrastructure  │
                   │  choices:    │  configuration:  │
                   │  - Service   │  - Feature flags │
                   │    boundaries│  - Env variables │
                   │  - API       │  - Database      │
                   │    contracts │    connection    │
                   ├──────────────┼──────────────────┤
                   │   ADAPTABLE  │     FLEXIBLE     │
                   │              │                  │
                   │  Code-level: │  Creative work:  │
                   │  - Plugin    │  - Algorithm     │
                   │    interfaces│    parameter      │
                   │  - Strategy  │    tuning         │
                   │    pattern   │  - ML model       │
                   │              │    selection      │
                   └──────────────┴──────────────────┘
  • Modular decisions: Invest in clean interfaces, use dependency injection. Changes are hard but infrequent.
  • Emergent decisions: Use configuration over code. Let the system evolve through tuning.
  • Adaptable decisions: Plan for change with plugin/strategy patterns. Frequent changes expected.
  • Flexible decisions: Maximize learning velocity. Experiment and iterate rapidly.

Framework 2: OREO Framework

OREO helps structure the analysis before scoring:

  1. Optionally Defer: Ask "What happens if we do nothing for 3 months?" If deferring causes no harm, defer. Many tradeoff decisions dissolve when time provides more information.
  2. Requirements Classification: As described in Step 2 of the Core Workflow.
  3. Options Generation: As described in Step 5 — three archetypes, not binary choices.
  4. Evaluation: Weighted scoring with transparent rationale.

Framework 3: CAP Theorem for Software Decisions

While CAP is often discussed in distributed systems context, it generalizes to any software architecture decision where you balance competing non-functional requirements:

DimensionWhat it meansExample tradeoff
ConsistencyAll consumers see the same data at the same timeStrong consistency slows writes (CAP: CP systems)
AvailabilityEvery request gets a response, even if staleEventual consistency risks reading stale data
Partition ToleranceSystem works despite network/component failuresRequires handling partial failures gracefully

In practice, choose which two of C/A/P matter most for your use case. There is no free lunch — every choice sacrifices one dimension.


Implementation Patterns

Pattern 1: Weighted Decision Matrix Engine

This Python function implements the core scoring engine for tradeoff analysis:

from dataclasses import dataclass, field
from typing import Optional


@dataclass
class Criterion:
    """A single evaluation criterion with its weight."""
    name: str
    weight: float  # Must sum to 1.0 across all criteria
    description: str = ""

    def __post_init__(self):
        if not 0 < self.weight <= 1.0:
            raise ValueError(f"Weight must be between 0 and 1, got {self.weight}")


@dataclass
class Option:
    """A candidate option to evaluate."""
    name: str
    description: str
    scores: dict[str, int] = field(default_factory=dict)  # criterion_name -> 1-5 score

    def weighted_score(self, criteria: list[Criterion]) -> float:
        """Calculate total weighted score across all criteria."""
        return sum(
            self.scores.get(criterion.name, 0) * criterion.weight
            for criterion in criteria
        )

    def __repr__(self) -> str:
        return f"Option({self.name}: {self.description})"


@dataclass
class TradeoffResult:
    """Structured result from tradeoff evaluation."""
    chosen: Option
    all_ranked: list[Option]
    criteria: list[Criterion]
    analysis_summary: str
    acknowledged_tradeoffs: list[str] = field(default_factory=list)

    def summary(self) -> str:
        lines = [f"## Tradeoff Analysis Result\n", f"**Chosen:** {self.chosen.name}\n"]
        lines.append(f"**Weighted Score:** {self.chosen.weighted_score(self.criteria):.2f}/5.00\n")
        lines.append("\n### Ranking\n")
        for i, opt in enumerate(self.all_ranked, 1):
            score = opt.weighted_score(self.criteria)
            marker = " ← CHOSEN" if opt is self.chosen else ""
            lines.append(f"{i}. **{opt.name}** — {score:.2f}/5.00{marker}")
        if self.acknowledged_tradeoffs:
            lines.append("\n### Acknowledged Tradeoffs\n")
            for tradeoff in self.acknowledged_tradeoffs:
                lines.append(f"- {tradeoff}")
        return "".join(lines)


def evaluate_tradeoffs(
    options: list[Option],
    criteria: list[Criterion],
    decision_type: str = "two-way",  # or "one-way"
) -> TradeoffResult:
    """Evaluate competing options using weighted multi-criteria analysis.

    Args:
        options: Candidate options with scores per criterion (1-5 scale)
        criteria: Named criteria with weights summing to 1.0
        decision_type: Reversibility classification for urgency context

    Returns:
        Structured result with ranking, chosen option, and analysis summary

    Raises:
        ValueError: If criteria weights do not sum to 1.0 or scores are out of range
    """
    # Validate weights sum to 1.0
    total_weight = sum(c.weight for c in criteria)
    if abs(total_weight - 1.0) > 0.001:
        raise ValueError(f"Criterion weights must sum to 1.0, got {total_weight:.4f}")

    # Validate scores are in range
    criterion_names = {c.name for c in criteria}
    for opt in options:
        for name, score in opt.scores.items():
            if name not in criterion_names:
                raise ValueError(f"Unknown criterion '{name}' in option '{opt.name}'")
            if not (1 <= score <= 5):
                raise ValueError(f"Score for {opt.name}.{name} = {score}, must be 1-5")

    # Score and rank options
    scored = sorted(options, key=lambda o: o.weighted_score(criteria), reverse=True)

    # Build analysis summary
    chosen = scored[0]
    runner_up = scored[1] if len(scored) > 1 else None

    gap = chosen.weighted_score(criteria) - (runner_up.weighted_score(criteria) if runner_up else 0)

    decision_label = "fast-tracked" if decision_type == "two-way" else "thoroughly analyzed"

    summary = (
        f"Option '{chosen.name}' selected ({decision_label}) with score "
        f"{chosen.weighted_score(criteria):.2f}. "
        f"Margin over runner-up '{runner_up.name if runner_up else 'N/A'}': {gap:.2f} points."
    )

    # Identify key tradeoffs: where runner-up beats chosen
    tradeoffs = []
    for c in criteria:
        if runner_up and runner_up.scores.get(c.name, 0) > chosen.scores.get(c.name, 0):
            direction = "better" if decision_type == "two-way" else "worse"
            tradeoffs.append(
                f"We choose '{chosen.name}' over '{runner_up.name}' accepting that "
                f"it scores lower on '{c.name}' (weight: {c.weight:.1f})"
            )

    return TradeoffResult(
        chosen=chosen,
        all_ranked=scored,
        criteria=criteria,
        analysis_summary=summary,
        acknowledged_tradeoffs=tradeoffs,
    )


# Example usage: Choosing between PostgreSQL and MongoDB for a user data store
if __name__ == "__main__":
    criteria = [
        Criterion("Data Integrity", weight=0.30, description="Required by financial compliance"),
        Criterion("Development Velocity", weight=0.25, description="Team needs to ship in < 6 weeks"),
        Criterion("Flexibility / Schema Evolution", weight=0.20),
        Criterion("Operational Complexity", weight=0.15),
        Criterion("Ecosystem Tooling", weight=0.10),
    ]

    options = [
        Option(
            name="PostgreSQL",
            description="Relational DB with ACID guarantees, rigid schema",
            scores={"Data Integrity": 5, "Development Velocity": 3, "Flexibility": 2, "Operational Complexity": 3, "Ecosystem Tooling": 5},
        ),
        Option(
            name="MongoDB",
            description="Document DB with flexible schema, eventual consistency",
            scores={"Data Integrity": 3, "Development Velocity": 4, "Flexibility": 5, "Operational Complexity": 4, "Ecosystem Tooling": 4},
        ),
    ]

    # Note: "Flexibility" maps to "Flexibility / Schema Evolution" criterion
    # In production, ensure option score keys match criterion names exactly

    result = evaluate_tradeoffs(options, criteria, decision_type="one-way")
    print(result.summary())

Pattern 2: Decision Matrix Template (Structured Output)

When producing tradeoff analysis for stakeholders, use this structured format. This is the output that feeds into an Architecture Decision Record.

Decision Matrix: [Decision Topic]

┌─────────────────────┬───────────┬───────────┬───────────┐
│ Criterion           │  Weight   │ Option A  │ Option B  │ Option C  │
├─────────────────────┼───────────┼───────────┼───────────┤
│ Data Integrity      │    0.30   │     5     │     3     │     4     │
│ → Weighted Score    │           │   1.50    │   0.90    │   1.20    │
├─────────────────────┼───────────┼───────────┼───────────┤
│ Dev Velocity        │    0.25   │     3     │     4     │     3     │
│ → Weighted Score    │           │   0.75    │   1.00    │   0.75    │
├─────────────────────┼───────────┼───────────┼───────────┤
│ [Additional]        │    ...    │     ·     │     ·     │     ·     │
├─────────────────────┼───────────┼───────────┼───────────┤
│ TOTAL               │   1.00    │   3.XX    │   X.XX    │   X.XX    │
│ RANKING             │           │     #1    │     #2    │     #3    │
└─────────────────────┴───────────┴───────────┴───────────┘

Decision Type: [Two-way door / One-way door]
Recommended Option: [Option A/B/C]
Review Date: [Date to revisit if assumptions prove wrong]

Real-World Tradeoff Case Studies

These examples demonstrate how leading companies navigated similar tradeoffs:

Twitter: Memcached → Redis

Conflict: Performance under load vs. operational complexity

  • Chose Redis for its data structures and persistence over Memcached's pure caching model
  • Accepted higher operational overhead for the capability of richer data operations
  • Tradeoff acknowledged: More ops burden, but enabled new feature capabilities (leaderboards, real-time feeds)

GitHub: Rails for Development Velocity

Conflict: Fast iteration vs. long-term performance scalability

  • Chose Rails despite knowing it would not scale infinitely — accepted technical debt with a plan to migrate parts to Go/Rust
  • Key insight: Speed of learning and iterating in the early market > optimal architecture
  • Tradeoff acknowledged: Performance bottlenecks emerged; solved through incremental migration, not rip-and-replace

Instagram: MongoDB for Schema Flexibility

Conflict: Data integrity vs. rapid schema evolution during product discovery

  • Chose MongoDB's flexible schema because their data model was still evolving rapidly with product changes
  • Later migrated photo metadata to PostgreSQL as the schema stabilized
  • Tradeoff acknowledged: Lost relational constraints during early phase, but gained speed of iteration

Slack: Elixir → Go Migration

Conflict: Technical elegance (Elixir/BEAM) vs. organizational hiring reality

  • Started with Elixir for its concurrency model — technically superior choice
  • Migrated to Go because hiring Go developers was easier and the team could move faster with familiar tools
  • Tradeoff acknowledged: Some technical tradeoffs in performance, but organizational capability won

Stripe: Custom Payments Infrastructure

Conflict: Build cost vs. vendor lock-in risk + competitive differentiation

  • Built custom payment processing instead of using existing gateways
  • Justification: Payment handling is core to their product — differentiating on reliability and developer experience
  • Tradeoff acknowledged: Massive upfront development cost, but created a defensible moat

Decision Heuristics

Apply these rules of thumb when the analysis feels stuck or overwhelming:

  1. Two-way door decisions → make fast. The cost of being wrong is bounded. You can always undo. Aim for 70% information, not 100%.
  2. One-way door decisions → consensus + thorough analysis. Involve more stakeholders. Require weighted scoring. Build detailed ADRs.
  3. Keep options open when uncertain. Pay the abstraction tax upfront if you genuinely don't know which direction is right. The cost of rework later is usually higher than building slightly more abstract code now.
  4. Optimize for learning, not certainty under high uncertainty. When you have less than 60% confidence in your assumptions, design decisions that maximize information gain (e.g., spike a prototype, run a time-boxed experiment).
  5. Default to YAGNI unless concrete evidence shows feature coming within 1–2 quarters. Speculative abstraction is the most common source of unnecessary tradeoff complexity.
  6. C3 Principle: Major architectural decisions should be continuous and consensual. No single person makes irreversible calls alone; no single meeting decides everything.
  7. If all options are equally bad, look for a fourth option. Binary and ternary choices are cognitive traps. The real answer often lies in a creative alternative that wasn't initially obvious.

Constraints

MUST DO

  • Always make the conflict explicit before generating options — never start with "here are some ideas"
  • Classify at least one requirement as Non-negotiable — if nothing is non-negotiable, decisions lose their anchor
  • Generate at least 3 options — binary choices hide superior alternatives and trigger confirmation bias
  • Weight criteria explicitly — unweighted comparisons are just opinions dressed up as analysis
  • Document acknowledged tradeoffs — every decision has downsides; hiding them destroys stakeholder trust
  • Match analysis depth to decision reversibility — two-way doors get lightweight analysis, one-way doors get thorough evaluation
  • Include a review date — decisions become stale when assumptions change

MUST NOT DO

  • Never present a binary choice as the full set of options
  • Don't weight criteria subjectively after evaluating options — define weights before scoring to avoid anchoring bias
  • Don't skip reversibility classification — it determines the appropriate amount of analysis effort
  • Don't let the most senior person's preference dictate the weights — that's not analysis, it's announcement
  • Don't document only the outcome without acknowledging tradeoffs — future teams need to understand what was accepted
  • Don't use this framework for decisions where one option clearly dominates on all non-negotiable criteria

Output Template

When applying this skill to a tradeoff decision, produce:

  1. Conflict Statement — One sentence: "We want X but achieving it requires A while B requires C"
  2. Classification Summary — Decision type (two-way/one-way door), requirements by tier with weights
  3. Options Catalog — Three options with descriptions, advantages, and primary risks
  4. Weighted Decision Matrix — Scoring table showing criterion weights, option scores, weighted sub-scores, and totals
  5. Recommendation — Chosen option with rationale tied to highest-weight criteria
  6. Acknowledged Tradeoffs — What downside is being accepted and on what criteria
  7. Fallback / Review Plan — Conditions that would trigger re-evaluation, and a date for the review

For one-way door decisions, also produce an Architecture Decision Record following the architecture-decision-records skill template.


Related Skills

SkillPurpose
architecture-decision-recordsDocument the decision after it's made — this skill analyzes, ADRs record
design-pattern-selectionPicks specific implementation patterns — use after tradeoff analysis narrows direction
engineering-principlesFoundational principles that inform criteria weights and constraint definitions
technical-debt-managementWhen the tradeoff accepts debt, track it here with repayment plans

Live References

Authoritative sources for engineering tradeoff frameworks and decision-making methodologies.

我的收藏