Files
py-dvt-ate/docs/03_architecture_decisions.md
Kai Chappell 89e644154d Update development plan with vertical slice approach
- Reorder sprints for visual-first development
- Dashboard (Sprint 4) now follows Physics Engine (Sprint 3)
- Infrastructure layers (SCPI, TCP, HAL) follow visual demo
- Update project references to py-dvt-ate
2025-01-22 12:14:32 +00:00

11 KiB

Architecture Decision Record

py_dvt_ate: Technical Architecture Decisions

Document ID ARD-001
Version 1.1.0
Status Draft
Author Kai Chappell
Created 2025-12-01
Last Updated 2025-12-01

Purpose

This document captures the rationale behind architectural decisions. It explains why certain approaches were chosen over alternatives.

For what the system must do, see 01_requirements.md. For how to implement the system, see 02_technical_specification.md.


Document Purpose
01_requirements.md Defines what the system must do
02_technical_specification.md Specifies how to implement the system
03_architecture_decisions.md Explains why decisions were made (this document)

Table of Contents

  1. Guiding Principles
  2. Decision Log

1. Guiding Principles

These principles guided all architectural decisions:

Principle Rationale
Single Responsibility Reduces coupling; each module changes for one reason only
Dependency Inversion Enables testing and hardware swapping without code changes
Explicit Dependencies Makes code predictable; no hidden global state
Fail Fast Problems surface immediately rather than propagating
Configuration over Code Runtime behaviour changes without recompilation
Engineering Efficiency Prioritise development velocity using appropriate tools

2. Decision Log

ADR-001: Programming Language

Aspect Content
Context Need to choose primary implementation language for a DVT automation platform
Decision Python 3.11+
Why This Choice Python is the industry standard for test automation. Hiring managers for DVT roles expect Python proficiency. The ecosystem (NumPy, SciPy, PyVISA) directly supports the problem domain. A single language reduces context-switching and demonstrates depth over breadth.
Trade-offs Accepted Slower execution than compiled languages (acceptable for 100Hz simulation). Dynamic typing requires discipline (mitigated with type hints and mypy).
Alternatives Rejected LabVIEW (proprietary, not demonstrable in portfolio), C++ (slower development velocity), TypeScript (not standard in ATE domain)

ADR-002: Frontend Approach

Aspect Content
Context Need user interface for test execution and monitoring. Must balance effort against target role (DVT/Backend, not Frontend). Must demonstrate engineering efficiency.
Decision CLI-first with Streamlit dashboard
Why This Choice CLI demonstrates core functionality without UI overhead. Streamlit enables rapid iteration on dashboard UI using pure Python—no JavaScript, CSS, or complex state management required. This demonstrates 'Engineering Efficiency': building effective internal tools quickly using appropriate technology. Real ATE tools at hardware companies are often CLI or simple Python GUIs, not React SPAs.
Trade-offs Accepted Streamlit has limitations for complex interactivity. Less customisable than React. Re-runs script on interaction (mitigated with caching).
Alternatives Rejected React (wrong skill signal for DVT roles, major time investment, JavaScript required), Panel (more powerful but steeper learning curve, slower iteration), PyQt (higher complexity, dated appearance)

ADR-003: Data Persistence Strategy

Aspect Content
Context Need to persist test metadata and high-frequency measurement data
Decision SQLite for metadata + Parquet for time-series measurements
Why This Choice SQLite requires no server process—the entire system remains self-contained. Parquet is columnar and optimised for analytical queries on measurement data. Both are file-based, making projects portable and easy to share. Standard library (sqlite3) and well-supported (PyArrow) tools demonstrate effective use of established technologies before reaching for external dependencies.
Trade-offs Accepted Single-user only (acceptable for portfolio project). No real-time replication. Query capabilities limited to pandas/SQL without additional tools.
Alternatives Rejected PostgreSQL (requires server, adds infrastructure complexity), InfluxDB (another service to manage), DuckDB (additional dependency not strictly necessary for single-user simulator)

ADR-004: Instrument Communication Protocol

Aspect Content
Context Need protocol for test application to communicate with simulated instruments
Decision SCPI over TCP/IP sockets
Why This Choice SCPI is the industry standard for programmable instruments (IEEE 488.2). Using the real protocol means the same drivers work with real hardware. TCP/IP enables process separation and future network deployment. Demonstrates domain knowledge to reviewers.
Trade-offs Accepted Must implement SCPI parser. Network overhead (negligible on localhost).
Alternatives Rejected Direct function calls (wouldn't demonstrate real-world architecture), gRPC (not industry standard for instruments), REST API (not SCPI-compliant, wouldn't transfer to real hardware)

ADR-005: Process Architecture

Aspect Content
Context Need to decide if physics simulation runs in-process or separately
Decision Simulation server runs as separate process
Why This Choice Mimics real hardware architecture where instruments are separate devices. Forces clean network boundaries that translate to real deployments. Enables Docker containerisation with proper service separation. The same test code works whether talking to simulation or real instruments over network.
Trade-offs Accepted Process management complexity. Inter-process communication overhead.
Alternatives Rejected In-process simulation (wouldn't demonstrate production architecture, wouldn't prove hardware abstraction works)

ADR-006: Hardware Abstraction Mechanism

Aspect Content
Context Need to swap between simulated and real instruments without changing test code
Decision Python Protocol classes (structural typing) with Factory pattern
Why This Choice Protocols enable interface-based programming without inheritance coupling. Factory centralises the simulator-vs-real decision to configuration. No heavy DI framework needed—Python's simplicity is sufficient. Demonstrates understanding of SOLID principles and dependency injection.
Trade-offs Accepted Manual wiring in factory (acceptable at this scale). Protocols require Python 3.8+.
Alternatives Rejected Abstract Base Classes only (less flexible than Protocols), DI framework like dependency-injector (over-engineering for this scale), No abstraction (would couple test code to simulator)

ADR-007: Concurrency Model

Aspect Content
Context Need to handle concurrent instrument connections and real-time physics updates
Decision asyncio for simulation server; synchronous-first for test code
Why This Choice Server must handle multiple simultaneous connections efficiently—asyncio is Python's standard solution. Test code is inherently sequential (set voltage, wait, measure), so forcing async everywhere adds complexity without benefit. Clear boundary at transport layer.
Trade-offs Accepted Two patterns to understand. Must be careful about blocking calls in async context.
Alternatives Rejected Threading everywhere (GIL limitations, harder to reason about), Full async in test code (unnecessary complexity, test sequences are sequential)

ADR-008: Configuration Format

Aspect Content
Context Need human-readable, version-controllable configuration
Decision YAML files validated with Pydantic
Why This Choice YAML supports comments (unlike JSON), making configs self-documenting. Pydantic provides type-safe parsing with clear error messages. Configs can be version-controlled alongside code.
Trade-offs Accepted YAML has some parsing quirks (Norway problem). Pydantic v2 has breaking changes from v1.
Alternatives Rejected JSON (no comments), TOML (less common in Python data ecosystem), Environment variables only (not structured enough for complex config)

ADR-009: Testing Philosophy

Aspect Content
Context Need automated testing strategy for quality assurance
Decision pytest with dependency injection via fixtures; 80% coverage target on core modules
Why This Choice pytest is the Python community standard. Fixtures align with DI pattern—inject mocks at test boundaries. 80% coverage balances thoroughness with pragmatism. Demonstrates professional engineering practices expected at senior level.
Trade-offs Accepted Must design for testability from the start. Some integration tests require running simulation server.
Alternatives Rejected No tests (unacceptable for portfolio demonstrating senior-level work), unittest (less ergonomic than pytest), 100% coverage target (diminishing returns, encourages testing trivial code)

ADR-010: Project Structure

Aspect Content
Context Need to organise code for clarity and maintainability
Decision Monorepo with src layout and package-per-concern
Why This Choice Single repository simplifies development for a solo developer. Src layout is Python packaging best practice (prevents import confusion). Package-per-concern makes dependencies explicit and enforceable.
Trade-offs Accepted Must configure editable installs for development. All code in one repo (acceptable at this scale).
Alternatives Rejected Flat structure (poor for larger codebases), Multi-repo (overhead for single developer), Package-per-layer only (too coarse-grained)

ADR-011: Development Phasing Strategy

Aspect Content
Context Need to prioritise features for efficient delivery of portfolio-quality project
Decision Vertical Slice approach: deliver end-to-end functionality (Physics → HAL → Driver → UI) before adding horizontal features (reporting, API)
Why This Choice A working "Virtual Lab Bench" demonstrates the core value proposition immediately. Vertical slices reduce integration risk—problems surface early. Defers low-value work (PDF formatting) until core is proven. Enables meaningful demos at every phase.
Trade-offs Accepted Some infrastructure (reporting) delayed. May need refactoring when adding phases.
Alternatives Rejected Horizontal layers first (delays integration, hides problems), Feature-complete phases (too long between demos), MVP without UI (harder to demonstrate value)

End of Architecture Decision Record