docs: record the layering rule and where it is enforced
The architecture section listed files but said nothing about which layer may import what, so the direction of dependency was only visible by reading the imports. States the rule as a table, notes that the UI depends on the Iperf3Runner contract rather than on a transport and what that buys, and points at the test that enforces it so the rule is not just prose. Also brings the tree up to date: it was missing the domain services directory, the event model and the formatter. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+34
-8
@@ -6,19 +6,23 @@ A Flutter-based Android GUI wrapper for iperf3, the popular network performance
|
|||||||
|
|
||||||
```
|
```
|
||||||
lib/ # Flutter/Dart application layer
|
lib/ # Flutter/Dart application layer
|
||||||
├── main.dart # App entry point (MaterialApp)
|
├── main.dart # Composition root: picks the Iperf3Runner impl
|
||||||
├── domain/ # Business logic (platform-independent)
|
├── domain/ # Pure Dart — no Flutter import
|
||||||
│ ├── models/
|
│ ├── models/
|
||||||
│ │ ├── test_configuration.dart # Server, port, duration, interval, parallel streams
|
│ │ ├── test_configuration.dart # Server, port, duration, interval, parallel streams
|
||||||
│ │ └── iperf3_result.dart # Raw output + exit code
|
│ │ ├── iperf3_result.dart # Raw output, exit code, stopped flag
|
||||||
├── data/
|
│ │ └── iperf3_event.dart # Parsed --json-stream reports
|
||||||
│ └── services/
|
│ └── services/
|
||||||
│ └── iperf3_service.dart # Dart → MethodChannel bridge (async with Completer)
|
│ └── iperf3_runner.dart # The contract the UI depends on
|
||||||
└── ui/ # Presentation layer
|
├── data/ # Transport — flutter/services only
|
||||||
|
│ └── services/
|
||||||
|
│ └── iperf3_service.dart # Iperf3Runner over MethodChannel → JNI
|
||||||
|
└── ui/ # Presentation
|
||||||
└── features/
|
└── features/
|
||||||
└── test_run/
|
└── test_run/
|
||||||
├── test_run_screen.dart # Server/port inputs + GO button
|
├── test_run_screen.dart # Inputs, GO/STOP, live transcript
|
||||||
└── test_run_view_model.dart # State machine: idle → running → completed/error
|
├── test_run_view_model.dart # idle → running → completed/error
|
||||||
|
└── iperf3_event_formatter.dart # Events → iperf3-style text
|
||||||
|
|
||||||
android/app/src/main/
|
android/app/src/main/
|
||||||
├── kotlin/ # Kotlin plugin layer
|
├── kotlin/ # Kotlin plugin layer
|
||||||
@@ -48,6 +52,28 @@ User taps GO
|
|||||||
→ On completion: Dart Completer resolves with Iperf3Result
|
→ On completion: Dart Completer resolves with Iperf3Result
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Layering
|
||||||
|
|
||||||
|
Dependencies point inward: `ui → domain ← data`, never the reverse.
|
||||||
|
|
||||||
|
| Layer | May import | Holds |
|
||||||
|
|---|---|---|
|
||||||
|
| `domain` | nothing else in this package, no Flutter | models and the `Iperf3Runner` contract |
|
||||||
|
| `data` | `domain`, `package:flutter/services.dart` | the MethodChannel/JNI implementation |
|
||||||
|
| `ui` | `domain` | widgets, view model, formatting |
|
||||||
|
| `main.dart` | everything | the single place that picks an implementation |
|
||||||
|
|
||||||
|
The UI depends on `Iperf3Runner`, not on `Iperf3Service`, so presentation names
|
||||||
|
no transport. That is what lets `test/widget_test.dart` drive the real widget
|
||||||
|
tree against an in-memory runner with no MethodChannel, native library or
|
||||||
|
device — and what keeps a test double at five stable members instead of
|
||||||
|
mirroring the transport's whole surface.
|
||||||
|
|
||||||
|
`test/architecture_test.dart` enforces all of this by reading the actual
|
||||||
|
imports under `lib/`, including a check that no fourth layer directory has
|
||||||
|
appeared unnoticed. Change the layering there when the layering should change;
|
||||||
|
don't work around it.
|
||||||
|
|
||||||
## Key Design Decisions
|
## Key Design Decisions
|
||||||
|
|
||||||
### JNI Over Process Execution
|
### JNI Over Process Execution
|
||||||
|
|||||||
Reference in New Issue
Block a user