Skip to content
Back to work
R / ShinyLive · v2.0.0 · MIT

Shiny App Valuation Toolkit

COCOMO II cost estimation with test-locked math

Shiny App Valuation Toolkit dashboard
~180
Test assertions
42%
Cost cliff eliminated
3
Analysis modes
±30%
Honest estimate range

The problem

Estimating what an internal Shiny or data-science tool would cost to build commercially usually comes down to a gut number nobody can defend. Generic COCOMO calculators don't understand mixed R/Python/SQL codebases, and ad-hoc spreadsheets drift: the toolkit's own v1 model had a discrete schedule-compression premium ladder where moving a deadline by one month could swing the estimate by up to 42%.

Architecture

01 · Input
  • Local folder scan
  • ZIP upload (50 MB)
  • Manual line entry
02 · Count & weight
  • Language detection
  • Productivity weights
  • Docs/config excluded
03 · COCOMO II
  • A × KLOC^B × EM
  • TDEV = 3.67 × E^D
  • ±30% range
04 · Constraints
  • Team cap (max 8)
  • Smooth SCED premium
  • Coordination +10%
05 · Output
  • Waterfall · sensitivity
  • Maintenance & TCO (NPV)
  • Quarto + Typst PDF
Shiny App Valuation Toolkit — repository to defensible estimateEvery displayed number is internally consistent — effort = team × schedule — and ~180 assertions keep it that way.

What it does

Two interfaces share one estimation engine: an interactive Shiny dashboard — hero estimate with a ±30% range, a waterfall breakdown that totals exactly the headline cost, a language treemap, sensitivity curves that pass through the user's actual estimate, and a maintenance/TCO projection — and an R CLI (analyze_repo_code()) that scans a repository and prints an scc-style report. Three analysis modes: local folder scan, ZIP upload (50 MB, path-traversal validated), and manual line entry.

  • Effort = A × KLOC^B × EM × 0.85, with the modern-framework calibration applied exactly once
  • Language productivity weighting (SQL 1.3×, JS 0.9×); docs and config (Markdown, JSON, YAML, SVG) shown but never billed
  • Scenario comparison of up to 3 estimates side-by-side with shared cost parameters

The 42% cost cliff

v1 applied schedule-compression premiums as a discrete 20/40/70/100% ladder, so moving a deadline by one month could jump the estimate by up to 42%. v2.0 replaced it with a continuous premium — ratio^1.25, anchored to COCOMO II's SCED driver and capped at 2.0× — so small input changes now produce small output changes. A regression test guards cost continuity at the schedule cap.

Model corrections, published-calibration honest

The v2.0 audit re-aligned every constant with published COCOMO II.2000 calibration: A = 2.94, C = 3.67, and the schedule exponent anchored at 0.91 — the old 1.01 anchor had been systematically shortening schedules.

  • Displayed effort always equals team × schedule, including under compression
  • The ±30% band is labeled an estimate range — typical COCOMO II accuracy — never a confidence interval
  • Teams of 6+ carry a 10% coordination premium, and infeasible compressed plans are flagged, not silently absorbed
  • Maintenance escalates 5%/yr and is reported both nominally and discounted to present value

~180 assertions lock the math

The test suite grew from 59 to ~180 assertions across 8 files, treating the estimation model as an API with a contract.

  • Golden-value regressions and model invariants (effort = team × schedule, exact wage linearity)
  • Billable-classification tests — adding documentation never moves the estimate
  • A testServer smoke test plus an end-to-end PDF render test
  • Drift detection that fails CI if the deployable modules/ copies of the engine diverge from R/

Client-ready PDF, no LaTeX

One click renders a 4–5 page branded report — cover with the headline estimate, KPI summary, waterfall and driver charts, assumptions table, methodology page — via Quarto + Typst, with no LaTeX and no headless Chrome, so it runs on shinyapps.io.

  • A single design-token source drives the app, every chart, and the PDF
  • Shareable URLs with validated, bounds-checked parameters; CSV and JSON export

Stack

RShinybslibCOCOMO IIPlotlyQuarto + Typsttestthat