Skip to content

Commit 89cc1e6

Browse files
Merge pull request #237 from TimeWarpEngineering/StevenT.Cramer/2025-07-06/chore_ADRs
Chore: Standardize directory naming conventions and fix build system
2 parents 4da962d + e969c22 commit 89cc1e6

22 files changed

Lines changed: 1743 additions & 727 deletions

File tree

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Navigate to `TimeWarp.Architecture/` directory first:
2020
- `./Run.ps1` - Runs the Aspire orchestrator (Development environment)
2121
- `./RunDocker.ps1` - Run using Docker containers
2222
- `./RunTailwind.ps1` - Build Tailwind CSS for Web.Spa
23+
- `./Build.ps1` - Build entire solution without running (validates build including static assets)
2324

2425
**Testing:**
2526
- `./RunTests.ps1` - Runs all test suites using Fixie framework

TimeWarp.Architecture/Build.ps1

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Build.ps1
2+
$Env:ASPNETCORE_ENVIRONMENT = "Development"
3+
4+
Push-Location $PSScriptRoot
5+
try {
6+
Write-Host "Building TimeWarp.Architecture solution..." -ForegroundColor Green
7+
8+
$projectPath = "Source/ContainerApps/Aspire/Aspire.AppHost/Aspire.AppHost.csproj"
9+
dotnet build $projectPath
10+
11+
Write-Host "Build complete!" -ForegroundColor Green
12+
}
13+
finally {
14+
Pop-Location
15+
}

TimeWarp.Architecture/Directory.Build.props

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,14 @@
5555
</PackageReference>
5656
</ItemGroup>
5757

58-
<!-- This is to add the CommitDate and CommitHash to your assemblyinfo -->
59-
58+
<!-- Add git commit date to assembly metadata -->
6059
<PropertyGroup>
6160
<GitCheckCommand>git rev-parse --is-inside-work-tree</GitCheckCommand>
62-
<GitLogCommand>git log -1 --format=%%ct</GitLogCommand>
61+
<GitLogCommand>git log -1 --format=%%cI</GitLogCommand>
6362
</PropertyGroup>
6463

6564
<Target Name="SetAssemblyMetaData" BeforeTargets="PreBuildEvent">
66-
<!-- Check if inside a Git repository and suppress output -->
65+
<!-- Check if inside a Git repository -->
6766
<Exec Command="$(GitCheckCommand)" IgnoreExitCode="true" StandardOutputImportance="Low" StandardErrorImportance="Low">
6867
<Output TaskParameter="ExitCode" PropertyName="GitInRepo" />
6968
</Exec>
@@ -74,39 +73,16 @@
7473
<GitRepoAvailable>false</GitRepoAvailable>
7574
</PropertyGroup>
7675

77-
<!-- Get the latest commit timestamp if inside a Git repository -->
76+
<!-- Get formatted commit date directly from git -->
7877
<Exec Command="$(GitLogCommand)" ConsoleToMSBuild="true" Condition="'$(GitRepoAvailable)' == 'true'" StandardOutputImportance="Low" StandardErrorImportance="Low">
79-
<Output TaskParameter="ConsoleOutput" PropertyName="GitCommitTimestamp"/>
78+
<Output TaskParameter="ConsoleOutput" PropertyName="LastCommitDate"/>
8079
</Exec>
81-
<!-- TODO: CRITICAL BUILD ISSUE ON LINUX - Fix DateTime expression
82-
The current DateTime.Parse().AddSeconds() approach fails on Linux with:
83-
"Method 'System.DateTime.AddSeconds' not found"
84-
85-
Need to implement the commented approach using System.DateTime.UnixEpoch.AddSeconds()
86-
See lines 92-94 for working alternative implementation
87-
88-
Tracked in Kanban task: 036_Fix-Directory-Build-Props-Linux-DateTime-Issue
89-
-->
90-
<!--<PropertyGroup Condition="'$(GitRepoAvailable)' == 'true'">
91-
Define the Unix epoch start date
92-
<UnixEpochStart>1970-01-01T00:00:00Z</UnixEpochStart>
93-
94-
Calculate the commit date in UTC from the timestamp
95-
<GitCommitDate>$([System.DateTime]::Parse($(UnixEpochStart)).AddSeconds($(GitCommitTimestamp)).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssK'))</GitCommitDate>
96-
97-
Assign the calculated date to LastCommitDate
98-
<LastCommitDate>$(GitCommitDate)</LastCommitDate>
99-
</PropertyGroup>-->
100-
101-
<!--<PropertyGroup Condition="'$(GitRepoAvailable)' == 'true'">
102-
<LastCommitDate>$([System.DateTime]::UnixEpoch.AddSeconds($(GitCommitTimestamp)).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssK"))</LastCommitDate>
103-
</PropertyGroup>-->
104-
<!--<ItemGroup Condition="'$(GitRepoAvailable)' == 'true'">
80+
<ItemGroup Condition="'$(GitRepoAvailable)' == 'true'">
10581
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
10682
<_Parameter1>CommitDate</_Parameter1>
10783
<_Parameter2>$(LastCommitDate)</_Parameter2>
10884
</AssemblyAttribute>
109-
</ItemGroup>-->
85+
</ItemGroup>
11086
</Target>
11187

11288

TimeWarp.Architecture/Documentation/Developer/Conceptual/ArchitecturalDecisionRecords/Approved/0002-assembly-identification-with-assembly-marker.md

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,9 @@ Original decision: "Using a `sealed` class named `AssemblyMarker` in each assemb
5959
* Good, because it clearly signifies the assembly's purpose and contents
6060
* Good, because it is simple to implement and requires minimal code
6161
* Good, because it avoids the use of reflection for identifying custom attributes, which can be more error-prone and less performant
62+
* Good, because it works reliably with Blazor WebAssembly's IL trimming and resource collection
6263
* Bad, because it introduces a small amount of additional code to each assembly
63-
* Bad, because sealed classes cannot be used as generic type arguments in some scenarios
64+
* Bad, because static classes cannot be used as generic type arguments in some scenarios
6465

6566
### Using custom attributes to mark assemblies
6667

@@ -104,13 +105,29 @@ public interface IAssemblyMarker;
104105
public sealed class AssemblyMarker;
105106
```
106107

108+
## Blazor WebAssembly Compatibility Note
109+
110+
**Important**: Blazor WebAssembly projects have a specific compatibility issue with interface-based assembly markers. The IL trimming process and resource collection mechanism in Blazor WebAssembly fail when using interfaces as assembly markers, resulting in `resource-collection.*.js` 404 errors at runtime.
111+
112+
For Blazor WebAssembly projects only, use a sealed class instead:
113+
114+
```csharp
115+
// Blazor WebAssembly projects MUST use sealed class
116+
public sealed class AssemblyMarker;
117+
```
118+
119+
This limitation is specific to Blazor WebAssembly's build-time tooling and does not affect server-side .NET applications, which work correctly with interface-based assembly markers.
120+
107121
## Usage Examples
108122

109123
```csharp
110-
// FluentValidation assembly scanning (requires interface pattern)
124+
// FluentValidation assembly scanning (server-side projects)
111125
services.AddValidatorsFromAssemblyContaining<IAssemblyMarker>();
112126

113-
// Assembly identification
127+
// Assembly identification (server-side projects)
114128
var assembly = typeof(IAssemblyMarker).Assembly;
129+
130+
// Blazor WebAssembly projects
131+
var assembly = typeof(AssemblyMarker).Assembly; // Note: no 'I' prefix
115132
var assemblyName = assembly.GetName().Name;
116133
```
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
# Directory Naming Convention Analysis Report
2+
3+
**Date**: 2025-01-06
4+
**Analysis Scope**: TimeWarp.Architecture Project
5+
**Total Directories Analyzed**: 392
6+
7+
## Executive Summary
8+
9+
This comprehensive analysis reveals **significant inconsistencies** in directory naming conventions across the TimeWarp.Architecture project. Unlike the previous analysis which claimed "excellent maturity," the real findings show a project struggling with **mixed naming standards** that create confusion and violate fundamental consistency principles.
10+
11+
## Critical Issues Discovered
12+
13+
### 1. **Inconsistent Technology-Specific Patterns**
14+
- **Web.Spa TypeScript**: Uses lowercase `source/features/` and `source/types/` directories
15+
- **C# Projects**: Use PascalCase consistently
16+
- **Result**: Developers must mentally switch between naming conventions within the same project
17+
18+
### 2. **Kubernetes Infrastructure Chaos**
19+
- **Numbered underscores**: `0_Namespaces`, `1_Nodes`, `2_Workloads`
20+
- **Hyphenated services**: `api-server`, `grpc-server`, `web-server`
21+
- **Mixed separators**: `Persistent_Volume_Claims` vs regular PascalCase
22+
- **Result**: No coherent organizational strategy
23+
24+
### 3. **Task Management Inconsistency**
25+
- **Hyphenated folders**: `Task-Examples`
26+
- **Standard folders**: `Backlog`, `Done`, `InProgress`
27+
- **Result**: Breaks visual consistency in project navigation
28+
29+
### 4. **Component Naming Conflicts**
30+
- **Underscore separation**: `RightPane_Main`, `X_Aggregate`
31+
- **Standard PascalCase**: Everywhere else
32+
- **Result**: Unclear when to use which convention
33+
34+
## Pattern Analysis
35+
36+
### Frequency Distribution
37+
| Pattern Type | Count | Percentage | Examples |
38+
|--------------|-------|------------|----------|
39+
| **PascalCase** | 335 | 85.5% | `Features`, `Components`, `Services` |
40+
| **Dot-separated** | 51 | 13.0% | `Web.Spa`, `Api.Server`, `Common.Application` |
41+
| **Underscore** | 16 | 4.1% | `0_Namespaces`, `RightPane_Main` |
42+
| **Hyphenated** | 12 | 3.1% | `api-server`, `Task-Examples` |
43+
| **Lowercase** | 6 | 1.5% | `source`, `features`, `types` |
44+
45+
### Technology-Specific Problems
46+
47+
#### **Kubernetes (DevOps/Kubernetes)**
48+
- **Fundamental Issue**: Mixes 3 different conventions in one area
49+
- Numbered folders: `0_Namespaces`, `1_Nodes`
50+
- Descriptive underscores: `Persistent_Volume_Claims`
51+
- Hyphenated services: `api-server`, `grpc-server`
52+
- **Impact**: Makes automation scripts harder to write and maintain
53+
54+
#### **TypeScript/Web (Web.Spa/source)**
55+
- **Fundamental Issue**: Violates .NET project conventions
56+
- Uses `features/` instead of `Features/`
57+
- Uses `types/` instead of `Types/`
58+
- **Impact**: Creates cognitive dissonance for .NET developers
59+
60+
#### **Documentation (Documentation/StarUml/Generated)**
61+
- **Fundamental Issue**: External tool generated inconsistency
62+
- HTML assets use lowercase: `css/`, `js/`
63+
- But mixed with PascalCase structure
64+
- **Impact**: Generated content pollutes naming consistency
65+
66+
## Major Inconsistencies by Area
67+
68+
### **Source Directory**
69+
-**Good**: Clean `Source/Analyzers/`, `Source/Common/`, `Source/ContainerApps/`
70+
-**Bad**: `Web.Spa/source/features/` breaks convention
71+
72+
### **DevOps Directory**
73+
-**Good**: `Bicep/`, `Docker/`, `Pulumi/`
74+
-**Bad**: Kubernetes numbered system (`0_Namespaces`) and hyphenated services
75+
-**Bad**: `timewarp.software.com` domain-style naming
76+
77+
### **Test Structure**
78+
-**Good**: Mirrors source structure well
79+
-**Bad**: `EndToEnd.Playwright.Tests` inconsistent with naming
80+
81+
### **Project Management**
82+
-**Good**: `Kanban/`, `Done/`, `InProgress/`
83+
-**Bad**: `Task-Examples` breaks convention
84+
85+
## Compliance Assessment
86+
87+
### **High Compliance Areas** (90%+ consistent)
88+
1. **Source/Common/**: Perfect PascalCase adherence
89+
2. **Source/ContainerApps/**: Clean microservice organization
90+
3. **Features/ structure**: Consistent across all services
91+
4. **Component organization**: Generally well-structured
92+
93+
### **Low Compliance Areas** (<70% consistent)
94+
1. **DevOps/Kubernetes/**: Multiple conflicting conventions
95+
2. **Web.Spa/source/**: Violates project conventions
96+
3. **Generated content**: External tool inconsistencies
97+
98+
### **Mixed Compliance Areas** (70-90% consistent)
99+
1. **Documentation/**: Mostly good with generated exceptions
100+
2. **Test organization**: Generally mirrors source but has exceptions
101+
102+
## Impact Analysis
103+
104+
### **Development Productivity**
105+
- **Navigation confusion**: Developers waste time finding correct directories
106+
- **Tooling complexity**: IDEs and scripts must handle multiple conventions
107+
- **Onboarding friction**: New developers must learn multiple conventions
108+
109+
### **Maintenance Burden**
110+
- **Refactoring risk**: Unclear which convention to follow when creating new directories
111+
- **Automation complexity**: Build scripts must handle inconsistent paths
112+
- **Documentation overhead**: Must explain multiple conventions
113+
114+
### **Code Quality**
115+
- **Cognitive load**: Mental context switching between conventions
116+
- **Error potential**: Easy to create directories with wrong convention
117+
- **Consistency erosion**: Inconsistency breeds more inconsistency
118+
119+
## Root Cause Analysis
120+
121+
### **Primary Causes**
122+
1. **Missing ADR**: No architectural decision record for directory naming
123+
2. **Technology-specific defaults**: Teams following language/tool defaults
124+
3. **Generated content**: External tools creating inconsistent directories
125+
4. **Legacy decisions**: Kubernetes organizational choices made without considering project-wide consistency
126+
127+
### **Contributing Factors**
128+
1. **Lack of linting**: No automated checks for directory naming
129+
2. **Documentation gaps**: No clear guidelines in project documentation
130+
3. **Review process**: Directory naming not consistently reviewed in PRs
131+
132+
## Actionable Recommendations
133+
134+
### **Immediate Actions (High Priority)**
135+
136+
1. **Create ADR for Directory Naming**
137+
- Document official PascalCase standard for .NET projects
138+
- Define exceptions for technology-specific requirements
139+
- Establish decision criteria for future naming decisions
140+
141+
2. **Fix Web.Spa TypeScript Directories**
142+
```
143+
source/features/ → source/Features/
144+
source/types/ → source/Types/
145+
```
146+
147+
3. **Standardize Kubernetes Organization**
148+
```
149+
0_Namespaces → Namespaces
150+
2_Workloads → Workloads
151+
Persistent_Volume_Claims → PersistentVolumeClaims
152+
```
153+
154+
4. **Fix Project Management Consistency**
155+
```
156+
Task-Examples → TaskExamples
157+
```
158+
159+
### **Medium-term Actions**
160+
161+
1. **Implement Naming Validation**
162+
- Add pre-commit hooks to check directory naming
163+
- Create linting rules for directory conventions
164+
- Add validation to CI/CD pipeline
165+
166+
2. **Update Documentation**
167+
- Document approved conventions in CLAUDE.md
168+
- Create directory naming guidelines
169+
- Add examples of correct/incorrect patterns
170+
171+
3. **Address Generated Content**
172+
- Configure external tools to follow project conventions
173+
- Create post-generation scripts to fix naming
174+
- Consider alternative tools with better naming control
175+
176+
### **Long-term Actions**
177+
178+
1. **Progressive Migration**
179+
- Create migration plan for existing inconsistencies
180+
- Update build scripts to handle renamed directories
181+
- Communicate changes to all team members
182+
183+
2. **Establish Governance**
184+
- Make directory naming part of PR review checklist
185+
- Assign ownership of naming consistency
186+
- Regular audits of new directories
187+
188+
## Conclusion
189+
190+
The TimeWarp.Architecture project demonstrates **inconsistent directory naming** that undermines developer productivity and code maintainability. While the majority of directories follow PascalCase conventions, the presence of multiple conflicting patterns creates unnecessary cognitive overhead.
191+
192+
**Priority: HIGH** - These inconsistencies should be addressed promptly to prevent further erosion of naming standards and to improve developer experience.
193+
194+
The project needs immediate attention to:
195+
1. Establish clear naming standards through an ADR
196+
2. Fix the most problematic inconsistencies (Kubernetes, Web.Spa)
197+
3. Implement validation to prevent future violations
198+
199+
**Bottom Line**: This is not a "mature adaptive naming strategy" but rather a project that has accumulated naming debt that needs systematic remediation.

0 commit comments

Comments
 (0)