🔍 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
// 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
-
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
-
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
-
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
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
🔍 Duplicate Code Detected: INamedPipeSerializer Boilerplate Pattern
Analysis of commit 78e6371
Assignee:
@copilotSummary
Extensive boilerplate duplication exists across 22+ serializer classes that implement
INamedPipeSerializer. Each serializer follows the exact same structural pattern: inheriting fromBaseSerializer, implementingINamedPipeSerializer, and providingId,Serialize, andDeserializemembers. 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:
Impact Analysis
Refactoring Recommendations
Source Generator Approach (Recommended)
[AutoSerialize(id: 1)]attribute to request/response recordsGeneric Base Serializer with Reflection
BaseRequestSerializer<TRequest>that uses reflection to serialize/deserialize record propertiesinternal sealed class ModuleInfoRequestSerializer : BaseRequestSerializer<ModuleInfoRequest> { public override int Id => 1; }Expression Tree-Based Serializer Factory
SerializerFactory.Register<ModuleInfoRequest>(id: 1)Implementation Checklist
Analysis Metadata
Add this agentic workflows to your repo
To install this agentic workflow, run