Bearing · free and open source · Apache 2.0

Do you understand your system?

Not is it healthy — that’s a different question, well served by other tools, for specialists. Bearing answers the one people ask right before they change something.

$ dotnet tool install -g IronMarten.Bearing
$ bearing ./MySolution.sln

Zero configuration. No account. No network call.

A map, and a short list

Bearing reads a .NET solution and gives you two things: a map of the system, and a short list of the components that are unusual for what they are.

Who it’s for

A developer who needs to reason about a .NET codebase they don’t hold entirely in their head — because it’s large, because they’re new to it, or because they’re about to change something in it.

Why it’s called Bearing

Two meanings: get your bearings in a system too big to hold in your head, and the load-bearing components you should be careful with.

What you get

A terminal report that opens with one claim per kind of risk the run found, then describes the structure. Everything else is a flag, and nothing is written unless you ask for it.

The terminal report. Every claim shows the numbers behind it.
--html — one shareable page, self-contained, no network.
--diagram — the project map, sized for pasting into chat.
--mosaic — every type as one cell.
--plot — projects by reach and density.

And the whole model as data: --json — every finding, versioned — and --csv — types, members and edges. bearing --help lists every flag and every threshold the report cites, each with its default.

What it names

On nopCommerce, Bearing names roughly one type in eight — 592 findings across 12 kinds — and has nothing to say about the other seven, which is itself a statement about where not to look.

  • Circular references

    Namespace cycles, project cycles and type tangles — the components that hold each other, so neither can be layered, understood or extracted without the other. Named, with the references that close the loop.

  • No static references found

    Methods and types nothing in the solution refers to. It’s the dead-code question, labelled “verify before deleting”, because a static analysis can’t see every caller and says so.

  • Load-bearing and intricate

    Many things depend on it, and it’s complex enough to hide a bug. Hard to change safely.

  • Bug blast radius

    Widely depended on and internally complex: a bug here propagates.

  • Concealed decision

    Complexity far above its peers while its connections are ordinary — something that looks like plumbing and isn’t.

  • Hub or god object

    It depends on, and is depended on by, much of the system.

  • Spans architectural layers

    Dependencies reaching across three or more architectural kinds — cross-cutting work, whatever the component is named.

  • Shared mutable state

    Writes to static mutable state that every caller, on every thread, shares. Whether it’s contended is a runtime question; the sharing is certain from the code.

How it reports

Five rules every report follows.

  • Findings are sentences, not scores.

    A finding is relative to the peer group a component should resemble. “Top 2% of your 56 normalizers” is a claim you can check; “Risk score 103,680” is one you can only argue with.

    It never says “instability 0.296”. It says “19 things depend on this; it depends on 8 concrete types.”

  • There is no composite score.

    Not on a dashboard, not in a tooltip, not as a CSV column. A deliberate, permanent constraint.

  • Silence is never a clean bill of health.

    Every report says what it stayed quiet about — components with no peers, excluded generated code, projects that failed to load.

  • Name the specifics.

    “Spans 3 architectural kinds” is arguable; “why is authentication calling TenantStore?” is not.

  • A finding you’ve decided about stays decided.

    Acknowledge it in a committed file, with a reason, and the next run tells you what is new.

Stable from 1.0

The output is a contract. A breaking change to the command line, the acknowledgment file, the JSON or the CSV is a new major version.

Validated against nopCommerce, Jellyfin and Umbraco. Every threshold it cites was set by measurement on those, not chosen.

Requirements

The .NET 10 SDK. A solution that targets net8.0 or net9.0 is analysed as it is — it doesn’t need to move. Restore the solution first.

What it will never do

  • Observe runtime or traffic.
  • Give a composite score or a grade.
  • Generate explanations with AI. Findings are deterministic and auditable.

When you want it continuously

Bearing tells you what your system looks like today. Bearing Pro keeps that true for a team: history, pull-request comments that name only what a change introduced, and decisions that stay decided — self-hosted.

See Bearing Pro