[Tech debt] SonarQube S3776: reduce cognitive complexity (~51 backend methods) #244

Open
opened 2026-06-19 18:44:40 +00:00 by spikerj · 4 comments
Owner

Surfaced by SonarQube (api.spikersoft.com), rule csharpsquid:S3776, severity CRITICAL (MAINTAINABILITY). ~51 methods exceed the cognitive-complexity limit of 15.

Worst offenders (complexity)

  • SpikerSoft.Api/Infrastructure/HealthChecks/SpfHealthCheck.cs:22472
  • SpikerSoft.Business/Domain/Lessons/Validation/LessonValidator.cs:3862
  • SpikerSoft.Api/Infrastructure/HealthChecks/DmarcHealthCheck.cs:23161
  • SpikerSoft.Data/Contexts/SpikerDbContext.cs~14 methods (45, 36, 33, 30×4, 24, 18×2, 16×2…)
  • SpikerSoft.EventHandlers.Embeddings/Services/TextChunkingService.cs:2143
  • SpikerSoft.Data/Repositories/InfluxMetricsRepository.cs — 35, 21
  • HexTowerDefence game managers (Economy 30, Combat/Waves 26/20), GameServer zones, code-execution executors, customer command handlers, etc.

(Full list of 51 available via SonarQube; api.spikersoft.com → rule csharpsquid:S3776.)

Suggested approach

Tackle highest-complexity first (SPF/DMARC health checks, LessonValidator, SpikerDbContext model-building). Extract helper methods, replace nested conditionals with guard clauses / lookup tables. Treat as an ongoing epic — close incrementally.

Rule: https://rules.sonarsource.com/csharp/RSPEC-3776/

Surfaced by SonarQube (`api.spikersoft.com`), rule `csharpsquid:S3776`, severity CRITICAL (MAINTAINABILITY). ~51 methods exceed the cognitive-complexity limit of 15. ## Worst offenders (complexity) - `SpikerSoft.Api/Infrastructure/HealthChecks/SpfHealthCheck.cs:224` — **72** - `SpikerSoft.Business/Domain/Lessons/Validation/LessonValidator.cs:38` — **62** - `SpikerSoft.Api/Infrastructure/HealthChecks/DmarcHealthCheck.cs:231` — **61** - `SpikerSoft.Data/Contexts/SpikerDbContext.cs` — **~14 methods** (45, 36, 33, 30×4, 24, 18×2, 16×2…) - `SpikerSoft.EventHandlers.Embeddings/Services/TextChunkingService.cs:21` — **43** - `SpikerSoft.Data/Repositories/InfluxMetricsRepository.cs` — 35, 21 - HexTowerDefence game managers (Economy 30, Combat/Waves 26/20), GameServer zones, code-execution executors, customer command handlers, etc. (Full list of 51 available via SonarQube; `api.spikersoft.com` → rule `csharpsquid:S3776`.) ## Suggested approach Tackle highest-complexity first (SPF/DMARC health checks, LessonValidator, SpikerDbContext model-building). Extract helper methods, replace nested conditionals with guard clauses / lookup tables. Treat as an ongoing epic — close incrementally. _Rule: https://rules.sonarsource.com/csharp/RSPEC-3776/_
spikerj added the sonarqube label 2026-06-19 18:44:40 +00:00
Author
Owner

First pass opened as spikersoft-backend PR #13 — the three highest-complexity methods, refactored with extracted helpers (no behaviour change; all healthData keys/values and validation messages preserved):

  • SpfHealthCheck.ValidateSpfRecord72
  • LessonValidator.ValidateLesson62
  • DmarcHealthCheck.ValidateDmarcRecord61

Still open for follow-up passes: SpikerDbContext model-building (~14 methods), TextChunkingService (43), InfluxMetricsRepository (35, 21), HexTowerDefence game managers, GameServer zones, code-execution executors, customer command handlers, etc.

First pass opened as spikersoft-backend PR #13 — the three highest-complexity methods, refactored with extracted helpers (no behaviour change; all healthData keys/values and validation messages preserved): - [x] `SpfHealthCheck.ValidateSpfRecord` — **72** - [x] `LessonValidator.ValidateLesson` — **62** - [x] `DmarcHealthCheck.ValidateDmarcRecord` — **61** Still open for follow-up passes: `SpikerDbContext` model-building (~14 methods), `TextChunkingService` (43), `InfluxMetricsRepository` (35, 21), HexTowerDefence game managers, GameServer zones, code-execution executors, customer command handlers, etc.
Author
Owner

Two more offenders added to PR #13 (no behaviour change; all log messages + metric mappings preserved, 53 chunking/influx tests pass):

  • TextChunkingService.ChunkText43
  • InfluxMetricsRepository.StreamMetricsAsync35
  • InfluxMetricsRepository.QueryMetricsBatchAsync21

PR #13 now covers the 6 highest-complexity methods. Still open: SpikerDbContext model-building (~14 methods), game managers, GameServer zones, code-execution executors, customer command handlers, etc.

Two more offenders added to PR #13 (no behaviour change; all log messages + metric mappings preserved, 53 chunking/influx tests pass): - [x] `TextChunkingService.ChunkText` — **43** - [x] `InfluxMetricsRepository.StreamMetricsAsync` — **35** - [x] `InfluxMetricsRepository.QueryMetricsBatchAsync` — **21** PR #13 now covers the 6 highest-complexity methods. Still open: `SpikerDbContext` model-building (~14 methods), game managers, GameServer zones, code-execution executors, customer command handlers, etc.
Author
Owner

Progress update:

  • PR #13 (merged) — 6 highest-complexity methods: SpfHealthCheck.ValidateSpfRecord (72), DmarcHealthCheck.ValidateDmarcRecord (61), LessonValidator.ValidateLesson (62), TextChunkingService.ChunkText (43), InfluxMetricsRepository.StreamMetricsAsync (35) + QueryMetricsBatchAsync (21).
  • PR #14 (open)HexTowerDefenceGameManager partials: FireBuildings (26), RunResourceCycle (30), SpawnWave (20). 17 HexTowerDefence unit tests pass.

SpikerDbContext.OnModelCreating — deferred from the mechanical pass. It's already decomposed into ~40 ConfigureXxx methods; the residual S3776 is repeated HasConversion + ValueComparer boilerplate with many subtly different variants (SequenceEqual vs Count equality; null→null vs null→empty-list snapshots; guarded vs unguarded (de)serialization; nullable vs non-nullable comparer types). A one-size helper would silently change EF change-tracking/serialization null semantics, and there is no integration-level coverage to catch it. It needs its own focused PR with exact-match helper overloads + round-trip tests, not a blanket extract.

Still open under this epic: SpikerDbContext (as above), GameServer zones, code-execution executors, customer command handlers, and other smaller offenders.

Progress update: - **PR #13 (merged)** — 6 highest-complexity methods: `SpfHealthCheck.ValidateSpfRecord` (72), `DmarcHealthCheck.ValidateDmarcRecord` (61), `LessonValidator.ValidateLesson` (62), `TextChunkingService.ChunkText` (43), `InfluxMetricsRepository.StreamMetricsAsync` (35) + `QueryMetricsBatchAsync` (21). - **PR #14 (open)** — `HexTowerDefenceGameManager` partials: `FireBuildings` (26), `RunResourceCycle` (30), `SpawnWave` (20). 17 HexTowerDefence unit tests pass. **`SpikerDbContext.OnModelCreating` — deferred from the mechanical pass.** It's already decomposed into ~40 `ConfigureXxx` methods; the residual S3776 is repeated `HasConversion` + `ValueComparer` boilerplate with many *subtly different* variants (SequenceEqual vs Count equality; null→null vs null→empty-list snapshots; guarded vs unguarded (de)serialization; nullable vs non-nullable comparer types). A one-size helper would silently change EF change-tracking/serialization null semantics, and there is no integration-level coverage to catch it. It needs its own focused PR with exact-match helper overloads + round-trip tests, not a blanket extract. **Still open under this epic:** SpikerDbContext (as above), GameServer zones, code-execution executors, customer command handlers, and other smaller offenders.
Author
Owner

Progress (safe extract-method pass continued):

  • PR #15 (open)ZoneManager handlers: HandleCreateCharacterCommand, HandleLandOnPlanetCommand, HandleLaunchFromPlanetCommand split into focused validation/context/build helpers. 76 ZoneManager unit tests pass. Note: ProcessCommandAsync is a type-switch dispatcher (low cognitive complexity, not an offender) and was intentionally left alone.

Still open under this epic: code-execution executors, customer command handlers, GameServer zones (remaining), other smaller offenders, and SpikerDbContext EF boilerplate (deferred — see earlier note; needs exact-match helpers + round-trip tests).

Progress (safe extract-method pass continued): - **PR #15 (open)** — `ZoneManager` handlers: `HandleCreateCharacterCommand`, `HandleLandOnPlanetCommand`, `HandleLaunchFromPlanetCommand` split into focused validation/context/build helpers. 76 ZoneManager unit tests pass. Note: `ProcessCommandAsync` is a type-switch dispatcher (low cognitive complexity, not an offender) and was intentionally left alone. **Still open under this epic:** code-execution executors, customer command handlers, GameServer zones (remaining), other smaller offenders, and `SpikerDbContext` EF boilerplate (deferred — see earlier note; needs exact-match helpers + round-trip tests).
Sign in to join this conversation.