Skip to content

Commit 4e4c19f

Browse files
authored
Document constructor naming conventions per semantic analysis (#818)
Semantic analysis identified inconsistent constructor patterns across the codebase and recommended documentation. Analysis also surfaced opportunities for file extraction (unified.go: 1032 lines, connection.go: 1009 lines) and RPC logger consolidation. ## Changes ### Constructor Naming Conventions (CONTRIBUTING.md) Documented three patterns with usage criteria and real examples: ```go // Simple object creation - no errors func NewConnection(ctx context.Context) *Connection // Factory with registry lookup or complex init func CreateGuard(name string) (Guard, error) // Global singleton initialization func InitFileLogger(dir string) error ``` Includes 35+ real examples from codebase and decision flow. ### Follow-up Work Items Created structured proposals for code refactorings (each ~4-6 hours): - **unified.go extraction** → 4 files: registration (~250L), session (~150L), tools (~200L), core (~400L) - **connection.go extraction** → 4 files: http (~350L), transport (~250L), tools (~200L), core (~200L) - **RPC logger consolidation** → `internal/logger/rpc/` subdirectory Each includes implementation plan, benefits, and context for future sessions with proper incremental testing. ## Rationale Semantic analysis marked refactorings as "optional enhancements." Delivered immediate value (documentation) and actionable future work (proposals) rather than rushing complex refactorings that require careful testing. > [!WARNING] > > <details> > <summary>Firewall rules blocked me from connecting to one or more addresses (expand for details)</summary> > > #### I tried to connect to the following addresses, but was blocked by firewall rules: > > - `example.com` > - Triggering command: `/tmp/go-build889290460/b275/launcher.test /tmp/go-build889290460/b275/launcher.test -test.testlogfile=/tmp/go-build889290460/b275/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true p=/opt/hostedtoolcache/go/1.25.6/x64=/_/GOROOT 6945474/b098/ x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet 6945�� submodules | head -n 10 6945474/b098/ x_amd64/vet /tmp/go-build409/opt/hostedtoolcache/go/1.25.6/x64/pkg/tool/linux_amd64/vet -imultiarch x86_64-linux-gnu-unreachable=false x_amd64/vet` (dns block) > - `invalid-host-that-does-not-exist-12345.com` > - Triggering command: `/tmp/go-build889290460/b260/config.test /tmp/go-build889290460/b260/config.test -test.testlogfile=/tmp/go-build889290460/b260/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true E=3 IBUTING.md Co-authored-by: lpcox &lt;15877973&#43;lpcox@users.noreply.github.com&gt; x_amd64/compile 6945474/b105/ --64 -o x_amd64/compile 6945�� is 6945474/b098/ x_amd64/vet -pthread -Wl,--no-gc-sect-unsafeptr=false -fmessage-length-unreachable=false x_amd64/vet` (dns block) > - `nonexistent.local` > - Triggering command: `/tmp/go-build889290460/b275/launcher.test /tmp/go-build889290460/b275/launcher.test -test.testlogfile=/tmp/go-build889290460/b275/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true p=/opt/hostedtoolcache/go/1.25.6/x64=/_/GOROOT 6945474/b098/ x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet 6945�� submodules | head -n 10 6945474/b098/ x_amd64/vet /tmp/go-build409/opt/hostedtoolcache/go/1.25.6/x64/pkg/tool/linux_amd64/vet -imultiarch x86_64-linux-gnu-unreachable=false x_amd64/vet` (dns block) > - `slow.example.com` > - Triggering command: `/tmp/go-build889290460/b275/launcher.test /tmp/go-build889290460/b275/launcher.test -test.testlogfile=/tmp/go-build889290460/b275/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true p=/opt/hostedtoolcache/go/1.25.6/x64=/_/GOROOT 6945474/b098/ x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet 6945�� submodules | head -n 10 6945474/b098/ x_amd64/vet /tmp/go-build409/opt/hostedtoolcache/go/1.25.6/x64/pkg/tool/linux_amd64/vet -imultiarch x86_64-linux-gnu-unreachable=false x_amd64/vet` (dns block) > - `this-host-does-not-exist-12345.com` > - Triggering command: `/tmp/go-build889290460/b284/mcp.test /tmp/go-build889290460/b284/mcp.test -test.testlogfile=/tmp/go-build889290460/b284/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true p=/opt/hostedtoolcache/go/1.25.6-p 6945474/b098/ x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet 6945�� 6945474/b182/_pkg_.a /opt/hostedtoolcache/go/1.25.6/x-c=4 x_amd64/vet /tmp/go-build409/opt/hostedtoolcache/go/1.25.6/x64/pkg/tool/linux_amd64/vet -imultiarch x86_64-linux-gnu-unreachable=false x_amd64/vet` (dns block) > > If you need me to access, download, or install something from one of these locations, you can either: > > - Configure [Actions setup steps](https://gh.io/copilot/actions-setup-steps) to set up my environment, which run before the firewall is enabled > - Add the appropriate URLs or hosts to the custom allowlist in this repository's [Copilot coding agent settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent) (admins only) > > </details> <!-- START COPILOT ORIGINAL PROMPT --> <details> <summary>Original prompt</summary> ---- *This section details on the original issue you should resolve* <issue_title>[refactor] Enhanced Semantic Analysis - Deep Refactoring Opportunities</issue_title> <issue_description>## 🔧 Enhanced Semantic Function Clustering Analysis *Analysis performed on repository: github/gh-aw-mcpg* *Analysis date: 2026-02-07* *Total Go files analyzed: 68 files (including root-level files)* *Total functions cataloged: ~225+ non-test functions* --- ## Executive Summary This analysis builds upon previous refactoring work and identifies **NEW opportunities** for code organization improvements. The codebase maintains excellent overall structure, but several patterns emerge that suggest targeted refactoring could improve maintainability and reduce cognitive load. **Key New Findings:** - ✅ **Strong functional organization** - Most files maintain single responsibility - ⚠️ **2 very large files** (1000+ lines) - `unified.go` and `connection.go` could benefit from extraction - ⚠️ **Scattered helper files** - 8 different "*_helpers.go" and "*_util*" files across packages - ⚠️ **Naming inconsistencies** - Mix of `New*` vs `Create*` patterns for constructors - ✅ **Excellent domain separation** - DIFC, guard, and logger packages well-isolated **Function Distribution Summary:** | Package | Functions | Primary Patterns | Quality Rating | |---------|-----------|------------------|----------------| | auth | 5 | Extract*, Parse*, Validate* | ✅ Excellent | | cmd | 16 | Register*, getDefault* | ✅ Excellent | | config | 28+ | Load*, Validate*, expand* | ✅ Good | | difc | 35+ | New*, Get*, Add*, Check* | ✅ Excellent | | guard | 14 | Register*, Get*, Create* | ✅ Excellent | | launcher | 18 | GetOrLaunch*, log* | ✅ Good | | logger | 45+ | Log*, Init*, Sanitize* | ⚠️ Good (scattered) | | mcp | 24 | New*, Send*, try* | ⚠️ Good (large file) | | middleware | 5 | apply*, Wrap* | ✅ Excellent | | server | 35+ | Handle*, Register*, Get* | ⚠️ Good (large file) | --- ## High-Priority Opportunities ### 1. ⚠️ Large File Refactoring Candidates **Priority:** 🟡 **MEDIUM** **Impact:** Medium-High - Improved maintainability and testing #### Problem: Two Files Exceed 1000 Lines **Files:** - `internal/server/unified.go` - **1,025 lines** (29 functions, 178 comments) - `internal/mcp/connection.go` - **999 lines** (29 functions) **Analysis:** Both files implement cohesive feature sets but have grown to the point where: - Navigation becomes challenging - Testing requires more setup - Pull request reviews are harder - Multiple developers may conflict on changes **Recommendation: Extract Logical Components** #### **For `internal/server/unified.go`:** Consider extracting into multiple files within `internal/server/`: 1. **`unified_registration.go`** - Tool registration logic - Functions: `registerAllTools`, `registerAllToolsSequential`, `registerAllToolsParallel`, `registerToolsFromBackend`, `registerSysTools` - **~250 lines extracted** 2. **`unified_session.go`** - Session management - Functions: `getSessionID`, `requireSession`, `getSessionKeys`, `ensureSessionDirectory` - **~150 lines extracted** 3. **`unified_tools.go`** - Tool execution logic - Functions: `callBackendTool`, `GetToolHandler`, `GetToolsForBackend` - **~200 lines extracted** 4. **`unified.go`** - Core server struct, constructor, Run, Close - Functions: `NewUnified`, `Run`, `Close`, `IsShutdown`, `GetServerIDs`, `GetServerStatus`, `GetPayloadSizeThreshold` - **~400 lines remaining** **Benefits:** - ✅ Each file has a clear, single purpose - ✅ Easier to locate registration, session, or tool execution logic - ✅ Better test organization (can test components in isolation) - ✅ Reduced merge conflicts - ✅ Follows Go idiom of grouping related methods by feature in separate files **Estimated Effort:** 4-6 hours **Risk:** Low-Medium - Pure refactor, no logic changes, tests verify correctness --- #### **For `internal/mcp/connection.go`:** Consider extracting into multiple files within `internal/mcp/`: 1. **`connection_http.go`** - HTTP-specific connection logic - Functions: `NewHTTPConnection`, `initializeHTTPSession`, `sendHTTPRequest`, `setupHTTPRequest`, HTTP transport methods - **~350 lines extracted** 2. **`connection_transport.go`** - Transport selection and fallback logic - Functions: `trySDKTransport`, `tryStreamableHTTPTransport`, `trySSETransport`, `tryPlainJSONTransport` - **~250 lines extracted** 3. **`connection_tools.go`** - Tool/resource/prompt operations - Functions: `listTools`, `callTool`, `listResources`, `readResource`, `listPrompts`, `getPrompt` - **~200 lines extracted** 4. **`connection.go`** - Core Connection struct and SendRequest - Functions: `NewConnection`, `SendRequest`, `SendRequestWithServerID`, `Close`, `IsHTTP`, core getters - **~200 lines remaining** **Benefits:** - ✅ HTTP logic isolated from stdio logic - ✅ Transport fallback strategy clearly visible in one file - ✅ Tool operati... </details> > **Custom agent used: agentic-workflows** > GitHub Agentic Workflows (gh-aw) - Create, debug, and upgrade AI-powered workflows with intelligent prompt routing <!-- START COPILOT CODING AGENT SUFFIX --> - Fixes #805 <!-- START COPILOT CODING AGENT TIPS --> --- ✨ Let Copilot coding agent [set things up for you](https://github.com/github/gh-aw-mcpg/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo.
2 parents c5df5c6 + a6705a8 commit 4e4c19f

1 file changed

Lines changed: 73 additions & 0 deletions

File tree

CONTRIBUTING.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,79 @@ awmg/
246246
- Add Godoc comments for all exported functions, types, and packages
247247
- Mock external dependencies (Docker, network) in tests
248248

249+
### Constructor Naming Conventions
250+
251+
The codebase uses three distinct constructor patterns. Follow these conventions consistently:
252+
253+
#### 1. `New*(args) *Type` - Standard Constructors
254+
255+
Use for simple object creation without error handling or complex initialization.
256+
257+
```go
258+
// Creates a new instance of the type directly
259+
func NewConnection(ctx context.Context) *Connection { ... }
260+
func NewRegistry() *Registry { ... }
261+
func NewSession(sessionID, token string) *Session { ... }
262+
```
263+
264+
**When to use:**
265+
- Object creation is always successful (no errors to return)
266+
- Direct instantiation of struct with provided parameters
267+
- Most common pattern in the codebase (35+ usages)
268+
269+
#### 2. `Create*(args) (Type, error)` - Factory Patterns
270+
271+
Use for factory functions that perform registry lookups or complex configuration-based initialization.
272+
273+
```go
274+
// Looks up a guard type from registry and creates it
275+
func CreateGuard(name string) (Guard, error) { ... }
276+
277+
// Complex initialization with potential failures
278+
func CreateHTTPServerForMCP(cfg *Config) (*http.Server, error) { ... }
279+
```
280+
281+
**When to use:**
282+
- Registry-based object creation (looking up registered types)
283+
- Complex configuration that might fail
284+
- Need to validate parameters and return errors
285+
- Factory pattern with type selection logic
286+
287+
#### 3. `Init*(args) error` - Global State Initialization
288+
289+
Use for initializing global singletons, loggers, or package-level state.
290+
291+
```go
292+
// Initializes global file logger singleton
293+
func InitFileLogger(dir string) error { ... }
294+
295+
// Initializes global JSON logger singleton
296+
func InitJSONLLogger(dir string) error { ... }
297+
```
298+
299+
**When to use:**
300+
- Initializing global variables or package-level state
301+
- Singleton initialization that should only happen once
302+
- Setting up loggers, configuration, or other shared resources
303+
- Typically returns an error if initialization fails
304+
305+
#### Examples from Codebase
306+
307+
**Standard Constructors (`New*`):**
308+
- `NewConnection`, `NewHTTPConnection` (mcp package)
309+
- `NewUnified`, `NewSession` (server package)
310+
- `NewRegistry`, `NewNoopGuard` (guard package)
311+
- `NewLabel`, `NewAgentLabels` (difc package)
312+
313+
**Factory Patterns (`Create*`):**
314+
- `CreateGuard` (guard package) - registry lookup
315+
- `CreateHTTPServerForMCP` (server package) - complex config-based creation
316+
317+
**Global Initialization (`Init*`):**
318+
- `InitFileLogger`, `InitJSONLLogger`, `InitMarkdownLogger`, `InitServerFileLogger` (logger package)
319+
320+
**When in doubt:** Use `New*` for most constructors. Only use `Create*` when implementing factory patterns with type selection, and `Init*` for global state initialization.
321+
249322
### Debug Logging
250323

251324
Use the logger package for debug logging:

0 commit comments

Comments
 (0)