|
| 1 | +--- |
| 2 | +name: 80-20-review |
| 3 | +description: > |
| 4 | + Focus code review effort on the 20% of code that causes 80% of issues. |
| 5 | + Prioritizes data access, security, concurrency, and integration boundaries |
| 6 | + over formatting and style. Uses blast radius scoring to determine review |
| 7 | + depth. Includes checkpoint schedules, critical path identification, and |
| 8 | + a batch review checklist. Load this skill when reviewing code, PRs, or |
| 9 | + architecture, or when the user mentions "review", "code review", "PR review", |
| 10 | + "what should I review", "review priorities", "blast radius", or "critical path". |
| 11 | +--- |
| 12 | + |
| 13 | +# 80/20 Review |
| 14 | + |
| 15 | +## Core Principles |
| 16 | + |
| 17 | +1. **Review at checkpoints, not continuously** — Constant review interrupts flow. Schedule reviews at natural breakpoints: post-implementation, pre-PR, post-integration, and post-deploy. Each checkpoint has a different focus. |
| 18 | + |
| 19 | +2. **Focus on data access, security, concurrency, integration** — These are the 20% of code areas that cause 80% of production incidents. A missing `CancellationToken` is more dangerous than a misnamed variable. Review depth should match risk. |
| 20 | + |
| 21 | +3. **Blast radius determines depth** — A utility function used in one place gets a glance. A middleware change that affects every request gets a thorough review. Score changes by blast radius and invest review time proportionally. |
| 22 | + |
| 23 | +4. **Automate the trivial** — Formatting, import ordering, naming conventions, and basic anti-patterns should be caught by tools (formatters, analyzers, hooks), not humans. Save human attention for things tools can't catch: logic errors, design flaws, and missing edge cases. |
| 24 | + |
| 25 | +## Patterns |
| 26 | + |
| 27 | +### Checkpoint Schedule |
| 28 | + |
| 29 | +Review at these natural breakpoints, each with a specific focus: |
| 30 | + |
| 31 | +``` |
| 32 | +CHECKPOINT 1: Post-Implementation (self-review) |
| 33 | +WHEN: After completing a feature or fix, before committing |
| 34 | +FOCUS: Does it work? Does it compile? Do tests pass? |
| 35 | +DEPTH: Quick — 5 minutes |
| 36 | +CHECKLIST: |
| 37 | +□ dotnet build passes |
| 38 | +□ dotnet test passes (all existing + new tests) |
| 39 | +□ get_diagnostics shows no new warnings |
| 40 | +□ No obvious anti-patterns (DateTime.Now, new HttpClient, async void) |
| 41 | +
|
| 42 | +CHECKPOINT 2: Pre-PR (focused review) |
| 43 | +WHEN: Before creating a pull request |
| 44 | +FOCUS: Would a staff engineer approve this? |
| 45 | +DEPTH: Thorough on critical paths, glance at routine code — 15-30 minutes |
| 46 | +CHECKLIST: |
| 47 | +□ Data access: N+1 queries, missing Include, no tracking where possible |
| 48 | +□ Security: Auth checks, input validation, no secrets in code |
| 49 | +□ Concurrency: CancellationToken propagated, no deadlocks, thread-safe state |
| 50 | +□ Error handling: Result pattern used, no swallowed exceptions |
| 51 | +□ API surface: TypedResults, proper status codes, response DTOs (not entities) |
| 52 | +□ Integration: Events published correctly, consumer idempotency |
| 53 | +□ Tests: Integration tests cover the happy path + main error case |
| 54 | +□ Breaking changes: Public API surface unchanged (or intentionally changed) |
| 55 | +
|
| 56 | +CHECKPOINT 3: Post-Integration (system review) |
| 57 | +WHEN: After merging to main or integrating with other modules |
| 58 | +FOCUS: Does it play well with the rest of the system? |
| 59 | +DEPTH: Targeted — check integration points — 10 minutes |
| 60 | +CHECKLIST: |
| 61 | +□ Cross-module events consumed correctly |
| 62 | +□ Database migrations applied cleanly |
| 63 | +□ No circular dependencies introduced |
| 64 | +□ CI pipeline passes |
| 65 | +
|
| 66 | +CHECKPOINT 4: Post-Deploy (production readiness) |
| 67 | +WHEN: Before or immediately after deploying |
| 68 | +FOCUS: Is it safe in production? |
| 69 | +DEPTH: Quick but critical — 5 minutes |
| 70 | +CHECKLIST: |
| 71 | +□ Health checks pass |
| 72 | +□ Logs produce structured output (no PII) |
| 73 | +□ Retry/circuit breaker policies configured for external calls |
| 74 | +□ Feature flags in place for risky changes (if applicable) |
| 75 | +``` |
| 76 | + |
| 77 | +### Critical Path Identification |
| 78 | + |
| 79 | +Use MCP tools to identify the code that matters most: |
| 80 | + |
| 81 | +``` |
| 82 | +HIGH-RISK CODE (review thoroughly): |
| 83 | +1. Data access layer |
| 84 | + → find_references for DbContext usage |
| 85 | + → Check for N+1 (missing Include/AsSplitQuery), missing CancellationToken |
| 86 | + → Check for raw SQL injection risks |
| 87 | +
|
| 88 | +2. Authentication & authorization |
| 89 | + → find_implementations of IAuthorizationHandler |
| 90 | + → Check every endpoint has [Authorize] or explicit [AllowAnonymous] |
| 91 | + → Verify token validation configuration |
| 92 | +
|
| 93 | +3. External service integration |
| 94 | + → find_references for HttpClient, IHttpClientFactory |
| 95 | + → Check for retry policies (Polly), timeout configuration |
| 96 | + → Verify error handling for external failures |
| 97 | +
|
| 98 | +4. Concurrency & shared state |
| 99 | + → find_references for static fields, ConcurrentDictionary |
| 100 | + → Check BackgroundService implementations for scope management |
| 101 | + → Verify CancellationToken propagation in async chains |
| 102 | +
|
| 103 | +5. Message consumers |
| 104 | + → find_implementations of IConsumer |
| 105 | + → Check for idempotency (handle duplicate messages) |
| 106 | + → Verify error handling and dead letter configuration |
| 107 | +
|
| 108 | +LOW-RISK CODE (glance or skip): |
| 109 | +- DTOs and record definitions |
| 110 | +- Extension method registration (AddXxx pattern) |
| 111 | +- Configuration binding (Options pattern) |
| 112 | +- Simple CRUD with no business logic |
| 113 | +- Test helper/fixture code |
| 114 | +``` |
| 115 | + |
| 116 | +### Blast Radius Scoring |
| 117 | + |
| 118 | +Score each change to determine review investment: |
| 119 | + |
| 120 | +``` |
| 121 | +CRITICAL (30+ min review): |
| 122 | +- Middleware changes (affects every request) |
| 123 | +- Authentication/authorization changes |
| 124 | +- Database schema changes (migrations) |
| 125 | +- Shared kernel / cross-cutting concern changes |
| 126 | +- CI/CD pipeline changes |
| 127 | +Signal: Many dependents, hard to roll back, security implications |
| 128 | +
|
| 129 | +HIGH (15-30 min review): |
| 130 | +- New module or subsystem |
| 131 | +- Public API surface changes |
| 132 | +- Message consumer changes (affects async workflows) |
| 133 | +- EF Core configuration changes (query behavior, indexes) |
| 134 | +Signal: Multiple consumers, behavioral changes, data integrity |
| 135 | +
|
| 136 | +MEDIUM (5-15 min review): |
| 137 | +- New feature within existing module (follows patterns) |
| 138 | +- Test additions or modifications |
| 139 | +- New endpoint following established conventions |
| 140 | +Signal: Localized impact, follows existing patterns |
| 141 | +
|
| 142 | +LOW (glance or auto-approve): |
| 143 | +- Documentation updates |
| 144 | +- Formatting / import ordering |
| 145 | +- Adding logging statements |
| 146 | +- Renaming internal variables |
| 147 | +Signal: No behavioral change, cosmetic only |
| 148 | +``` |
| 149 | + |
| 150 | +### Batch Review Checklist |
| 151 | + |
| 152 | +The 10 highest-value checks for any .NET code review: |
| 153 | + |
| 154 | +``` |
| 155 | +THE TOP 10 (in priority order): |
| 156 | +
|
| 157 | +1. SQL INJECTION — Any raw SQL or string-interpolated queries? |
| 158 | + → EF parameterizes by default, but check for FromSqlRaw with user input |
| 159 | +
|
| 160 | +2. AUTH GAPS — Every endpoint has explicit auth? No open endpoints by accident? |
| 161 | + → Check for missing [Authorize] on new controllers/endpoint groups |
| 162 | +
|
| 163 | +3. N+1 QUERIES — Loading collections without Include/join? |
| 164 | + → Check any LINQ that accesses navigation properties after the query |
| 165 | +
|
| 166 | +4. CANCELLATION PROPAGATION — CancellationToken passed through the full chain? |
| 167 | + → From endpoint → handler → service → EF query. Breaking the chain = uninterruptible |
| 168 | +
|
| 169 | +5. SECRET EXPOSURE — Any connection strings, API keys, or tokens in code? |
| 170 | + → Check for hardcoded strings that look like credentials |
| 171 | +
|
| 172 | +6. EXCEPTION SWALLOWING — Catch blocks that silently discard errors? |
| 173 | + → Empty catch, catch with only a log, catch(Exception) without rethrow |
| 174 | +
|
| 175 | +7. ASYNC DEADLOCKS — .Result, .Wait(), .GetAwaiter().GetResult()? |
| 176 | + → Any synchronous blocking on async code = potential deadlock |
| 177 | +
|
| 178 | +8. ENTITY LEAKS — Domain entities returned directly from API endpoints? |
| 179 | + → Entities should map to response DTOs/records at the API boundary |
| 180 | +
|
| 181 | +9. MISSING VALIDATION — User input reaching business logic unchecked? |
| 182 | + → Every command/request DTO should have a corresponding validator |
| 183 | +
|
| 184 | +10. RESOURCE LEAKS — Disposable objects not in using/await using blocks? |
| 185 | + → HttpClient, DbContext, FileStream, etc. created without disposal |
| 186 | +``` |
| 187 | + |
| 188 | +### Review with MCP Tools |
| 189 | + |
| 190 | +Leverage Roslyn MCP tools for efficient, targeted review: |
| 191 | + |
| 192 | +``` |
| 193 | +REVIEW WORKFLOW WITH MCP: |
| 194 | +
|
| 195 | +1. get_project_graph → Understand what changed in the solution structure |
| 196 | +2. get_diagnostics → Catch compiler warnings (CS warnings often signal real issues) |
| 197 | +3. detect_antipatterns → Automated anti-pattern scan |
| 198 | +4. find_dead_code → Check if the change left any dead code behind |
| 199 | +5. detect_circular_dependencies → Verify no new cycles introduced |
| 200 | +6. get_test_coverage_map → Verify changed code has test coverage |
| 201 | +
|
| 202 | +This MCP-first approach reviews the system-level impact in ~300 tokens |
| 203 | +before you even read a single file. |
| 204 | +``` |
| 205 | + |
| 206 | +## Anti-patterns |
| 207 | + |
| 208 | +### Reviewing Every Trivial Change |
| 209 | + |
| 210 | +``` |
| 211 | +// BAD — spending 20 minutes reviewing a rename |
| 212 | +PR: Rename `OrderSvc` → `OrderService` across 8 files |
| 213 | +Reviewer spends 20 minutes verifying each rename is correct. |
| 214 | +*This is what Find & Replace + tests are for* |
| 215 | +
|
| 216 | +// GOOD — trust the tooling for mechanical changes |
| 217 | +PR: Rename `OrderSvc` → `OrderService` across 8 files |
| 218 | +Reviewer: "Tests pass? Build passes? Auto-approve." |
| 219 | +*Spend that 20 minutes reviewing the authentication change instead* |
| 220 | +``` |
| 221 | + |
| 222 | +### Skipping Reviews Because "It's Just a Small Change" |
| 223 | + |
| 224 | +``` |
| 225 | +// BAD — one-line change to auth middleware, no review |
| 226 | +"It's just adding a header, no need to review" |
| 227 | +*That header now leaks internal server info to every response* |
| 228 | +
|
| 229 | +// GOOD — blast radius determines review, not line count |
| 230 | +One-line change to middleware → CRITICAL blast radius → thorough review |
| 231 | +"This adds a header to every HTTP response. Is it safe? Does it leak info? |
| 232 | +Does it affect caching? Does it break CORS?" |
| 233 | +``` |
| 234 | + |
| 235 | +### Style Over Substance |
| 236 | + |
| 237 | +``` |
| 238 | +// BAD — reviewer focuses on naming while missing the N+1 |
| 239 | +"Line 15: rename 'x' to 'order' for clarity" |
| 240 | +"Line 23: add a blank line between methods" |
| 241 | +*Meanwhile, line 28 has an N+1 query that will hammer the database* |
| 242 | +
|
| 243 | +// GOOD — substance first, style if time permits |
| 244 | +"Line 28: This will produce an N+1 — add .Include(o => o.Items)" |
| 245 | +"Line 42: Missing CancellationToken in the EF query" |
| 246 | +*Only after critical issues are addressed: "Line 15: consider renaming 'x'"* |
| 247 | +``` |
| 248 | + |
| 249 | +### Manual Review of Automatable Checks |
| 250 | + |
| 251 | +``` |
| 252 | +// BAD — manually checking formatting in every PR |
| 253 | +Reviewer spends 5 minutes checking import ordering, bracket placement, |
| 254 | +and whitespace consistency. |
| 255 | +*Formatters and analyzers do this in milliseconds* |
| 256 | +
|
| 257 | +// GOOD — automate the trivial, review the meaningful |
| 258 | +Pre-commit hook: dotnet format --verify-no-changes |
| 259 | +CI step: dotnet format --verify-no-changes (catches anything the hook missed) |
| 260 | +Reviewer: focuses on logic, security, performance, and design |
| 261 | +``` |
| 262 | + |
| 263 | +## Decision Guide |
| 264 | + |
| 265 | +| Scenario | Review Depth | Focus Area | |
| 266 | +|----------|-------------|------------| |
| 267 | +| New endpoint following existing pattern | Medium (5-15 min) | Auth, validation, response mapping | |
| 268 | +| Authentication/authorization change | Critical (30+ min) | Every code path, edge cases, token handling | |
| 269 | +| Database migration | Critical (30+ min) | Data loss risk, rollback strategy, index impact | |
| 270 | +| New module or subsystem | High (15-30 min) | Architecture, boundaries, integration points | |
| 271 | +| Bug fix with clear root cause | Medium (5-15 min) | Root cause correctness, regression test | |
| 272 | +| Rename/formatting/docs PR | Low (glance) | Tests pass, build passes, auto-approve | |
| 273 | +| EF Core query changes | High (15-30 min) | N+1, tracking, cancellation, SQL generated | |
| 274 | +| Middleware or filter changes | Critical (30+ min) | Blast radius — affects every request | |
| 275 | +| Test additions | Low-Medium | Test quality, are they testing behavior not implementation | |
| 276 | +| CI/CD pipeline changes | High (15-30 min) | Security (secrets), deployment safety, rollback | |
0 commit comments