Software metrics for research code
Quality talk stays opinion until something is measured. A cluster
of the community research software quality indicators is explicitly
quantitative - complexity, duplication, cohesion/coupling, churn,
maintainability index, size and documentation coverage "within
community conventions" - and all of it is measurable in minutes
with free tools. The discipline is in the interpretation: metrics
LOCATE problems, humans judge them; a number out of convention is
a place to look, not a verdict. And Goodhart's law is the standing
hazard - when a metric becomes a target, it stops measuring
(the gaming section below is as important as the tools).
The metrics and what they actually indicate
- Cyclomatic complexity (independent paths per function): high
values mean hard-to-test, hard-to-reason code; each point is
roughly one more test case needed (rseng-testing). Look at the
per-function outliers, never the average.
- Duplication ratio: copy-pasted blocks that must be fixed twice;
research code's most common debt (the "second copy-paste" signal
from rseng-software-design's extraction rule, made measurable).
- Coupling and cohesion: how tangled modules are (CBO-style
counts) and how single-purpose they are internally - the
quantitative face of rseng-software-design's change-cost test.
- Code churn (change frequency per file): files that change
constantly are either active development or a design hotspot;
churn x complexity is the best bug-risk locator in the set.
- Maintainability index: a composite; useful for trend and
worst-file ranking, meaningless as an absolute grade.
- Size conventions (LOC per function/module): long functions
correlate with everything bad; community conventions vary by
language (rseng-language-guides).
- Documentation coverage: fraction of public functions/classes
with docstrings (interrogate-style) - the measurable slice of
rseng-documentation, and an explicit quality indicator.
Measuring: the tool layer
- Python: radon (complexity, maintainability index, raw metrics),
interrogate (docstring coverage); lizard covers complexity
across a dozen languages (C/C++, Java, JS, Fortran-adjacent
stacks) with no setup.
- Duplication: jscpd scans mixed-language repositories quickly.
- Churn: git itself (
git log --format= --name-only | sort | uniq -c) - no tool needed; join with complexity for the
hotspot map.
- Platform-scale: SonarQube-class services aggregate all of the
above with history when a team wants dashboards; overkill for a
single analysis repo (match the tier).
Run measurements read-only first and report: worst five functions
by complexity, duplication clusters, hotspot files (churn x
complexity), doc-coverage percentage - with file:line locations
so every number is actionable.
Interpreting against conventions and tier
"Community conventions" is the catalog phrasing for a reason -
absolute thresholds are folklore, but working defaults exist:
complexity warnings commonly start around 10 per function,
duplication tolerance a few percent, doc coverage expectations
scale with audience. Calibrate by tier (rseng-quality-framework):
analysis code earns attention only for egregious outliers;
shared libraries justify gates; infrastructure justifies trend
tracking. State the convention being applied and why - an
unexplained threshold is just a different opinion.
Gates and trends in CI
- Ratchet, do not ambush: set gates at the CURRENT values so
metrics cannot regress, then tighten deliberately - a strict
gate on a legacy codebase blocks all work and gets disabled
within a week (the same start-where-you-are rule as
rseng-fairguard's quality gates).
- Fail on new debt only where possible (changed-files scope), and
keep the full-repo numbers as a tracked report, not a blocker
(rseng-ci-cd).
- Trends beat snapshots: rising churn in a complex module is a
refactoring signal (rseng-legacy-code, rseng-software-design)
worth an issue, even when every absolute number still passes.
Metric gaming, named
Every metric can be satisfied without improving anything:
splitting functions mechanically to duck a complexity gate,
deleting docstring checks instead of writing docstrings,
suppressing duplication detection with trivial edits. Flag the
pattern when reviewing (rseng-pair-programming's pre-review pass),
and keep metrics plural - a basket is harder to game than a
single number. The metric serves the change-cost reality, never
the reverse; when a metric and good judgment disagree, judgment
wins and the exception gets a comment.
Working with this skill
This skill is source-independent: its authority is the tool
documentation and the published indicator definitions linked below.
It supplies the quantitative half of rseng-quality-framework
assessments; rseng-code-quality owns style and linting,
rseng-performance-profiling owns runtime measurement.
Learn more (verified):
Related skills
Check whether any of these applies before moving on:
- rseng-community-metrics - project-level counterpart to code metrics
- rseng-documentation - doc-coverage is its measurable slice
- rseng-legacy-code - hotspot map targets refactoring
- rseng-maintenance-sustainability - trend tracking signals sustainability risk
- rseng-quality-framework - supplies the quantitative half of assessments
- rseng-software-design - coupling numbers test the design
1---2name: rseng-software-metrics3description: Covers measuring code health quantitatively: cyclomatic complexity, code duplication, coupling and cohesion, code churn, maintainability index, size conventions and documentation coverage - running radon, lizard, jscpd, interrogate and SonarQube-class tools, interpreting numbers against community conventions and the software's tier, wiring metric gates into CI, and avoiding metric gaming. Use when the user asks how healthy, complex or maintainable their code is, wants metrics or duplication measured, mentions cyclomatic complexity, churn, coupling or maintainability index, or when a quality assessment (rseng-quality-framework) needs the quantitative half. For style and linting see rseng-code-quality; for runtime performance measurement see rseng-performance-profiling.4license: CC-BY-4.05---67# Software metrics for research code89Quality talk stays opinion until something is measured. A cluster10of the community research software quality indicators is explicitly11quantitative - complexity, duplication, cohesion/coupling, churn,12maintainability index, size and documentation coverage "within13community conventions" - and all of it is measurable in minutes14with free tools. The discipline is in the interpretation: metrics15LOCATE problems, humans judge them; a number out of convention is16a place to look, not a verdict. And Goodhart's law is the standing17hazard - when a metric becomes a target, it stops measuring18(the gaming section below is as important as the tools).1920## The metrics and what they actually indicate2122- Cyclomatic complexity (independent paths per function): high23 values mean hard-to-test, hard-to-reason code; each point is24 roughly one more test case needed (rseng-testing). Look at the25 per-function outliers, never the average.26- Duplication ratio: copy-pasted blocks that must be fixed twice;27 research code's most common debt (the "second copy-paste" signal28 from rseng-software-design's extraction rule, made measurable).29- Coupling and cohesion: how tangled modules are (CBO-style30 counts) and how single-purpose they are internally - the31 quantitative face of rseng-software-design's change-cost test.32- Code churn (change frequency per file): files that change33 constantly are either active development or a design hotspot;34 churn x complexity is the best bug-risk locator in the set.35- Maintainability index: a composite; useful for trend and36 worst-file ranking, meaningless as an absolute grade.37- Size conventions (LOC per function/module): long functions38 correlate with everything bad; community conventions vary by39 language (rseng-language-guides).40- Documentation coverage: fraction of public functions/classes41 with docstrings (interrogate-style) - the measurable slice of42 rseng-documentation, and an explicit quality indicator.4344## Measuring: the tool layer4546- Python: radon (complexity, maintainability index, raw metrics),47 interrogate (docstring coverage); lizard covers complexity48 across a dozen languages (C/C++, Java, JS, Fortran-adjacent49 stacks) with no setup.50- Duplication: jscpd scans mixed-language repositories quickly.51- Churn: git itself (`git log --format= --name-only | sort |52 uniq -c`) - no tool needed; join with complexity for the53 hotspot map.54- Platform-scale: SonarQube-class services aggregate all of the55 above with history when a team wants dashboards; overkill for a56 single analysis repo (match the tier).5758Run measurements read-only first and report: worst five functions59by complexity, duplication clusters, hotspot files (churn x60complexity), doc-coverage percentage - with file:line locations61so every number is actionable.6263## Interpreting against conventions and tier6465"Community conventions" is the catalog phrasing for a reason -66absolute thresholds are folklore, but working defaults exist:67complexity warnings commonly start around 10 per function,68duplication tolerance a few percent, doc coverage expectations69scale with audience. Calibrate by tier (rseng-quality-framework):70analysis code earns attention only for egregious outliers;71shared libraries justify gates; infrastructure justifies trend72tracking. State the convention being applied and why - an73unexplained threshold is just a different opinion.7475## Gates and trends in CI7677- Ratchet, do not ambush: set gates at the CURRENT values so78 metrics cannot regress, then tighten deliberately - a strict79 gate on a legacy codebase blocks all work and gets disabled80 within a week (the same start-where-you-are rule as81 rseng-fairguard's quality gates).82- Fail on new debt only where possible (changed-files scope), and83 keep the full-repo numbers as a tracked report, not a blocker84 (rseng-ci-cd).85- Trends beat snapshots: rising churn in a complex module is a86 refactoring signal (rseng-legacy-code, rseng-software-design)87 worth an issue, even when every absolute number still passes.8889## Metric gaming, named9091Every metric can be satisfied without improving anything:92splitting functions mechanically to duck a complexity gate,93deleting docstring checks instead of writing docstrings,94suppressing duplication detection with trivial edits. Flag the95pattern when reviewing (rseng-pair-programming's pre-review pass),96and keep metrics plural - a basket is harder to game than a97single number. The metric serves the change-cost reality, never98the reverse; when a metric and good judgment disagree, judgment99wins and the exception gets a comment.100101## Working with this skill102103This skill is source-independent: its authority is the tool104documentation and the published indicator definitions linked below.105It supplies the quantitative half of rseng-quality-framework106assessments; rseng-code-quality owns style and linting,107rseng-performance-profiling owns runtime measurement.108109Learn more (verified):110 - https://radon.readthedocs.io - radon (Python complexity and111 maintainability)112 - https://github.com/terryyin/lizard - lizard multi-language113 complexity114 - https://github.com/kucherenko/jscpd - jscpd duplication115 detection116 - https://interrogate.readthedocs.io - interrogate docstring117 coverage118119<!-- related-skills:begin -->120121## Related skills122123Check whether any of these applies before moving on:124125- rseng-community-metrics - project-level counterpart to code metrics126- rseng-documentation - doc-coverage is its measurable slice127- rseng-legacy-code - hotspot map targets refactoring128- rseng-maintenance-sustainability - trend tracking signals sustainability risk129- rseng-quality-framework - supplies the quantitative half of assessments130- rseng-software-design - coupling numbers test the design131132<!-- related-skills:end -->