Files
landscape/adr/approved/ADR1_application-size.md

216 lines
10 KiB
Markdown

**ID:** ADR1 \
**Title:** Application size \
**Supersedes:** - \
**Status:** APPROVED \
**Expiration Date:** Six months after approval; record the calendar date upon manual approval.
## Context
Agile Dancers currently keeps its frontend, backend, CI pipeline, skills,
specifications, ADRs, and other documentation in one repository. As the application
grows, humans and agents need more context to understand individual tasks.
Functional dependencies can become entangled, making changes and reuse harder.
The primary goal is to reduce the context required for a task. Supporting goals
are preventing uncontrolled coupling and enabling reuse and replacement of
capabilities. Repository organization, module boundaries, and deployment
boundaries are separate architectural choices.
Business capabilities stand on their own, while an application system may support
multiple capabilities. Loosely coupled capability boundaries allow implementations
to change between custom software, libraries, and externally supplied components.
Scheduling and school administration are candidate areas to examine; their exact
system boundaries have not yet been decided.
Code-level modularity alone is insufficient when shared tables, materialized
views, SQL scripts, or other database access bypass module boundaries. Separate
services would have the same weakness without enforced data ownership.
Systems can initially run on the same physical server. Independent workload
placement is nevertheless useful: computational work, such as runners and future
scheduling calculations, may run on a mini-PC rather than the Synology. Independent
scaling and release cycles are future possibilities rather than universal current
requirements. Colocation reduces network exposure but process restarts, timeouts,
and resource contention still require defined failure behavior.
Reusable engineering resources should also support other projects. Specifications
can affect several projects, and ADRs apply across the application landscape.
## Decisions
### Capabilities and systems
Organize the landscape into independently deployable systems. Group capabilities
into systems according to cohesion, data ownership, replacement needs, and
operational requirements, including workload placement. Capability size alone does
not justify a separate system.
Each system has its own repository and independent deployment lifecycle. Within a
system, use modules to keep its capabilities loosely coupled. A capability does
not automatically require its own service or deployment. Compute workers may be
deployed separately from the business system that delegates work to them.
Capability contracts should allow implementations to be replaced by custom code,
libraries, or external products, using adapters where necessary.
### Data ownership
Each system exclusively owns its data. Other systems access that data through
explicit contracts, never through direct access to its storage. This restriction
also applies to reporting queries, views, migrations, and maintenance scripts.
Cross-system reporting requires explicit contracts or a separately owned
projection.
PostgreSQL-backed systems initially share one PostgreSQL server/container, with
separate databases or schemas and separate credentials whose permissions enforce
ownership. Sharing physical infrastructure does not permit sharing storage access.
Systems may choose other storage technologies when justified. This permits future
CQRS designs without adopting CQRS through this ADR.
### Contracts and communication
Systems communicate through explicit, versioned contracts. Internal domain models
and persistence entities remain private to their owning system and are not shared
through common libraries. Contract definitions and generated clients may be shared.
Choose synchronous APIs or asynchronous messaging for each interaction according
to its needs. Define failure behavior for each interaction. This ADR mandates
neither a landscape-wide communication mechanism nor a message broker.
### Landscape and engineering resources
Maintain a landscape repository containing ADRs, specifications, and the capability
and system map. Specifications identify the projects they affect and may span
multiple systems. ADRs govern the application landscape according to their scope.
Each system retains a README describing its implementation and operation.
Maintain reusable engineering resources, including pipeline components, skills,
and general engineering documentation, separately from the landscape repository
and individual systems. Group these resources according to maintenance and release
needs; a separate repository per resource type is not required. Version shared
resources so consuming projects can adopt updates deliberately.
### Adoption and review
Use this ADR as guidance and the starting point for follow-up specifications.
Detailed system boundaries, contracts, and migration designs are follow-up work.
Migrate incrementally, keeping the application working after each extraction.
Perform an initial review six months after approval. Review earlier if contract
coordination, operational overhead, or persistent cross-system coupling becomes a
significant burden. The expiration date triggers reevaluation and does not
automatically invalidate the decision.
## Options considered
### 1. Improve navigation within the current structure
Keep the existing projects and deployment structure, improving focused
documentation, task guidance, and file organization.
Pros:
- Requires little disruption or migration work.
- Makes relevant context easier to find.
- Retains simple local development and coordinated changes.
Cons:
- Offers limited protection against functional entanglement.
- Does not enforce data ownership or support independent workload placement.
- Leaves reuse and replacement dependent on existing application boundaries.
Not chosen because navigation improvements alone do not establish the ownership
and replacement boundaries needed as the landscape grows.
### 2. Modular monolith in one repository
Organize capabilities into modules with explicit interfaces and dependency rules,
while retaining coordinated deployment and one repository.
Pros:
- Reduces the code area needed to understand a capability.
- Enables dependency checks and straightforward changes across modules.
- Keeps deployment and in-process communication simple.
Cons:
- Shared database access can bypass code-level boundaries through tables, views,
and scripts unless storage ownership is separately enforced.
- Workload placement and deployment remain coupled.
- Independent replacement and reuse may require later extraction.
Not chosen as the landscape-wide approach because independently enforced ownership
and deployment boundaries are desired. Modular design remains part of the chosen
approach inside each system.
### 3. Separate projects and repositories with coordinated deployment
Extract capabilities into separately built libraries or applications with
versioned contracts, while retaining a coordinated deployment lifecycle.
Pros:
- Separates source and build context.
- Gives reusable components their own versioned releases.
- Retains a coordinated operational release process.
Cons:
- Changes spanning repositories require dependency release coordination.
- Deployment remains coupled despite repository separation.
- Repository separation alone does not enforce storage ownership or runtime
independence.
Not chosen because it incurs repository coordination costs while retaining a
deployment constraint that would limit workload placement and replacement.
### 4. Independently deployable systems with internal capability modules — chosen
Give systems their own repositories, deployment lifecycles, contracts, and enforced
data ownership. Keep capabilities loosely coupled through modules within a system.
Place compute workers independently where useful.
Pros:
- Supports focused development context and independent system evolution.
- Enforces data ownership beyond code dependency rules through storage permissions.
- Allows workloads to move between the Synology and mini-PC.
- Supports capability replacement and reuse through explicit contracts.
- Allows storage technology choices per system.
Cons:
- Requires contract compatibility and coordination for changes spanning systems.
- Adds deployment, configuration, and operational maintenance for multiple processes.
- Requires explicit failure handling and cross-system consistency decisions.
- Sharing one server or PostgreSQL instance retains common infrastructure failure
points despite logical isolation.
Chosen because ownership, replaceability, focused context, and independent workload
placement outweigh the additional operational and contract coordination work.
## Consequences
- Write follow-up specifications to map capabilities and dependencies, choose
initial system boundaries, define contracts and data ownership, and plan
extraction. This ADR does not itself settle those boundaries or implement them.
- Establish the landscape repository and the repositories and versioning needed
for reusable engineering resources. Preserve links between specifications and
affected projects, and between system READMEs and landscape guidance.
- Extract systems one at a time, establishing contracts and enforcing storage
ownership as part of each extraction. Moving tables into separate schemas is
insufficient while cross-system SQL access remains possible.
- Adapt build and deployment pipelines to release systems independently and
consume versioned shared engineering resources.
- Add appropriate checks for module dependencies, contract compatibility, and
storage isolation. Include views and scripts in boundary enforcement.
- Specify how systems exchange information, handle failed interactions, and keep
derived information consistent. These choices belong to the relevant follow-up
specifications rather than a universal messaging requirement.
- Keep one PostgreSQL container initially. Detailed backup and failover design is
future work; logical data separation does not provide infrastructure failover.
- Record the calendar review date when a maintainer manually approves this ADR.
REFINED records the agreed proposal; approval remains a separate manual step.