Skip to content

[duplicate-code] Duplicate Code: INamedPipeSerializer Boilerplate Pattern #8532

@Evangelink

Description

@Evangelink

🔍 Duplicate Code Detected: INamedPipeSerializer Boilerplate Pattern

Analysis of commit 78e6371

Assignee: @copilot

Summary

Extensive boilerplate duplication exists across 22+ serializer classes that implement INamedPipeSerializer. Each serializer follows the exact same structural pattern: inheriting from BaseSerializer, implementing INamedPipeSerializer, and providing Id, Serialize, and Deserialize members. This creates significant maintenance overhead and violates the DRY principle.

Duplication Details

Pattern: INamedPipeSerializer Implementation Boilerplate

  • Severity: High

  • Occurrences: 22+ serializer classes across 5 platform extensions

  • Locations:

    • src/Platform/Microsoft.Testing.Extensions.MSBuild/Serializers/ (3 files: 111 total lines)
      • ModuleInfoRequestSerializer.cs (25 lines)
      • RunSummaryRequestSerializer.cs (37 lines)
      • FailedTestInfoRequestSerializer.cs (49 lines)
    • src/Platform/Microsoft.Testing.Extensions.HangDump/Serializers/ (4 files)
    • src/Platform/Microsoft.Testing.Extensions.Retry/Serializers/ (4 files)
    • src/Platform/Microsoft.Testing.Extensions.TrxReport/Serializers/ (3 files)
    • src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Serializers/ (6 files)
    • src/Platform/Microsoft.Testing.Platform/IPC/Serializers/ (2 files)
  • Code Sample:

// Pattern repeated 22+ times with minor variations
internal sealed class ModuleInfoRequestSerializer : BaseSerializer, INamedPipeSerializer
{
    public int Id => 1;

    public object Deserialize(Stream stream)
        => new ModuleInfoRequest(ReadString(stream), ReadString(stream), ReadString(stream));

    public void Serialize(object objectToSerialize, Stream stream)
    {
        var moduleInfo = (ModuleInfoRequest)objectToSerialize;
        WriteString(stream, moduleInfo.FrameworkDescription);
        WriteString(stream, moduleInfo.ProcessArchitecture);
        WriteString(stream, moduleInfo.TestResultFolder);
    }
}

// Another example with the same structure
internal sealed class FailedTestRequestSerializer : BaseSerializer, INamedPipeSerializer
{
    public int Id => 1;

    public object Deserialize(Stream stream)
    {
        string uid = ReadString(stream);
        return new FailedTestRequest(uid);
    }

    public void Serialize(object obj, Stream stream)
    {
        var failedTestRequest = (FailedTestRequest)obj;
        WriteString(stream, failedTestRequest.Uid);
    }
}

Impact Analysis

  • Maintainability: Any change to serialization logic (e.g., adding logging, error handling, or validation) requires updates to 22+ files
  • Bug Risk: Inconsistent implementations across serializers create potential for subtle serialization bugs
  • Code Bloat: Estimated 500-800 lines of boilerplate code that could be auto-generated or abstracted
  • Testing Burden: Each serializer requires separate unit tests for essentially identical serialization logic
  • Onboarding Friction: New contributors must understand and replicate the pattern when adding new message types

Refactoring Recommendations

  1. Source Generator Approach (Recommended)

    • Create Roslyn source generator to auto-generate serializer implementations from record declarations
    • Add [AutoSerialize(id: 1)] attribute to request/response records
    • Generator produces serializer classes at compile time based on record properties
    • Estimated effort: 8-12 hours initial implementation
    • Benefits: Zero boilerplate in source, compile-time verification, consistent behavior, easy to add new serializers
    • Example:
      [AutoSerialize(id: 1)]
      internal sealed record ModuleInfoRequest(string FrameworkDescription, string ProcessArchitecture, string TestResultFolder) : IRequest;
      // Serializer auto-generated at compile time
  2. Generic Base Serializer with Reflection

    • Create BaseRequestSerializer<TRequest> that uses reflection to serialize/deserialize record properties
    • Each concrete serializer becomes a one-liner: internal sealed class ModuleInfoRequestSerializer : BaseRequestSerializer<ModuleInfoRequest> { public override int Id => 1; }
    • Estimated effort: 4-6 hours
    • Benefits: Immediate reduction in boilerplate, centralized serialization logic
    • Drawbacks: Runtime reflection overhead, potential performance impact
  3. Expression Tree-Based Serializer Factory

    • Use expression trees to generate serialization delegates at startup
    • Register serializers via factory: SerializerFactory.Register<ModuleInfoRequest>(id: 1)
    • Compile-time type safety with runtime code generation
    • Estimated effort: 6-8 hours
    • Benefits: Performance close to hand-written code, no source boilerplate
    • Drawbacks: Complex implementation, harder to debug

Implementation Checklist

  • Review all 22+ serializer implementations
  • Choose refactoring approach (source generator recommended)
  • Create proof-of-concept for 2-3 serializers
  • Measure performance impact (if using reflection/expression trees)
  • Implement chosen solution
  • Migrate existing serializers incrementally
  • Update unit tests to work with new approach
  • Verify all IPC communication still works correctly
  • Document serializer creation process for future contributors

Analysis Metadata

  • Analyzed Files: 22+ serializer files across 5 platform extension projects
  • Detection Method: Structural pattern analysis with grep and file inspection
  • Estimated Duplicate Lines: 500-800 lines of boilerplate code
  • Commit: 78e6371
  • Analysis Date: 2026-05-24T05:30:57Z

Generated by Duplicate Code Detector · ● 1.4M ·

Add this agentic workflows to your repo

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/duplicate-code-detector.md@main
  • expires on May 26, 2026, 5:36 AM UTC

Metadata

Metadata

Type

No type
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