Skip to content

What is dowse?

The problem it solves

In a large codebase — a monorepo especially — a team keeps running into one question:

With the time we actually have, where do we fix things so it pays off most?

Technical debt is unbounded. Refactoring candidates are unbounded. Time is not.

Conventional static analysis (ESLint, SonarQube) looks at a snapshot and lists every problem as equally important. It produces thousands of warnings and no priority. And fixing code that is complex but that nobody ever touches returns approximately nothing.

The central insight

Adam Tornhill, who created this field with CodeScene, put it simply:

Not all code is equal. Only code that is both changed often and complex — a hotspot — is genuinely a problem, and that is where investment pays off.

And "changed often" is already written down, in your git history.

Crossing code structure (static analysis) with change history (version control mining) is behavioral code analysis.

What dowse adds

dowse reworks that insight specifically for TypeScript monorepos.

1. Package boundaries are first-class

CodeScene supports 39 languages, and monorepos are retrofitted onto it as "a collection of folders". It does not understand npm/pnpm workspaces, or the package boundaries and dependency graph of Turborepo/Nx.

dowse reads your workspace configuration directly and runs the behavioral analysis on top of the package graph. Everything below follows from that.

2. It finds hidden coupling

Two packages with no dependency between them that keep being changed in the same commit — coupling that never appears in the structure.

affected in Nx or Turborepo tells you what to rebuild; it does not see this. Looking at the dependency graph alone, you cannot find it.

A real detection:

@acme/admin-web ↔ @acme/doctor-web   33% coupling, 91 co-changes, no dependency

Running dowse why on that pair showed server-api.ts and the auth pages existing in near-identical form in both, changed together by commits like "add re-login prompt on session expiry to all three surfaces". Not a shared abstraction — copied code.

3. It checks whether change frequency is real

A git line diff cannot tell you whether the meaning changed. Renaming an identifier, reformatting, or editing comments all look like large diffs and inflate change frequency. CodeScene itself lists "renaming a type inflates churn" as a known weakness.

dowse compares the AST of each revision to identify changes that did not alter meaning. Measured on a real repository: of 568 revisions across the top 20 hotspots, 55 (9.7%) were false churn, and the worst file was 42% inflated.

4. It publishes how every score is derived

CodeScene's Code Health keeps its formulas, thresholds, and weights closed. You cannot reproduce it, verify it, or tune it.

dowse publishes all of it.

health = 10 − Σ(weight × severity)

And it shows which smell cost how many points, down to the function name and line number. Meaning: you can recompute it by hand.

It also prints the score you would get from lines of code alone. If the two are close, that health score is just file length wearing a costume — and you should be able to see that for yourself.

5. It fixes, then measures

Advice alone never tells you whether it helped. dowse applies the change, verifies it with your type checker and tests, and reports how much the complexity actually moved.

packages/cli/src/analyze.ts
  cognitive -41 / cyclomatic -22 / LoC -111
  typecheck ✓  tests ✓   $1.86

The claim "this was the highest-ROI fix" is then a measurement, not a prediction.

What dowse is not for

  • Multi-language codebases. It is all-in on TS/TSX. For breadth, use CodeScene.
  • Repositories with no or shallow git history. Change frequency cannot be computed, so half the tool does nothing. In CI, fetch-depth: 0 is mandatory.
  • Evaluating people. Bus factor and ownership are risk indicators for a team. Do not use them as a performance review. Tornhill gives the same warning.

Next

Released under the MIT License