Files
natsnet/docs/plans/phases/phase-4-dotnet-design.md
Joseph Doherty 6021d8445e docs: link completion criteria to Gitea issues and add issue tracking guidance
- Created 52 Gitea issues across milestones 1-7, one per completion criterion
- Each criterion now links to its corresponding issue ([#N](url) format)
- Milestone Tracking sections updated with Issue Updates subsection:
  when/how to comment, close issues via CLI or web UI
- Phases 4-7 criteria converted from plain bullets to checkbox format
2026-02-26 06:50:08 -05:00

9.6 KiB

Phase 4: .NET Solution Design

Design the target .NET 10 solution structure and map every Go item to its .NET counterpart. This phase translates the Go codebase decomposition (from Phases 1-2) and library mappings (from Phase 3) into a concrete .NET implementation plan.

Objective

Every module, feature, and test in the porting database must have either a .NET mapping (project, namespace, class, method) or a justified N/A status. The result is a complete blueprint for the porting work in Phase 6.

Prerequisites

  • Phases 1-3 complete: all Go items in the DB, all libraries mapped
  • Verify with: dotnet run --project tools/NatsNet.PortTracker -- report summary --db porting.db

Source and Target Locations

  • Go source code is located in the golang/ folder (specifically golang/nats-server/)
  • .NET ported version is located in the dotnet/ folder

Milestone Tracking

This phase corresponds to Milestone 4 in Gitea. When starting this phase, verify the milestone is open. Assign relevant issues to this milestone as work progresses.

Issue Updates

Each completion criterion has a corresponding Gitea issue. Update issues as you work:

  • Starting a criterion: Add a comment noting work has begun
  • Blocked: Add a comment describing the blocker
  • Complete: Close the issue with a comment summarizing the result (e.g., counts, verification output)

Close issues via CLI:

curl -s -X PATCH "https://gitea.dohertylan.com/api/v1/repos/dohertj2/natsnet/issues/{N}" \
  -H "Content-Type: application/json" \
  -H "Authorization: token $GITEA_TOKEN" \
  -d '{"state":"closed"}'

Or close via the Gitea web UI.

Solution Structure

Define the .NET solution layout following standard conventions:

dotnet/
  ZB.MOM.NatsNet.sln
  src/
    ZB.MOM.NatsNet.Server/                    # Main server library (all core logic)
      Protocol/                     # Wire protocol parsing, commands
      Subscriptions/                # SubList trie, subject matching
      JetStream/                    # Stream management, consumers
      Cluster/                      # Routes, gateways, leaf nodes
      Auth/                         # Authentication, accounts, JWT
      ...
    ZB.MOM.NatsNet.Server.Host/               # Host/entry point (Program.cs, DI, config)

  tests/
    ZB.MOM.NatsNet.Server.Tests/              # Unit tests for ZB.MOM.NatsNet.Server
      Protocol/
      Subscriptions/
      JetStream/
      ...
    ZB.MOM.NatsNet.Server.IntegrationTests/   # Cross-module and end-to-end tests

The ZB.MOM.NatsNet.Server project holds all portable logic. ZB.MOM.NatsNet.Server.Host is the thin entry point that wires up dependency injection, configuration, and hosting. Tests mirror the source structure.

Naming Conventions

Follow these rules consistently when mapping Go items to .NET:

Aspect Convention Example
Classes PascalCase NatsParser, SubList, JetStreamController
Methods PascalCase TryParse, Match, ProcessMessage
Namespaces ZB.MOM.NatsNet.Server.[Module] ZB.MOM.NatsNet.Server.Protocol, ZB.MOM.NatsNet.Server.Subscriptions
Test classes [ClassName]Tests NatsParserTests, SubListTests
Test methods [Method]_[Scenario]_[Expected] TryParse_ValidInput_ReturnsTrue
Interfaces I[Name] IMessageRouter, ISubListAccess
Projects ZB.MOM.NatsNet.Server[.Suffix] ZB.MOM.NatsNet.Server, ZB.MOM.NatsNet.Server.Host

Avoid abbreviations unless they are universally understood (e.g., TCP, TLS, JWT). Prefer descriptive names over short ones.

Steps

Step 1: Map modules

For each module in the database, assign a .NET project, namespace, and class. The --namespace and --class options are optional but recommended.

# List all modules to review
dotnet run --project tools/NatsNet.PortTracker -- module list --db porting.db

# Map a module to its .NET target
dotnet run --project tools/NatsNet.PortTracker -- module map <id> \
  --project "ZB.MOM.NatsNet.Server" \
  --namespace "ZB.MOM.NatsNet.Server.Protocol" \
  --class "NatsParser" \
  --db porting.db

Work through all modules systematically. Group related Go files into the same namespace:

Go package/file pattern .NET namespace
server/parser.go ZB.MOM.NatsNet.Server.Protocol
server/sublist.go ZB.MOM.NatsNet.Server.Subscriptions
server/jetstream*.go ZB.MOM.NatsNet.Server.JetStream
server/route.go, server/gateway.go ZB.MOM.NatsNet.Server.Cluster
server/auth.go, server/accounts.go ZB.MOM.NatsNet.Server.Auth
server/pse/ Likely N/A (Go-specific platform code)

Step 2: Map features

For each feature (function/method), assign the .NET class and method name:

# List features for a specific module
dotnet run --project tools/NatsNet.PortTracker -- feature list --module <module_id> --db porting.db

# Map a feature
dotnet run --project tools/NatsNet.PortTracker -- feature map <id> \
  --project "ZB.MOM.NatsNet.Server" \
  --class "NatsParser" \
  --method "TryParse" \
  --db porting.db

When mapping Go functions to .NET methods:

  • Go free functions become static methods or instance methods on the appropriate class
  • Go methods with receivers map to instance methods on the corresponding .NET class
  • Go init() functions typically map to static constructors or initialization in DI setup
  • Go goroutine launches map to Task-based async methods

Step 3: Map tests

For each test function, assign the .NET test class and method:

# List tests for a module
dotnet run --project tools/NatsNet.PortTracker -- test list --module <module_id> --db porting.db

# Map a test
dotnet run --project tools/NatsNet.PortTracker -- test map <id> \
  --project "ZB.MOM.NatsNet.Server.Tests" \
  --class "NatsParserTests" \
  --method "TryParse_ValidInput_ReturnsTrue" \
  --db porting.db

Go test naming (TestParserValid) translates to .NET naming (TryParse_ValidInput_ReturnsTrue). Each Go Test* function maps to one or more [Fact] or [Theory] methods. Table-driven Go tests often become [Theory] with [InlineData] or [MemberData].

Step 4: Mark N/A items

Some Go code has no .NET equivalent. Mark these with a clear reason:

# Mark a module as N/A
dotnet run --project tools/NatsNet.PortTracker -- module set-na <id> \
  --reason "Go-specific platform code, not needed in .NET" \
  --db porting.db

# Mark a feature as N/A
dotnet run --project tools/NatsNet.PortTracker -- feature set-na <id> \
  --reason "Go signal handling, replaced by .NET host lifecycle" \
  --db porting.db

Common N/A categories

Items that typically do not need a .NET port:

Go item Reason
pse_darwin.go, pse_linux.go, pse_windows.go Go-specific platform syscall wrappers; use .NET System.Diagnostics.Process instead
disk_avail_windows.go, disk_avail_linux.go Go-specific disk APIs; use .NET System.IO.DriveInfo instead
Custom logger (logger.go, log.go) Replaced by Serilog via ZB.MOM.NatsNet.Server.Host
Signal handling (signal.go) Replaced by .NET Generic Host IHostLifetime
Go sync.Pool, sync.Map wrappers .NET has ObjectPool<T>, ConcurrentDictionary<K,V> built-in
Build tags / _test.go helpers specific to Go test infra Replaced by xUnit attributes and test fixtures
go:embed directives Replaced by embedded resources or IFileProvider

Every N/A must include a reason. Bare N/A status without explanation is not acceptable.

Verification

After mapping all items, run a quick check:

# Count unmapped items (should be 0)
dotnet run --project tools/NatsNet.PortTracker -- report summary --db porting.db

# Review all modules — every row should show DotNet Project filled or status n_a
dotnet run --project tools/NatsNet.PortTracker -- module list --db porting.db

# Review N/A items to confirm they all have reasons
dotnet run --project tools/NatsNet.PortTracker -- module list --status n_a --db porting.db
dotnet run --project tools/NatsNet.PortTracker -- feature list --status n_a --db porting.db

Completion Criteria

  • #25 Every module has dotnet_project and dotnet_namespace set, or status is n_a with a reason
  • #26 Every feature has dotnet_project, dotnet_class, and dotnet_method set, or status is n_a with a reason
  • #27 Every test has dotnet_project, dotnet_class, and dotnet_method set, or status is n_a with a reason
  • #28 Naming follows PascalCase and the namespace hierarchy described above
  • #29 No two features map to the same class + method combination (collisions)
  • Close the Phase 4 milestone in Gitea:
    curl -s -X PATCH "https://gitea.dohertylan.com/api/v1/repos/dohertj2/natsnet/milestones/4" \
      -H "Content-Type: application/json" \
      -H "Authorization: token $GITEA_TOKEN" \
      -d '{"state":"closed"}'
    
    Or close it via the Gitea web UI at https://gitea.dohertylan.com/dohertj2/natsnet/milestone/4