Overview
Bias against bespoke internal implementations by preferring mature open-source tools and
composable libraries. When custom code is unavoidable, enforce justification rubrics that
require explicit rationale, ownership, versioning, testing, and security considerations.
When to Use
- Proposals to write internal mappers, code generators, custom build scripts, or DI containers
- Reviews where new internal tooling or bespoke framework layers are introduced
- Evaluating whether to build vs buy/adopt for any infrastructure component
- Reviewing PRs that add custom implementations for common concerns (validation, retries, caching)
- Architectural decisions involving custom scaffolding or automation scripts
Core Workflow
- Identify the concern: Determine what functionality is being proposed (mapping, validation, CLI, etc.)
- Search for OSS alternatives: Evaluate mature open-source libraries that solve the same problem
- Compare trade-offs: Assess maintenance burden, test effort, performance, and community support
- Apply decision framework: Choose OSS unless clear justification exists for bespoke code
- Require justification rubric: If bespoke code is proposed, demand explicit rationale,
ownership, versioning, tests, and security considerations
- Document decision: Record OSS evaluation, selection rationale, and maintenance plan
- Verify in PR: Check that PR includes evidence of OSS evaluation and rubric satisfaction
Core
Defaults
- Prefer OSS libraries/tools over bespoke implementations for:
- mapping,
- validation,
- retries/circuit breakers,
- caching,
- scheduling,
- logging/metrics,
- CLI/automation tools,
- test harnesses.
Principles
- "Library before framework": small, composable components are preferred.
- "Configuration before code" when it improves transparency and reduces maintenance.
- "Script last": if unavoidable, scripts must be versioned, tested, and documented.
Load: checklists
Bespoke justification rubric (required)
A bespoke internal tool/framework must include:
- explicit rationale why OSS alternatives are insufficient,
- ownership (team/person) and support model,
- versioning and deprecation policy,
- tests and documentation,
- security and supply-chain considerations.
Load: examples
- Prefer an OSS formatter/analyzer/CLI over a custom PowerShell script.
- Prefer an OSS mapping generator over internal reflection-based mapping.
Load: enforcement
- Reject PRs introducing new internal framework layers without:
- justification rubric satisfied,
- a documented maintenance plan,
- confirmation that OSS options were evaluated and licensing revalidated.
Load: PR review checklist
When reviewing PRs proposing new custom code, verify:
Decision rule: If OSS evaluation is incomplete or rubric unsatisfied, request
changes before approving.
Load: worked example
Scenario: Object Mapping in .NET
Requirement: Convert DTOs to domain entities in a health insurance claims
system.
Option A: Custom Reflection-Based Mapper (Bespoke)
public class ClaimMapper
{
public DomainClaim MapToClaim(ClaimDto dto)
{
var claim = new DomainClaim();
// Manual property assignment for ~30 properties
claim.ClaimId = dto.Id;
claim.MemberId = dto.MemberId;
// ... 28 more assignments
return claim;
}
}
Costs:
- Maintenance: Manual updates required when entities change (tight coupling)
- Testing: Every mapping path must be tested manually
- Performance: Reflection-based or slow property copying
- Versioning: No clear deprecation path if mapping rules change
- Ownership: Who maintains this when the original author leaves?
OSS Evaluation: Rejected without justification.
Option B: AutoMapper (OSS Library)
services.AddAutoMapper(cfg =>
{
cfg.CreateMap<ClaimDto, DomainClaim>();
});
Strengths:
- Maintenance: Configuration-driven, auto-discovers properties by name/convention
- Testing: Industry-standard test patterns, extensive test suite in OSS
- Performance: Mature optimization, benchmarked at scale
- Versioning: Library follows SemVer; breaking changes documented
- Ownership: Active maintainers, funding model established
- Documentation: Comprehensive guides for complex mappings
Risks: Dependency on external library (mitigated by extensive industry
adoption and source availability).
Option C: Mapperly (Modern OSS Library)
[Mapper]
public partial class ClaimMapper
{
public partial DomainClaim MapToClaim(ClaimDto dto);
}
Strengths:
- Zero runtime overhead via source generation (better than AutoMapper for
performance-critical paths)
- Explicit, generated code is auditable
- Compile-time safety
- Minimal dependencies
- Fastest execution path
Trade-off: Newer library (active development but smaller ecosystem than
AutoMapper).
Decision Framework
| Criterion |
Bespoke |
AutoMapper |
Mapperly |
| Maintenance burden |
High (manual) |
Low (config) |
Low (generated) |
| Test effort |
High |
Medium |
Low |
| Performance |
Unknown |
Good |
Excellent |
| Versioning clarity |
None |
Documented |
Documented |
| Ownership model |
Implicit |
Explicit |
Explicit |
| Industry adoption |
N/A |
Mature (15+ years) |
Growing (active) |
| Time to value |
Slow (30+ lines) |
Fast (2 lines) |
Fast (1 line) |
Recommendation
Use Mapperly for new systems (source generation, zero deps, best
performance) or AutoMapper for teams with existing expertise.
Reject bespoke mapper unless:
- Performance benchmarks prove custom code materially faster (at scale)
- Mapping logic is genuinely bespoke (not property-to-property)
- Ownership, versioning, and testing documented per rubric
Verification
Evidence required in PR:
Red Flags - STOP
These statements indicate bypass of bespoke minimisation principles:
| Thought |
Reality |
| "We need full control over this" |
OSS libraries offer customisation; evaluate before rejecting |
| "OSS is too heavy for our needs" |
Measure actual overhead; most libraries are well-optimised |
| "We're special, our case is unique" |
Most "unique" cases have OSS solutions; search thoroughly |
| "I can write this in a day" |
Maintenance cost exceeds initial development; OSS shifts burden |
| "External dependencies are risky" |
Well-maintained OSS with active communities reduces risk |
| "We'll document it later" |
Undocumented internal code becomes unmaintainable quickly |
1---2name: dotnet-bespoke-code-minimisation3description: Use when adding tooling, scripts, or frameworks to a .NET project - bias against bespoke code in favour of mature open-source tools and composable libraries with clear ownership.4metadata:5 type: Implementation6 priority: P27---89## Overview1011Bias against bespoke internal implementations by preferring mature open-source tools and12composable libraries. When custom code is unavoidable, enforce justification rubrics that13require explicit rationale, ownership, versioning, testing, and security considerations.1415## When to Use1617- Proposals to write internal mappers, code generators, custom build scripts, or DI containers18- Reviews where new internal tooling or bespoke framework layers are introduced19- Evaluating whether to build vs buy/adopt for any infrastructure component20- Reviewing PRs that add custom implementations for common concerns (validation, retries, caching)21- Architectural decisions involving custom scaffolding or automation scripts2223## Core Workflow24251. **Identify the concern**: Determine what functionality is being proposed (mapping, validation, CLI, etc.)262. **Search for OSS alternatives**: Evaluate mature open-source libraries that solve the same problem273. **Compare trade-offs**: Assess maintenance burden, test effort, performance, and community support284. **Apply decision framework**: Choose OSS unless clear justification exists for bespoke code295. **Require justification rubric**: If bespoke code is proposed, demand explicit rationale,30 ownership, versioning, tests, and security considerations316. **Document decision**: Record OSS evaluation, selection rationale, and maintenance plan327. **Verify in PR**: Check that PR includes evidence of OSS evaluation and rubric satisfaction3334## Core3536### Defaults3738- Prefer OSS libraries/tools over bespoke implementations for:39 - mapping,40 - validation,41 - retries/circuit breakers,42 - caching,43 - scheduling,44 - logging/metrics,45 - CLI/automation tools,46 - test harnesses.4748### Principles4950- "Library before framework": small, composable components are preferred.51- "Configuration before code" when it improves transparency and reduces maintenance.52- "Script last": if unavoidable, scripts must be versioned, tested, and documented.5354## Load: checklists5556### Bespoke justification rubric (required)5758A bespoke internal tool/framework must include:5960- explicit rationale why OSS alternatives are insufficient,61- ownership (team/person) and support model,62- versioning and deprecation policy,63- tests and documentation,64- security and supply-chain considerations.6566## Load: examples6768- Prefer an OSS formatter/analyzer/CLI over a custom PowerShell script.69- Prefer an OSS mapping generator over internal reflection-based mapping.7071## Load: enforcement7273- Reject PRs introducing new internal framework layers without:74 - justification rubric satisfied,75 - a documented maintenance plan,76 - confirmation that OSS options were evaluated and licensing revalidated.7778## Load: PR review checklist7980When reviewing PRs proposing new custom code, verify:8182- [ ] **OSS Evaluation**: Has the author evaluated mature OSS alternatives?83 (Expect evidence: library list, why each was rejected)84- [ ] **Justification Rubric**: If OSS rejected, is the full rubric satisfied?85 - [ ] Explicit rationale for OSS insufficiency86 - [ ] Named owner (team/person) responsible for maintenance87 - [ ] Versioning and deprecation policy defined88 - [ ] Tests covering critical functionality89 - [ ] Security and supply-chain considerations documented90- [ ] **Library vs Framework**: For applicable cases, has the author chosen91 libraries over frameworks?92- [ ] **Documentation**: Is maintenance burden and support model clearly93 communicated?94- [ ] **Red Flags**: Watch for rationalizations that bypass evaluation (e.g.,95 "we need full control", "OSS is too heavy", "we're special")9697**Decision rule**: If OSS evaluation is incomplete or rubric unsatisfied, request98changes before approving.99100## Load: worked example101102### Scenario: Object Mapping in .NET103104**Requirement**: Convert DTOs to domain entities in a health insurance claims105system.106107#### Option A: Custom Reflection-Based Mapper (Bespoke)108109```csharp110public class ClaimMapper111{112 public DomainClaim MapToClaim(ClaimDto dto)113 {114 var claim = new DomainClaim();115 // Manual property assignment for ~30 properties116 claim.ClaimId = dto.Id;117 claim.MemberId = dto.MemberId;118 // ... 28 more assignments119 return claim;120 }121}122```123124**Costs**:125126- Maintenance: Manual updates required when entities change (tight coupling)127- Testing: Every mapping path must be tested manually128- Performance: Reflection-based or slow property copying129- Versioning: No clear deprecation path if mapping rules change130- Ownership: Who maintains this when the original author leaves?131132**OSS Evaluation**: Rejected without justification.133134#### Option B: AutoMapper (OSS Library)135136```csharp137services.AddAutoMapper(cfg =>138{139 cfg.CreateMap<ClaimDto, DomainClaim>();140});141```142143**Strengths**:144145- Maintenance: Configuration-driven, auto-discovers properties by name/convention146- Testing: Industry-standard test patterns, extensive test suite in OSS147- Performance: Mature optimization, benchmarked at scale148- Versioning: Library follows SemVer; breaking changes documented149- Ownership: Active maintainers, funding model established150- Documentation: Comprehensive guides for complex mappings151152**Risks**: Dependency on external library (mitigated by extensive industry153adoption and source availability).154155#### Option C: Mapperly (Modern OSS Library)156157```csharp158[Mapper]159public partial class ClaimMapper160{161 public partial DomainClaim MapToClaim(ClaimDto dto);162}163```164165**Strengths**:166167- Zero runtime overhead via source generation (better than AutoMapper for168 performance-critical paths)169- Explicit, generated code is auditable170- Compile-time safety171- Minimal dependencies172- Fastest execution path173174**Trade-off**: Newer library (active development but smaller ecosystem than175AutoMapper).176177#### Decision Framework178179| Criterion | Bespoke | AutoMapper | Mapperly |180| ------------------ | ---------------- | ------------------ | ---------------- |181| Maintenance burden | High (manual) | Low (config) | Low (generated) |182| Test effort | High | Medium | Low |183| Performance | Unknown | Good | Excellent |184| Versioning clarity | None | Documented | Documented |185| Ownership model | Implicit | Explicit | Explicit |186| Industry adoption | N/A | Mature (15+ years) | Growing (active) |187| Time to value | Slow (30+ lines) | Fast (2 lines) | Fast (1 line) |188189#### Recommendation190191**Use Mapperly** for new systems (source generation, zero deps, best192performance) or **AutoMapper** for teams with existing expertise.193194**Reject bespoke mapper** unless:195196- Performance benchmarks prove custom code materially faster (at scale)197- Mapping logic is genuinely bespoke (not property-to-property)198- Ownership, versioning, and testing documented per rubric199200#### Verification201202Evidence required in PR:203204- [ ] OSS libraries evaluated: AutoMapper, Mapperly, TinyMapper considered205- [ ] Selection rationale: "Mapperly chosen for source-gen performance and206 zero-dependency model"207- [ ] Tests: Core mappings covered208- [ ] Documentation: Mapping conventions explained (if non-obvious)209210## Red Flags - STOP211212These statements indicate bypass of bespoke minimisation principles:213214| Thought | Reality |215| ----------------------------------- | --------------------------------------------------------------- |216| "We need full control over this" | OSS libraries offer customisation; evaluate before rejecting |217| "OSS is too heavy for our needs" | Measure actual overhead; most libraries are well-optimised |218| "We're special, our case is unique" | Most "unique" cases have OSS solutions; search thoroughly |219| "I can write this in a day" | Maintenance cost exceeds initial development; OSS shifts burden |220| "External dependencies are risky" | Well-maintained OSS with active communities reduces risk |221| "We'll document it later" | Undocumented internal code becomes unmaintainable quickly |