Architect maintainable apps
Skill AE86-Victory/webapp-engineering-skills/skills/architect-maintainable-apps
Production-minded Agent Skills for responsive web design, root-cause refactoring, and maintainable app architecture.
npx -y skills add AE86-Victory/webapp-engineering-skills --skill architect-maintainable-appsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 15 days oldThe repository was created 15 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Design maintainable application architecture before and during implementation. Use when starting a web, mobile, desktop, or backend app; adding a substantial feature; choosing MVC, MVVM, unidirectional flow, factories, dependency injection, or singleton lifetimes; defining folder structure and module boundaries; or preventing UI, state, business logic, and infrastructure from becoming coupled.
SKILL.md
7.7 KB, as published. Nobody here has run it
Architect Maintainable Apps
Make architecture visible from Day 1: one owner per invariant, inward dependencies, explicit construction, and patterns selected for an observed force rather than ceremony.
1. Discover the forces
Inspect the product and repository before choosing a pattern:
- user journeys and domain rules;
- sources of truth and state lifetimes;
- framework-required ownership and lifecycle;
- I/O boundaries: network, storage, device, queue, clock, analytics;
- expected variation: platform, provider, customer, environment, algorithm;
- team size, delivery cadence, test strategy, and likely change axes.
Read the installed framework documentation. Treat framework conventions as constraints, not the architecture itself.
Completion criterion: list the independent reasons the code will change and the state/resource lifetimes the app must support.
2. Set the dependency rule
Use these conceptual layers even when the physical project is small:
- Domain: business entities, value objects, invariants, pure policies.
- Application: use cases, commands/queries, orchestration, ports.
- Presentation: views plus presentation state and user-intent translation.
- Infrastructure: framework adapters, persistence, network, analytics, filesystem.
- Composition root: the only ordinary place that selects concrete implementations and lifetimes.
Dependencies point toward policy: presentation and infrastructure may depend on application/domain interfaces; domain code stays unaware of UI, database, network, and dependency containers.
Scale physical layers to complexity. A small app may colocate files while preserving conceptual ownership. Read project-structure.md before creating folders.
Completion criterion: every planned module has one layer, one owner, and an allowed dependency direction.
3. Choose the presentation pattern
Select roles from product and framework needs:
- MVC for controller-mediated input and request/response or platform-controller lifecycles.
- MVVM for stateful declarative/bound UI where presentation state and commands need isolated testing.
- Unidirectional presentation for event → update → state → view flows, especially reactive web UIs.
- A thin view plus presenter/controller when binding machinery would add no leverage.
Pattern roles matter more than class suffixes. A React hook or feature store can own view-model responsibilities without a ViewModel class.
Read presentation-patterns.md whenever UI state, actions, validation, loading, or navigation are involved.
Completion criterion: name the owner of display state, business state, user intents, side effects, and navigation; ensure the view contains no business policy.
4. Design deep feature modules
Organize around capabilities rather than technical file types when features evolve independently. For each feature:
- expose a small interface at a deliberate seam;
- hide orchestration and provider details behind it;
- keep domain terms consistent across UI, use cases, and tests;
- represent real variation through ports/strategies, not conditionals spread across callers;
- avoid interfaces with only one hypothetical adapter unless isolation is already valuable for testing or framework containment.
Completion criterion: deleting a module would force its hidden complexity back into multiple callers; otherwise deepen or remove it.
5. Choose creation and lifetime patterns
Resolve construction separately from use:
- direct construction for simple stable values with no hidden dependencies;
- Factory Method when one creation decision varies;
- Abstract Factory when a coherent family of implementations must vary together;
- Builder for validated multi-step assembly of a complex value;
- dependency injection for supplying already-selected collaborators;
- singleton lifetime only when exactly one identity/resource per declared scope is a domain or platform invariant.
Prefer a composition-root-managed singleton lifetime over static global access. Global reachability is not the same as singular lifetime.
Read creation-and-lifetimes.md before adding a factory, service locator, dependency container, static instance, global store, or cache.
Completion criterion: every stateful dependency has an explicit owner, creation site, lifetime, disposal rule, and test replacement strategy.
6. Define the project structure
Create folders only for real responsibilities. Prefer:
- a composition root near the application entry;
- feature modules containing their domain/application/presentation code;
- infrastructure adapters grouped by the port or external system they implement;
- a narrow shared kernel for genuinely cross-feature concepts;
- tests beside modules or mirrored consistently by feature.
Avoid global utils, services, helpers, and managers buckets. Name modules by business capability or explicit technical role.
Completion criterion: a new maintainer can find where a behavior lives and where a new provider/feature belongs without searching the whole repository.
7. Implement a walking skeleton
Before expanding breadth, build one thin end-to-end path:
view/input -> presentation state -> use case -> port -> adapter
Wire it in the composition root, use real contracts, and keep alternate adapters replaceable. This validates dependency direction and lifecycle assumptions before they spread.
Completion criterion: one production-shaped vertical slice runs and can replace at least one external adapter in tests without changing policy code.
8. Enforce architecture continuously
Add proportionate checks:
- unit tests for domain and presentation state;
- contract tests for ports/adapters;
- integration tests through the composition root;
- lint/import-boundary rules where the language supports them;
- tests for state transition, lifetime, and teardown behavior;
- architecture review when a dependency crosses layers or a shared abstraction is introduced.
Read architecture-verification.md when establishing CI or reviewing a large feature.
Completion criterion: forbidden dependency directions fail mechanically where practical, and important seams are tested through their public interfaces.
9. Record decisions and reassess
For consequential choices, record context, decision, alternatives, and consequences in the repository's existing decision format. Reassess when the forces change; preserve stable interfaces while replacing implementations.
Report the selected architecture, dependency rule, state owners, pattern decisions, folder map, lifetime table, tested seams, and intentionally deferred complexity.
Failure signals
Stop and redesign when:
- a view fetches persistence/network data and applies business rules;
- business policy imports UI or framework types;
- multiple stores own the same state;
- a factory only wraps one constructor without hiding a decision;
- a singleton exists merely to avoid passing a dependency;
- callers resolve dependencies from a container/service locator;
- every feature requires edits across unrelated technical folders;
- abstractions are named after mechanisms but expose no stable policy;
- the architecture diagram cannot identify construction and lifetime ownership.