6.3 KiB
NewEditor Port Boundary Refactor Plan
Date: 2026-04-23 Status: In Progress
1. Objective
Refactor new_editor so that external boundaries are modeled explicitly instead of being mixed into a single app/Ports bucket.
This plan targets three concrete issues:
SystemInteractionPortis a platform/system boundary.TexturePortandViewportRenderPortare rendering host boundaries.ShaderResourceDescriptorAllocatorPortis not a real application boundary because it leaksd3d12.htypes directly into the interface.
The goal is to make the directory structure match the actual architecture, reduce "add another port" cargo cult growth, and make later editor features cheaper to extend.
2. Current Problems
2.1 Mixed abstraction levels
app/Ports currently mixes:
- operating-system integration
- rendering-host integration
- backend-internal D3D12 helpers
These are not the same architectural seam and should not share one bucket.
2.2 The word "Port" is being used too broadly
The current structure encourages a bad rule:
"If something crosses a layer, add a port."
That is not the intended use of ports. A port should exist only for a real boundary contract, not for every data handoff or helper collaboration.
2.3 Fake abstraction in D3D12 descriptor allocation
ShaderResourceDescriptorAllocatorPort exposes:
D3D12_CPU_DESCRIPTOR_HANDLED3D12_GPU_DESCRIPTOR_HANDLEUINT- direct D3D12 header dependency
That makes it a D3D12-specific helper wearing an interface costume. It should be concrete backend code unless there is a proven need for a cross-backend contract.
3. Target End State
After the refactor:
- system-facing services live in a system-oriented location and namespace
- rendering host contracts live under rendering host boundaries
- D3D12-only helpers stay D3D12-local unless a backend-agnostic contract is justified
- new features do not add interfaces by default; they only add one when a real host boundary appears
4. Boundary Rules
Use a boundary interface only when all of the following are true:
- the caller depends on an external capability
- dependency inversion is useful at the application boundary
- the contract can be expressed without leaking backend-only details
- there is a realistic need for substitution, testing, or multiple implementations
Do not add a boundary interface for:
- feature-to-feature communication
- panel-to-runtime state transfer
- helpers inside one rendering backend
- temporary include avoidance
5. Execution Phases
Phase A. Split the app/Ports bucket by responsibility
Create explicit homes for:
- system interaction service
- rendering host contracts
Then move call sites to the new locations and names.
Phase B. Remove the fake D3D12 port
Delete ShaderResourceDescriptorAllocatorPort and make the descriptor allocator a concrete D3D12 helper again.
Phase C. Clean up forwarding and naming
Replace Ports::... references with names that explain the real role:
System::SystemInteractionServiceRendering::Host::UiTextureHostRendering::Host::ViewportRenderHost
Phase D. Validate and harden
- ensure no remaining includes depend on
app/Ports - ensure the app still builds
- document the rule for future extension
6. File Plan
New files
new_editor/app/System/SystemInteractionService.hnew_editor/app/Rendering/Host/HostFwd.hnew_editor/app/Rendering/Host/UiTextureHost.hnew_editor/app/Rendering/Host/ViewportRenderHost.h
Files expected to be updated
new_editor/app/Bootstrap/Application.hnew_editor/app/Bootstrap/Application.cppnew_editor/app/Composition/EditorContext.hnew_editor/app/Composition/EditorContext.cppnew_editor/app/Composition/EditorShellRuntime.hnew_editor/app/Composition/EditorShellRuntime.cppnew_editor/app/Features/Project/ProjectPanel.hnew_editor/app/Features/Project/ProjectPanel.cppnew_editor/app/Features/Scene/SceneViewportFeature.hnew_editor/app/Features/Scene/SceneViewportFeature.cppnew_editor/app/Features/Scene/SceneViewportController.hnew_editor/app/Features/Scene/SceneViewportController.cppnew_editor/app/Features/Scene/SceneViewportToolOverlay.hnew_editor/app/Features/Scene/SceneViewportToolOverlay.cppnew_editor/app/Rendering/Assets/BuiltInIcons.hnew_editor/app/Rendering/Assets/BuiltInIcons.cppnew_editor/app/Rendering/D3D12/D3D12UiTextureHost.hnew_editor/app/Rendering/D3D12/D3D12WindowRenderer.hnew_editor/app/Rendering/D3D12/D3D12ShaderResourceDescriptorAllocator.hnew_editor/app/Rendering/Viewport/ViewportHostService.hnew_editor/app/Rendering/Viewport/ViewportHostService.cppnew_editor/app/Rendering/Viewport/ViewportRenderTargets.hnew_editor/app/Rendering/Viewport/ViewportRenderTargets.cppnew_editor/app/Support/EmbeddedPngLoader.hnew_editor/app/Support/EmbeddedPngLoader.cppnew_editor/app/Platform/Win32/System/Win32SystemInteractionHost.hnew_editor/app/Platform/Win32/Content/EditorWindowContentController.h
Files expected to be retired
new_editor/app/Ports/SystemInteractionPort.hnew_editor/app/Ports/TexturePort.hnew_editor/app/Ports/ViewportRenderPort.hnew_editor/app/Ports/PortFwd.hnew_editor/app/Ports/ShaderResourceDescriptorAllocatorPort.h
7. First Execution Slice
Execute the smallest high-value slice first:
- introduce the new system and rendering host interface headers
- switch call sites away from
Ports:: - remove
ShaderResourceDescriptorAllocatorPort - leave behavior unchanged
This keeps risk lower while immediately fixing the worst architectural confusion.
8. Validation
Minimum validation for this refactor:
rg "Ports::|Ports/" new_editor/appreturns no production referencesShaderResourceDescriptorAllocatorPortno longer existsXCUIEditorAppcompiles, or any build failure is isolated and reported precisely
9. Completion Criteria
This refactor is complete only when:
app/Portsis no longer the active boundary bucket- system and rendering host boundaries are visibly separated
- D3D12-only helpers are no longer presented as generic app ports
- future contributors can answer "where should a new boundary go?" without guessing