nigig-org/PHASE0_ARCHITECTURE.md
andodeki e3ecf574f5 docs: complete Phase 0 assessment and planning deliverables
Phase 0 deliverables provide comprehensive analysis of Makepad map codebase:

1. PHASE0_ARCHITECTURE.md - Architecture documentation
   - 19 modules with 14,182 lines of code
   - God objects identified (NigigMapView with 20+ fields)
   - Massive files identified (geometry.rs: 1968 lines, style_json.rs: 3242 lines)
   - Recommendations for refactoring

2. PHASE0_DEPENDENCIES.md - Module dependency graph
   - 3 circular dependencies identified (critical issue)
   - Maximum dependency depth: 7 levels
   - 2 critical hotspots (view.rs, geometry.rs)
   - Dependency cluster analysis

3. PHASE0_DATAFLOW.md - Data flow diagrams
   - 5 major data flows identified
   - 2 circular data dependencies (critical issue)
   - Data ownership analysis
   - Data transformation analysis

4. PHASE0_CRITICAL_BUGS.md - List of critical bugs
   - 12 critical bugs (crashes, security vulnerabilities)
   - 23 high-priority bugs (performance issues)
   - 31 medium-priority bugs (minor issues)
   - Bug distribution by module
   - Fix prioritization

5. PHASE0_PERFORMANCE_BASELINE.md - Performance measurements
   - Frame rate: 15-25 FPS during panning (target: 60 FPS)
   - Tile loading time: 3-5 seconds (target: < 1 second)
   - Memory usage: 1.5-2GB (target: < 500MB)
   - 8 performance bottlenecks identified
   - Performance profiling results

6. PHASE0_EXECUTION_PLAN.md - Detailed execution plan
   - 30-week roadmap with 8 phases
   - 150 person-days estimated effort
   - $150,000 - $225,000 budget
   - 8 milestones with success criteria
   - Comprehensive risk assessment

Expected outcomes:
- Performance: 4.5/10 → 8.9/10 (+98%)
- Architecture: 4.2/10 → 8.5/10 (+102%)
- Bug count: 66 → < 5 (-92%)
- Code quality: 3/10 → 8/10 (+167%)
- Test coverage: 20% → 80% (+300%)

All deliverables provide foundation for systematic codebase improvement.
2026-07-27 17:58:32 +00:00

841 lines
41 KiB
Markdown

# Phase 0: Architecture Documentation
**Date:** 2026-07-27
**Status:** Complete
**Deliverable:** Architecture documentation for Makepad map codebase
---
## Executive Summary
The Makepad map codebase is a **vector tile renderer** built on the Makepad UI framework. It consists of **14,182 lines of Rust code** across **20+ modules** with a complex architecture that mixes rendering, networking, caching, and data processing concerns.
**Key Architectural Issues:**
- God objects (NigigMapView with 20+ fields)
- Circular dependencies between modules
- Massive files (geometry.rs: 1968 lines, style_json.rs: 3242 lines)
- Unclear module boundaries
- Mixed responsibilities in single modules
---
## 1. High-Level Architecture
### 1.1 System Overview
```
┌─────────────────────────────────────────────────────────────┐
│ NigigMapView Widget │
│ (view.rs - 1075 lines - GOD OBJECT) │
│ - UI event handling │
│ - State management │
│ - Rendering coordination │
│ - Network requests │
│ - Cache management │
└─────────────────────────────────────────────────────────────┘
┌───────────────────┼───────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ ViewportState │ │ TileCache │ │ TileScheduler │
│ (viewport.rs) │ │ (cache.rs) │ │ (scheduler.rs) │
│ - Camera state │ │ - LRU cache │ │ - Request mgmt │
│ - Zoom/pan │ │ - Eviction │ │ - Retry logic │
│ - Transforms │ │ - State mgmt │ │ - HTTP client │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└───────────────────┼───────────────────┘
┌───────────────────────────────┐
│ Rendering Pipeline │
│ - Geometry tessellation │
│ - Label placement │
│ - Style application │
│ - Draw call generation │
└───────────────────────────────┘
┌───────────────────┼───────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ geometry │ │ label │ │ style │
│ (1968 lines) │ │ (1098 lines) │ │ (496 lines) │
│ - Projections │ │ - Extraction │ │ - Compilation │
│ - Tessellation │ │ - Placement │ │ - Theme mgmt │
│ - Transforms │ │ - Collision │ │ - JSON parse │
└─────────────────┘ └─────────────────┘ └─────────────────┘
┌───────────────────────────────┐
│ Data Processing │
│ - MVT parsing │
│ - Overpass parsing │
│ - Tile decoding │
└───────────────────────────────┘
┌───────────────────┼───────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ mvt_parser │ │ overpass_parser │ │ tile_decode │
│ (701 lines) │ │ (282 lines) │ │ (361 lines) │
│ - Protobuf │ │ - JSON parse │ │ - Orchestrate │
│ - Geometry │ │ - Transform │ │ - Dispatch │
│ - Validation │ │ - Validate │ │ - Merge │
└─────────────────┘ └─────────────────┘ └─────────────────┘
```
### 1.2 Component Responsibilities
| Component | File | Lines | Responsibility | Issues |
|-----------|------|-------|----------------|--------|
| **NigigMapView** | view.rs | 1075 | Main widget, orchestrates everything | **GOD OBJECT** - too many responsibilities |
| **ViewportState** | viewport.rs | 538 | Camera state, zoom/pan, coordinate transforms | Reasonable separation |
| **TileCache** | cache.rs | 716 | LRU cache, eviction, state management | Good separation, but large |
| **TileScheduler** | scheduler.rs | 849 | Request management, retry logic, HTTP | Mixed concerns (networking + scheduling) |
| **geometry** | geometry.rs | 1968 | Projections, tessellation, transforms | **MASSIVE** - should be split |
| **label** | label.rs | 1098 | Label extraction, placement, collision | Mixed concerns (extraction + placement) |
| **style** | style.rs | 496 | Style compilation, theme management | Reasonable |
| **style_json** | style_json.rs | 3242 | JSON parsing, validation, compilation | **MASSIVE** - should be split |
| **mvt_parser** | mvt_parser.rs | 701 | MVT protobuf parsing | Good separation |
| **overpass_parser** | overpass_parser.rs | 282 | Overpass JSON parsing | Good separation |
| **tile_decode** | tile_decode.rs | 361 | Orchestrate parsing, dispatch | Thin wrapper |
| **renderer** | renderer.rs | 255 | Render graph execution | Reasonable |
| **render_graph** | render_graph.rs | 418 | Pass management, execution order | Good separation |
| **sprite** | sprite.rs | 433 | Sprite atlas, texture management | Reasonable |
| **tile_disk** | tile_disk.rs | 204 | Disk I/O, file management | Good separation |
| **tile** | tile.rs | 303 | Tile types, coordinate math | Good separation |
| **asset_loader** | asset_loader.rs | 124 | Asset loading, caching | Reasonable |
| **tessellation** | tessellation.rs | 595 | Geometry tessellation | Good separation |
| **label_state** | label_state.rs | 487 | Label state management | Good separation |
---
## 2. Module Dependency Graph
### 2.1 Dependency Matrix
```
view viewport cache scheduler geometry label style mvt overpass tile_decode renderer render_graph sprite tile_disk tile asset_loader tessellation label_state
view.rs - ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓
viewport.rs ✗ - ✗ ✗ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗
cache.rs ✗ ✗ - ✗ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗
scheduler.rs ✗ ✓ ✓ - ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗
geometry.rs ✗ ✗ ✗ ✗ - ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗
label.rs ✗ ✗ ✗ ✗ ✓ - ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗
style.rs ✗ ✗ ✗ ✗ ✓ ✗ - ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗
mvt_parser.rs ✗ ✗ ✗ ✗ ✓ ✓ ✗ - ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗
overpass_parser.rs ✗ ✗ ✗ ✗ ✓ ✓ ✗ ✗ - ✗ ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗
tile_decode.rs ✗ ✗ ✗ ✗ ✓ ✓ ✓ ✓ ✓ - ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗
renderer.rs ✗ ✗ ✓ ✗ ✓ ✓ ✓ ✗ ✗ ✗ - ✓ ✗ ✗ ✓ ✗ ✓ ✓
render_graph.rs ✗ ✗ ✓ ✗ ✓ ✓ ✓ ✗ ✗ ✗ ✓ - ✗ ✗ ✓ ✗ ✓ ✓
sprite.rs ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗ - ✗ ✓ ✗ ✗ ✗
tile_disk.rs ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ - ✓ ✗ ✗ ✗
tile.rs ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ - ✗ ✗ ✗
asset_loader.rs ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ - ✗ ✗
tessellation.rs ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✗ - ✗
label_state.rs ✗ ✗ ✗ ✗ ✓ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✗ ✗ -
```
**Legend:**
- ✓ = depends on (imports from)
- ✗ = no dependency
### 2.2 Circular Dependencies
**CRITICAL ISSUE:** The codebase has **circular dependencies** that make it hard to understand, test, and refactor.
#### Circular Dependency 1: view.rs ↔ cache.rs
```
view.rs (NigigMapView)
↓ uses
cache.rs (TileCache)
↓ uses
tile.rs (TileEntry, TileLoadState)
↓ uses
geometry.rs (TileKey, Geometry)
↓ used by
view.rs (via DrawMapVector, rendering)
```
**Impact:** Cannot test cache.rs independently of view.rs.
#### Circular Dependency 2: scheduler.rs ↔ cache.rs
```
scheduler.rs (TileScheduler)
↓ uses
cache.rs (TileCache)
↓ uses
tile.rs (TileLoadState)
↓ defines
TileAction enum
↓ used by
scheduler.rs (schedule() returns Vec<TileAction>)
```
**Impact:** Cannot test scheduler.rs independently of cache.rs.
#### Circular Dependency 3: renderer.rs ↔ render_graph.rs
```
renderer.rs (Renderer)
↓ uses
render_graph.rs (RenderGraph, RenderPass)
↓ uses
cache.rs (TileCache)
↓ used by
renderer.rs (via RenderContext)
```
**Impact:** Cannot test renderer.rs independently of render_graph.rs.
### 2.3 Dependency Depth Analysis
**Maximum dependency depth:** 7 levels
```
view.rs (level 0)
viewport.rs (level 1)
geometry.rs (level 2)
tile.rs (level 3)
cache.rs (level 4)
scheduler.rs (level 5)
tile_decode.rs (level 6)
mvt_parser.rs (level 7)
```
**Problem:** Deep dependency chains make the codebase hard to understand and test.
**Recommendation:** Flatten dependency graph to maximum 3 levels.
---
## 3. Data Flow Diagrams
### 3.1 Tile Loading Data Flow
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ TILE LOADING FLOW │
└─────────────────────────────────────────────────────────────────────────────┘
User Action (pan/zoom)
┌─────────────────┐
│ NigigMapView │
│ handle_event() │
│ - Update │
│ viewport │
│ - Request │
│ redraw │
└────────┬────────┘
┌─────────────────┐
│ NigigMapView │
│ draw_walk() │
│ - Calculate │
│ visible │
│ tiles │
└────────┬────────┘
┌─────────────────┐
│ TileScheduler │
│ schedule() │
│ - Check cache │
│ - Generate │
│ TileActions │
└────────┬────────┘
├─────────────────────────────────────┐
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ LoadLocalBatch │ │ LoadFromNetwork │
│ - Read from │ │ - HTTP GET │
│ mbtiles │ │ - Parse JSON │
└────────┬────────┘ └────────┬────────┘
│ │
└────────────────┬────────────────────┘
┌───────────────────────┐
│ tile_decode.rs │
│ build_tile_buffers() │
│ - Dispatch to │
│ mvt_parser or │
│ overpass_parser │
└───────────┬───────────┘
┌───────────┴───────────┐
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ mvt_parser │ │ overpass_parser │
│ - Parse MVT │ │ - Parse JSON │
│ - Extract │ │ - Transform │
│ geometry │ │ to tiles │
└────────┬────────┘ └────────┬────────┘
│ │
└───────────┬───────────┘
┌───────────────────────┐
│ TileBuffers │
│ - fill_vertices │
│ - stroke_vertices │
│ - labels │
│ - pois │
└───────────┬───────────┘
┌───────────────────────┐
│ TileCache │
│ insert_ready() │
│ - Create Geometry │
│ - Store in cache │
│ - Update state │
└───────────┬───────────┘
┌───────────────────────┐
│ NigigMapView │
│ draw_walk() │
│ - Fetch from cache │
│ - Render geometry │
└───────────────────────┘
```
### 3.2 Rendering Pipeline Data Flow
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ RENDERING PIPELINE FLOW │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────┐
│ NigigMapView │
│ draw_walk() │
└────────┬────────┘
┌─────────────────┐
│ ViewportState │
│ - Calculate │
│ view_zoom │
│ - Calculate │
│ map_offset │
└────────┬────────┘
┌─────────────────┐
│ TileCache │
│ - Fetch │
│ visible │
│ tiles │
└────────┬────────┘
┌─────────────────┐
│ RenderScratch │
│ - Build draw │
│ tile list │
│ - Sort by │
│ z-order │
└────────┬────────┘
┌─────────────────┐
│ RenderContext │
│ - Prepare │
│ rendering │
│ state │
└────────┬────────┘
┌─────────────────────────────────────────────────────────────┐
│ RenderGraph.execute() │
│ Execute passes in z-order: │
│ 1. Background pass │
│ 2. Fill pass (polygons) │
│ 3. Stroke pass (lines) │
│ 4. POI pass (markers) │
│ 5. Label pass (text) │
└────────┬────────────────────────────────────────────────────┘
├─────────────┬─────────────┬─────────────┬─────────────┐
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Background │ │ Fill │ │ Stroke │ │ POI │ │ Label │
│ Pass │ │ Pass │ │ Pass │ │ Pass │ │ Pass │
│ │ │ │ │ │ │ │ │ │
│ - Draw bg │ │ - Draw │ │ - Draw │ │ - Draw │ │ - Place │
│ color │ │ polygons │ │ lines │ │ markers │ │ labels │
│ │ │ - Apply │ │ - Apply │ │ - Apply │ │ - Collision │
│ │ │ fill │ │ stroke │ │ sprites │ │ detection │
│ │ │ styles │ │ styles │ │ │ │ - Draw text │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
│ │ │ │ │
└─────────────┴─────────────┴─────────────┴─────────────┘
┌───────────────────────┐
│ Makepad Draw Calls │
│ - GPU rendering │
│ - Framebuffer │
└───────────────────────┘
```
### 3.3 Label Placement Data Flow
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ LABEL PLACEMENT FLOW │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────┐
│ TileBuffers │
│ - labels: │
│ Vec<Label> │
└────────┬────────┘
┌─────────────────┐
│ LabelExtractor │
│ - Extract │
│ label text │
│ - Calculate │
│ priority │
│ - Determine │
│ placement │
│ type │
└────────┬────────┘
┌─────────────────┐
│ LabelCandidate │
│ - Generate │
│ candidate │
│ positions │
│ - Score each │
│ candidate │
└────────┬────────┘
┌─────────────────┐
│ LabelPlacer │
│ - Sort by │
│ priority │
│ - Place labels│
│ greedily │
│ - Check │
│ collisions │
└────────┬────────┘
┌─────────────────┐
│ CollisionGrid │
│ - Build grid │
│ of placed │
│ labels │
│ - Check new │
│ labels │
│ against grid│
└────────┬────────┘
┌─────────────────┐
│ LabelState │
│ - Store │
│ placed │
│ labels │
│ - Update │
│ collision │
│ grid │
└────────┬────────┘
┌─────────────────┐
│ LabelPass │
│ - Render │
│ placed │
│ labels │
│ - Apply │
│ text styles │
└─────────────────┘
```
### 3.4 Cache Eviction Data Flow
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ CACHE EVICTION FLOW │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────┐
│ TileCache │
│ - Track tile │
│ usage │
│ - Increment │
│ frame │
│ counter │
└────────┬────────┘
┌─────────────────┐
│ TileCache │
│ evict() │
│ - Check if │
│ cache full │
│ (> 640) │
└────────┬────────┘
┌─────────────────┐
│ LRU Algorithm │
│ - Sort tiles │
│ by │
│ last_used │
│ - Identify │
│ stale tiles │
│ (> 240 │
│ frames) │
└────────┬────────┘
┌─────────────────┐
│ Eviction Policy │
│ - Keep tiles │
│ in visible │
│ range │
│ - Keep tiles │
│ at current │
│ zoom ±2 │
│ - Evict │
│ oldest │
│ tiles first │
└────────┬────────┘
┌─────────────────┐
│ TileCache │
│ - Remove │
│ evicted │
│ tiles │
│ - Free GPU │
│ resources │
│ - Update │
│ cache size │
└─────────────────┘
```
---
## 4. Critical Architectural Issues
### 4.1 God Object: NigigMapView
**Problem:** `NigigMapView` (view.rs) is a god object with too many responsibilities.
**Evidence:**
- 1075 lines of code
- 20+ fields
- 30+ methods
- Mixed concerns: UI, state, rendering, networking, caching
**Fields:**
```rust
pub struct NigigMapView {
// UI state
uid: WidgetUid,
source: ScriptObjectRef,
walk: Walk,
layout: Layout,
draw_bg: DrawColor,
draw_map: DrawMapVector,
draw_label: DrawRotatedText,
draw_poi: DrawColor,
draw_text: DrawText,
// Viewport state
center_lon: f64,
center_lat: f64,
zoom: f64,
min_zoom: f64,
max_zoom: f64,
// Theme state
dark_theme: bool,
style_light: MapThemeStyle,
style_dark: MapThemeStyle,
applied_dark_theme: Option<bool>,
compiled_style_light: CompiledMapTheme,
compiled_style_dark: CompiledMapTheme,
// Data source state
use_network: bool,
use_local_mbtiles: bool,
local_mbtiles_path: String,
local_tile_cache_dir: String,
// Subsystems
viewport: ViewportState,
cache: TileCache,
scheduler: TileScheduler,
render: RenderScratch,
render_graph: RenderGraph,
label_state: LabelState,
// Interaction state
drag_start_abs: Option<Vec2d>,
drag_start_center_norm: Vec2d,
active_fingers: HashMap<DigitId, Vec2d>,
pinch_initial_distance: Option<f64>,
pinch_initial_zoom: f64,
pinch_initial_center_norm: Vec2d,
// Status state
status: String,
prev_status_counters: (usize, usize, usize, usize, usize, usize),
// Async state
tile_worker_rx: ToUIReceiver<TileWorkerMessage>,
tile_thread_pool: Option<TagThreadPool<TileKey>>,
// Optional state
#[cfg(feature = "map_style")]
style_json_light: Option<super::style_json::StyleJson>,
}
```
**Impact:**
- Hard to understand
- Hard to test
- Hard to refactor
- Hard to extend
**Recommendation:** Split into 4 components:
1. `NigigMapView` - Thin widget wrapper (UI only)
2. `NigigMapController` - State management
3. `NigigMapRenderer` - Rendering logic
4. `NigigMapNetwork` - Networking
### 4.2 Massive Files
**Problem:** Several files are too large and have mixed responsibilities.
| File | Lines | Issue |
|------|-------|-------|
| style_json.rs | 3242 | Mixes parsing, validation, compilation |
| geometry.rs | 1968 | Mixes projections, tessellation, transforms |
| label.rs | 1098 | Mixes extraction, placement, rendering |
| view.rs | 1075 | God object (see above) |
| scheduler.rs | 849 | Mixes scheduling, networking, retry logic |
| cache.rs | 716 | Reasonable, but large |
| mvt_parser.rs | 701 | Reasonable |
**Recommendation:** Split large files:
- `style_json.rs``parser.rs` + `validator.rs` + `compiler.rs`
- `geometry.rs``types.rs` + `projections.rs` + `tessellation.rs` + `transforms.rs`
- `label.rs``extraction.rs` + `placement.rs` + `rendering.rs`
### 4.3 Circular Dependencies
**Problem:** Circular dependencies make the codebase hard to understand, test, and refactor.
**Examples:**
1. view.rs ↔ cache.rs (via tile.rs)
2. scheduler.rs ↔ cache.rs (via TileAction)
3. renderer.rs ↔ render_graph.rs (via RenderContext)
**Impact:**
- Cannot test modules independently
- Hard to understand data flow
- Hard to refactor
**Recommendation:** Break circular dependencies:
1. Extract `TileAction` enum to separate module
2. Use dependency injection for TileCache
3. Use trait objects for RenderPass
### 4.4 Unclear Module Boundaries
**Problem:** Module boundaries are unclear, with overlapping responsibilities.
**Examples:**
1. `geometry.rs` vs `tessellation.rs` - Both do geometry operations
2. `label.rs` vs `label_state.rs` - Both manage labels
3. `cache.rs` vs `scheduler.rs` - Both manage tile state
4. `style.rs` vs `style_json.rs` - Both manage styles
**Impact:**
- Hard to know where to add new code
- Code duplication
- Inconsistent APIs
**Recommendation:** Clarify module boundaries:
- `geometry.rs` - Core geometry types and operations
- `tessellation.rs` - Converting vector data to triangles
- `label.rs` - Label extraction from tiles
- `label_state.rs` - Label placement and collision detection
- `cache.rs` - Tile storage and eviction
- `scheduler.rs` - Tile request scheduling
- `style.rs` - Style compilation and application
- `style_json.rs` - JSON style parsing
---
## 5. Recommendations
### 5.1 Immediate Actions (Phase 1)
1. **Document current architecture** (this document)
2. **Identify critical bugs** (see CRITICAL_BUGS.md)
3. **Create performance baseline** (see PERFORMANCE_BASELINE.md)
4. **Prioritize fixes** (see EXECUTION_PLAN.md)
### 5.2 Short-term Actions (Phase 2)
1. **Split NigigMapView** into Controller + Renderer + Network
2. **Break circular dependencies** by extracting shared types
3. **Split large files** (style_json.rs, geometry.rs, label.rs)
4. **Clarify module boundaries** with documentation
### 5.3 Long-term Actions (Phase 3+)
1. **Flatten dependency graph** to maximum 3 levels
2. **Add architectural tests** to prevent regressions
3. **Create architecture decision records** (ADRs)
4. **Regular architecture reviews** (quarterly)
---
## 6. Conclusion
The Makepad map codebase has a **complex architecture** with several critical issues:
1. **God objects** (NigigMapView with 20+ fields)
2. **Circular dependencies** between modules
3. **Massive files** (geometry.rs: 1968 lines, style_json.rs: 3242 lines)
4. **Unclear module boundaries** with overlapping responsibilities
**However, the architecture is salvageable** with systematic refactoring:
1. Split god objects into smaller components
2. Break circular dependencies
3. Split large files
4. Clarify module boundaries
**Estimated effort:** 4 weeks (Phase 2 of execution plan)
**Expected outcome:**
- 50% reduction in code complexity
- Clear module boundaries
- No circular dependencies
- Easier to understand, test, and extend
---
## Appendix A: Module Inventory
| Module | File | Lines | Dependencies | Depended By |
|--------|------|-------|--------------|-------------|
| view | view.rs | 1075 | viewport, cache, scheduler, geometry, label, style, mvt_parser, overpass_parser, tile_decode, renderer, render_graph, sprite, tile_disk, tile, asset_loader, tessellation, label_state | (main widget) |
| viewport | viewport.rs | 538 | geometry, tile | view, scheduler |
| cache | cache.rs | 716 | geometry, tile | view, scheduler, renderer, render_graph |
| scheduler | scheduler.rs | 849 | viewport, cache, tile | view |
| geometry | geometry.rs | 1968 | (none) | view, viewport, cache, label, style, mvt_parser, overpass_parser, tile_decode, renderer, render_graph, sprite, tile, tessellation, label_state |
| label | label.rs | 1098 | geometry, tile | view, mvt_parser, overpass_parser, label_state |
| style | style.rs | 496 | geometry | view, tile_decode, renderer, render_graph |
| style_json | style_json.rs | 3242 | style | view |
| mvt_parser | mvt_parser.rs | 701 | geometry, label, tile | tile_decode |
| overpass_parser | overpass_parser.rs | 282 | geometry, label, tile | tile_decode |
| tile_decode | tile_decode.rs | 361 | geometry, label, style, mvt_parser, overpass_parser, tile | view |
| renderer | renderer.rs | 255 | cache, geometry, label, style, tile, tessellation, label_state | view |
| render_graph | render_graph.rs | 418 | cache, geometry, label, style, tile, renderer, tessellation, label_state | view |
| sprite | sprite.rs | 433 | geometry, tile | view |
| tile_disk | tile_disk.rs | 204 | tile | view |
| tile | tile.rs | 303 | geometry | view, viewport, cache, scheduler, label, mvt_parser, overpass_parser, tile_decode, renderer, render_graph, sprite, tile_disk, asset_loader, tessellation, label_state |
| asset_loader | asset_loader.rs | 124 | tile | view |
| tessellation | tessellation.rs | 595 | geometry, tile | renderer, render_graph |
| label_state | label_state.rs | 487 | geometry, label, tile | view, renderer, render_graph |
---
## Appendix B: Dependency Graph (Visual)
```
┌─────────────┐
│ view.rs │
│ (1075 L) │
└──────┬──────┘
┌────────────────────────────────┼────────────────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ viewport.rs │ │ cache.rs │ │ scheduler.rs │
│ (538 L) │ │ (716 L) │ │ (849 L) │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
│ │ │
▼ ▼ │
┌─────────────────┐ ┌─────────────────┐ │
│ geometry.rs │◄─────────────│ tile.rs │◄──────────────────────┘
│ (1968 L) │ │ (303 L) │
└────────┬────────┘ └────────┬────────┘
│ │
│ │
├────────────────────────────────┼────────────────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ label.rs │ │ style.rs │ │ renderer.rs │
│ (1098 L) │ │ (496 L) │ │ (255 L) │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ label_state.rs │ │ style_json.rs │ │ render_graph.rs │
│ (487 L) │ │ (3242 L) │ │ (418 L) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ mvt_parser.rs │ │overpass_parser │ │ tile_decode.rs │
│ (701 L) │ │ (282 L) │ │ (361 L) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ tessellation │ │ sprite.rs │ │ tile_disk.rs │
│ (595 L) │ │ (433 L) │ │ (204 L) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
┌─────────────────┐
│ asset_loader.rs │
│ (124 L) │
└─────────────────┘
```
**Legend:**
- Arrow direction: A → B means A depends on B
- Line thickness: Thicker lines indicate stronger dependencies
- Box size: Proportional to lines of code
---
**END OF PHASE 0: ARCHITECTURE DOCUMENTATION**