Skip to content

[duplicate-code] Duplicate Code Pattern: Environment Variable Default Functions #582

@github-actions

Description

@github-actions

🔍 Duplicate Code Pattern: Environment Variable Default Functions

Part of duplicate code analysis: #581

Summary

Three nearly identical getDefault*() functions implement the same environment variable fallback pattern with minor variations. These functions check for an environment variable and return either the env value or a hardcoded default.

Duplication Details

Pattern: Environment Variable with Fallback

  • Severity: Medium
  • Occurrences: 3 instances
  • Locations:
    • internal/cmd/flags_difc.go (lines 30-38) - getDefaultEnableDIFC()
    • internal/cmd/flags_logging.go (lines 32-37) - getDefaultLogDir()
    • internal/cmd/flags_logging.go (lines 41-46) - getDefaultPayloadDir()

Code Samples

Pattern 1: String environment variable (used 2x)

// getDefaultLogDir - flags_logging.go:32-37
func getDefaultLogDir() string {
	if envLogDir := os.Getenv("MCP_GATEWAY_LOG_DIR"); envLogDir != "" {
		return envLogDir
	}
	return defaultLogDir
}

// getDefaultPayloadDir - flags_logging.go:41-46
func getDefaultPayloadDir() string {
	if envPayloadDir := os.Getenv("MCP_GATEWAY_PAYLOAD_DIR"); envPayloadDir != "" {
		return envPayloadDir
	}
	return defaultPayloadDir
}

Pattern 2: Boolean environment variable with case-insensitive parsing

// getDefaultEnableDIFC - flags_difc.go:30-38
func getDefaultEnableDIFC() bool {
	if envDIFC := os.Getenv("MCP_GATEWAY_ENABLE_DIFC"); envDIFC != "" {
		switch strings.ToLower(envDIFC) {
		case "1", "true", "yes", "on":
			return true
		}
	}
	return defaultEnableDIFC
}

Impact Analysis

  • Maintainability: Each new environment-backed flag requires copying this pattern, increasing code volume
  • Bug Risk: Inconsistent parsing logic (bool vs string) scattered across files
  • Code Bloat: ~15-20 lines of similar code across 2 files
  • Testing: Each function needs separate tests despite identical logic

Refactoring Recommendations

Option 1: Generic Environment Variable Helper (Recommended)

Extract common logic to a utility package with type-safe helpers:

// internal/envutil/envutil.go
package envutil

import (
	"os"
	"strings"
)

// GetStringOrDefault returns environment variable value or default
func GetStringOrDefault(envKey, defaultValue string) string {
	if val := os.Getenv(envKey); val != "" {
		return val
	}
	return defaultValue
}

// GetBoolOrDefault returns environment variable as bool or default
func GetBoolOrDefault(envKey string, defaultValue bool) bool {
	val := os.Getenv(envKey)
	if val == "" {
		return defaultValue
	}
	switch strings.ToLower(val) {
	case "1", "true", "yes", "on":
		return true
	case "0", "false", "no", "off":
		return false
	default:
		return defaultValue
	}
}

Updated flag files:

// flags_logging.go
func getDefaultLogDir() string {
	return envutil.GetStringOrDefault("MCP_GATEWAY_LOG_DIR", defaultLogDir)
}

func getDefaultPayloadDir() string {
	return envutil.GetStringOrDefault("MCP_GATEWAY_PAYLOAD_DIR", defaultPayloadDir)
}

// flags_difc.go
func getDefaultEnableDIFC() bool {
	return envutil.GetBoolOrDefault("MCP_GATEWAY_ENABLE_DIFC", defaultEnableDIFC)
}

Benefits:

  • Reduces ~40 lines to ~10 lines
  • Centralizes environment variable parsing logic
  • Makes boolean parsing consistent and testable
  • Easy to extend with GetIntOrDefault, GetDurationOrDefault, etc.

Option 2: Inline with Comments

If keeping code local is preferred, at least add a comment referencing the pattern:

// getDefaultLogDir follows the standard env-or-default pattern.
// See also: getDefaultPayloadDir, getDefaultEnableDIFC
func getDefaultLogDir() string {
	if envLogDir := os.Getenv("MCP_GATEWAY_LOG_DIR"); envLogDir != "" {
		return envLogDir
	}
	return defaultLogDir
}

Implementation Checklist

  • Review duplication findings with team
  • Decide on refactoring approach (Option 1 vs Option 2)
  • If Option 1: Create internal/envutil package with helpers
  • If Option 1: Add unit tests for GetStringOrDefault and GetBoolOrDefault
  • Update all 3 getDefault*() functions to use helpers
  • Update existing tests to verify behavior unchanged
  • Document pattern in AGENTS.md or CONTRIBUTING.md

Estimated effort: 1-2 hours (create utility + update 3 call sites + tests)

Parent Issue

See parent analysis report: #581
Related to #581

AI generated by Duplicate Code Detector

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions