Engineering performance insights — from raw metrics to actionable interpretation.
Built as part of the intern assignment on developer productivity.
Most dashboards stop at visualization. DevLens adds an interpretation layer that translates raw engineering metrics into a diagnosis and concrete next steps — helping a developer move from "I see a number" to "I know what to do."
| Metric | Definition |
|---|---|
| Lead Time | Avg days from PR opened to production deployment |
| Cycle Time | Avg days from issue In Progress to Done |
| Bug Rate | Escaped bugs ÷ issues completed × 100 |
| Deploy Frequency | Count of successful production deployments in the month |
| PR Throughput | Count of merged pull requests in the month |
| Layer | Choice | Why |
|---|---|---|
| Frontend | React + Vite | Fast setup, no unnecessary complexity |
| Data | Static JS files | Data was pre-aggregated; shape mirrors a real API response |
| Styling | Vanilla CSS with custom properties | No framework dependency, full control |
| Backend | None | Not needed — swapping to a REST API is a one-line change in useMetrics |
src/
├── data/
│ ├── metrics.js # 16 rows — 8 developers × 2 months (pre-aggregated)
│ └── developers.js # 8 developer dimension records
├── components/
│ ├── DeveloperSelector.jsx # Dropdown + month toggle
│ ├── MetricCard.jsx # Single metric with status + delta badge
│ ├── MetricsGrid.jsx # 5-card grid, computes status and deltas
│ ├── InterpretationPanel.jsx # Headline, story, next steps
│ └── ManagerView.jsx # Team summary table with signal column
├── hooks/
│ └── useMetrics.js # Data lookup — returns matching row or null
├── logic/
│ ├── getStatus.js # Threshold rules → 'good' | 'warn' | 'alert'
│ ├── getDelta.js # Month-over-month delta with directional awareness
│ └── interpret.js # Rule engine → headline, story, next steps
├── App.jsx # Single source of truth — owns all state
└── app.css # Single stylesheet with CSS custom properties
Both MetricsGrid and InterpretationPanel need the same data. Lifting state to App.jsx gives both components access without prop drilling through intermediate layers.
getStatus, getDelta, and interpret are pure functions in src/logic/. Components receive results as props and render — they never decide anything. This makes the logic independently testable and easy to explain.
interpret.js uses an explicit rule chain. Each rule maps a specific metric combination to a likely cause and a concrete action. Chosen over ML because:
- 16 rows of data is not enough to train anything meaningful
- Every output is fully explainable — you can trace any headline back to the exact condition that triggered it
- Thresholds are based on DORA research benchmarks and are easy to adjust
The assignment provided a pre-aggregated Excel sheet. The data shape mirrors what a REST API would return — swapping to a real backend is a one-line change in useMetrics.js. No backend complexity for zero benefit.
getDelta knows which direction is good per metric. A ↓ on bug rate is green. A ↓ on PR throughput is red. This avoids misleading signals on the metric cards.
If you want to understand the project quickly, read these three files in order:
src/logic/interpret.js— the core differentiatorsrc/logic/getStatus.js— explicit threshold tablesrc/App.jsx— how state flows through the app
# Install dependencies
npm install
# Start dev server
npm run devApp runs at http://localhost:5173