croc's core transfer layer carries the highest activity risk — 5 functions to address first

croc's file-transfer core in src/croc/croc.go and src/cli/cli.go dominates risk, with four fire-quadrant god functions actively changing at the highest complexity in the codebase.

Stephen Collins ·
oss go refactoring code-health

Antipatterns Detected

god_function10long_function9exit_heavy8deeply_nested4complex_branching4neighbor_risk1

Key Points

What is a god function and why does it matter in croc?

A god function is one that has accumulated so many responsibilities that it becomes the single point of coordination for a broad slice of the system — in croc, 10 of the top hotspot functions carry this pattern, most prominently `Send` in croc.go with 50 outbound calls. The problem is coupling: when one function touches that many other parts of the codebase, any change to it — even a small one — can have unintended ripple effects far from the edit site. It also makes the function nearly impossible to unit-test in isolation, because its behavior depends on the behavior of dozens of collaborators.

How do I reduce fan-out in Go?

Introduce intermediate coordinator types or service structs that group related collaborators behind a single interface, so the high-fan-out function delegates to a small set of well-defined collaborators rather than calling 40–50 disparate functions directly; this also makes the function's dependencies explicit and injectable for testing.

Is croc actively maintained?

The data strongly suggests yes: four of the five top-risk functions — `Send`, `send`, `receive`, and `Receive` — are in the fire quadrant, meaning they combine high structural complexity with high recent commit activity, which hotspots only assigns when a function is genuinely being modified in recent history. The top function's recent commit activity of 16.37 is the highest in the dataset, indicating sustained attention to the core transfer logic.

How do I reproduce this analysis?

Run the hotspots CLI against the schollz/croc repository at commit 9a3d42a to reproduce the scores and quadrant assignments shown here.

What does activity-weighted risk mean?

Complexity × recent commit frequency — functions that are hard to understand AND actively changing are the highest priority for refactoring.

croc, the peer-to-peer file transfer tool, has 33 critical-band functions out of 161 total — and its four highest-risk hotspots are all in the ‘fire’ quadrant, meaning they combine structural complexity with active recent commit churn. The top-ranked function, Send in src/croc/croc.go, carries a recent commit activity of 16.37 and a fan-out of 50, making every change to it a potential ripple across half the codebase. These aren’t cleanup candidates sitting in a backlog — they are live regression surfaces being modified today.

The table below ranks functions by activity-weighted risk — a score that multiplies structural complexity by recent commit frequency. A function that is both hard to understand (high cyclomatic complexity) and actively changing is a higher priority than one that is complex but untouched. CC = cyclomatic complexity (independent execution paths); ND = max nesting depth; FO = fan-out (distinct callees).

Top 5 Hotspots

FunctionFileRiskCCNDFO
Sendsrc/croc/croc.go17.28750
sendsrc/cli/cli.go16.212440
receivesrc/cli/cli.go15.415332
Receivesrc/croc/croc.go15.212443
processMessageFileInfosrc/croc/croc.go14.610523

Hotspot Analysis

Send — src/croc/croc.go

As the core library-level entry point for initiating a file transfer, Send is almost certainly responsible for orchestrating the entire outbound transfer lifecycle — connection setup, file preparation, relay negotiation, and progress reporting. Its fan-out of 50 is the highest in the dataset, meaning it directly invokes 50 distinct functions, giving it an enormous blast radius: a signature change or behavioral shift here propagates across virtually the entire codebase. A max nesting depth of 7 signals deeply layered conditional logic that is hard to reason about in isolation, and with a recent commit activity of 16.37 in the fire quadrant, this function is being actively modified while already carrying that structural load — a textbook live regression risk. The god_function and long_function patterns confirm it is doing far more than any single function should.

Recommendation: Before the next commit touches Send, write characterization tests that capture its current input/output behavior across transfer scenarios; then begin extracting sub-responsibilities — connection orchestration, file chunking coordination, and progress lifecycle — into dedicated functions to reduce the fan-out from 50 toward something reviewable.

send — src/cli/cli.go

The lowercase send in src/cli/cli.go is the CLI-layer counterpart to the library’s Send — it likely parses user flags, validates arguments, builds the options struct, and delegates to the library. Its cyclomatic complexity of 12 means there are at least 12 independent execution paths through its branching logic, each a required test case, and its fan-out of 40 shows it reaches broadly into the codebase despite being a CLI entry point. The neighbor_risk pattern is a notable flag here: changes to send in cli.go are correlated with required edits in adjacent code, meaning a focused change here tends to become a wider, coordinated edit. With a recent commit activity of 14.31 in the fire quadrant, this function is actively changing under those conditions right now.

Recommendation: Decompose the 12-path branching logic by extracting flag validation and options construction into separate, independently testable functions; address the neighbor_risk signal by auditing which adjacent functions in cli.go are most frequently co-edited with send and consider co-locating shared logic.

receive — src/cli/cli.go

The receive function in src/cli/cli.go is the CLI entry point for inbound file transfers, and at a cyclomatic complexity of 15 it is the most branch-heavy of the CLI-layer functions — 15 independent execution paths representing every combination of flags, error conditions, and user prompts the receiver must handle. Its fan-out of 32 shows it still reaches broadly across the codebase, and the exit_heavy pattern indicates multiple return paths that are each a gap in test coverage. In the fire quadrant with a recent commit activity of 13.63, it is actively being changed at a complexity level that makes each edit risky to get right.

Recommendation: Use the CC of 15 as a decomposition target: identify the dominant branching axes — likely overwrite prompts, relay selection, and password handling based on what a CLI receiver must do — and extract each into a named function so that individual paths can be unit-tested in isolation.

Receive — src/croc/croc.go

Receive is the library-level entry point for inbound file transfers — the counterpart to the CLI’s receive in cli.go. Its fan-out of 43 is second only to Send in this dataset, meaning it reaches into 43 distinct functions to coordinate the receiving side of a transfer: relay negotiation, decryption, file assembly, and progress handling. A cyclomatic complexity of 12 adds at least 12 independent execution paths through its branching logic, and those two factors together earn it the god_function label. Unlike its CLI counterpart, Receive operates at the library layer where callers outside croc’s own CLI can invoke it directly, making its interface harder to change safely. At Risk 15.2 in the fire quadrant, it is under active change pressure right now.

Recommendation: Audit Receive’s 43 callees and group them by responsibility — relay setup, cryptographic handshake, file I/O, and progress reporting are likely natural seams. Extracting each group into a dedicated coordinator function reduces fan-out to a reviewable number and makes the inbound transfer lifecycle readable at a glance.

processMessageFileInfo — src/croc/croc.go

processMessageFileInfo is the one debt-quadrant function in the top five: its Risk score of 14.6 reflects structural weight rather than recent churn, meaning it is complex but not currently under heavy modification. A nesting depth of 5 signals layered conditional logic — likely parsing and validating the file metadata messages exchanged during a transfer — and a fan-out of 23 combined with a cyclomatic complexity of 10 means any future edit to this function must navigate significant branching and callee coupling. Debt-quadrant functions are lower urgency than fire-quadrant ones, but they become live risks the moment a new feature or protocol change forces a modification.

Recommendation: Before the next change to the file-info message protocol touches this function, extract the validation logic for each metadata field into a named helper — this reduces both the CC and the nesting depth, and leaves the function as a thin dispatcher that is straightforward to follow when the next change arrives.

Patterns Found

Antipatterns detected across the top functions in this snapshot:

PatternOccurrences
god_function10
long_function9
exit_heavy8
deeply_nested4
complex_branching4
neighbor_risk1

These labels belong to two tiers — Tier 1 (structural): complex_branching, deeply_nested, exit_heavy, long_function, god_function. Tier 2 (relational/temporal): hub_function, cyclic_hub, middle_man, neighbor_risk, stale_complex, churn_magnet, shotgun_target, volatile_god.

Key Takeaways

  • Send in src/croc/croc.go has a fan-out of 50 and is in the fire quadrant — add characterization tests before any further modifications to contain blast radius.
  • The receive function in src/cli/cli.go has the highest cyclomatic complexity of the top hotspots at 15, meaning at minimum 15 test cases are needed to cover its branches; audit current test coverage against that number.
  • processMessageFileInfo in src/croc/croc.go is the one debt-quadrant function in the top five — it hasn’t been under recent pressure, but its nesting depth of 5 and fan-out of 23 mean it carries high blast radius when next touched; treat it as a refactoring prerequisite before the next feature push into croc.go.

Reproduce This Analysis

git clone https://github.com/schollz/croc
cd croc
git checkout 9a3d42ae7d4eecbf99266dafb79330e5774f81f3
hotspots analyze . --mode snapshot --explain-patterns --force

To run the same analysis on your own codebase, run hotspots analyze . --mode snapshot in any local git repo — no configuration required.

Hotspots highlights structural and activity risk — not “bad code.” Findings are a prioritization aid, not a bug predictor. Editorial policy →

Run this on your own codebase

Hotspots runs locally in under a minute — no account, no data leaves your machine.

macOS
$ brew install Stephen-Collins-tech/tap/hotspots
Linux / cargo
$ cargo install hotspots-cli
Run in any repo
$ hotspots analyze .
★ Star on GitHub

Related Analyses