Skip to content

[duplicate-code] Duplicate Code Pattern: Validation Function Log-Check-Return Structure #8477

Description

@github-actions

Part of duplicate code analysis: #8475

Summary

Two config validation files (validation_rules.go and validation_errors.go) contain 14+ functions that all follow an identical structural pattern: emit an entry/failure debug log and return a &ValidationError{Field, Message, JSONPath, Suggestion}. The repeated structure increases the cost of logging format changes and makes the codebase harder to scan.

Duplication Details

Pattern A: Log-entry → condition check → log-failure → return &ValidationError{}

File: internal/config/validation_rules.go

  • Severity: High
  • Occurrences: 5 functions (PortRange, PositiveInteger, TimeoutMinimum, TimeoutRange, AbsolutePath)
  • Locations: lines 21–33, 50–62, 66–78, 82–95, 205–238+
// PortRange — lines 21-33
func PortRange(port int, jsonPath string) *ValidationError {
	logValidation.Printf("Validating port range: port=%d, jsonPath=%s", port, jsonPath)
	if port < 1 || port > 65535 {
		logValidation.Printf("Port validation failed: port=%d out of range", port)
		return &ValidationError{
			Field: "port", Message: fmt.Sprintf("...%d", port),
			JSONPath: jsonPath, Suggestion: "Use a valid port number (e.g., 8080)",
		}
	}
	return nil
}

// PositiveInteger — lines 50-62 (identical structure, different field/message)
func PositiveInteger(value int, fieldName, jsonPath string) *ValidationError {
	logValidation.Printf("Validating positive integer: field=%s, value=%d, jsonPath=%s", ...)
	if value < 1 {
		logValidation.Printf("Positive integer validation failed: %s=%d ...", ...)
		return &ValidationError{Field: fieldName, Message: ..., JSONPath: jsonPath, Suggestion: ...}
	}
	return nil
}
// TimeoutMinimum, TimeoutRange, AbsolutePath — same 3-section structure

Pattern B: Log-entry → immediately return &ValidationError{}

File: internal/config/validation_errors.go

  • Severity: Medium
  • Occurrences: 7 constructor functions (UnsupportedType, UndefinedVariable, MissingRequired, UnsupportedField, InvalidPattern, InvalidValue, SchemaValidationError)
  • Locations: lines 39–120
// UnsupportedType — lines 39-47
func UnsupportedType(fieldName, actualType, jsonPath, suggestion string) *ValidationError {
	logValidation.Printf("Validation error: unsupported type at %s.%s, type=%s", jsonPath, fieldName, actualType)
	return &ValidationError{
		Field: fieldName, Message: fmt.Sprintf("unsupported type '%s' for field '%s'", actualType, fieldName),
		JSONPath: jsonPath, Suggestion: suggestion,
	}
}
// UndefinedVariable, MissingRequired, InvalidPattern, InvalidValue, ... — identical log+return pattern

Impact Analysis

  • Maintainability: Changing the validation log format (e.g., adding a structured level= prefix) requires editing all 12+ call sites across both files
  • Bug Risk: Medium — divergent log formats across validation functions can obscure root cause during debugging
  • Code Bloat: ~84 lines of repetitive boilerplate; each new validation rule adds another 10-line block

Refactoring Recommendations

  1. Extract a shared logAndReturn helper for Pattern B

    // In validation_errors.go
    func newValidationError(logMsg, field, message, jsonPath, suggestion string) *ValidationError {
        logValidation.Printf(logMsg)
        return &ValidationError{Field: field, Message: message, JSONPath: jsonPath, Suggestion: suggestion}
    }

    Each constructor becomes a 1–2 line call. Estimated effort: 1–2 hours.

  2. Extract a validateInt helper for Pattern A rule functions

    // In validation_rules.go
    func validateInt(fieldName, jsonPath string, value int, check func(int) bool, buildErr func() *ValidationError) *ValidationError {
        logValidation.Printf("Validating %s: value=%d, jsonPath=%s", fieldName, value, jsonPath)
        if !check(value) {
            logValidation.Printf("%s validation failed: %s=%d", fieldName, fieldName, value)
            return buildErr()
        }
        return nil
    }

    Estimated effort: 2–3 hours.

  3. Accept Pattern B as intentional constructors (lower effort)

    • The functions in validation_errors.go are already a thin constructor layer; add a comment to the file header documenting the expected structure for new constructors
    • Estimated effort: 30 minutes

Implementation Checklist

  • Review both patterns and decide on helper approach
  • Implement logAndReturn or validateInt helpers
  • Refactor existing functions to use helpers
  • Verify all tests pass (make test)
  • Check that validation error messages are unchanged

Parent Issue

See parent analysis report: #8475
Related to #8475

Generated by Duplicate Code Detector · 229.8 AIC · ⊞ 8.5K ·

  • expires on Jul 9, 2026, 3:44 AM UTC

Metadata

Metadata

Assignees

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions