# Application Guidelines ## Purpose This document defines the default rules for building business applications on top of `plba`. The goal is to keep applications: - explicit - small - easy to debug - free from platform legacy artifacts ## Main model Build every application around this chain: `ApplicationModule` -> `Worker` -> business `Routine` Meaning: - `ApplicationModule` assembles the application - `Worker` owns runtime execution and lifecycle - `Routine` owns business behavior `Routine` is an application pattern, not a mandatory platform contract. ## Rules ### 1. Assemble the app in `ApplicationModule` `ApplicationModule` should: - create application services - create routines - create workers - register workers - register optional health contributors `ApplicationModule` should not: - execute business logic itself - contain runtime loops ### 2. Treat `Worker` as the only primary runtime abstraction `Worker` is the core runtime contract of the platform. Worker should own: - `start()` - `stop(force=False)` - `health()` - `status()` - thread ownership - execution strategy - graceful shutdown Worker should not own: - large business flows - domain decisions - parsing, persistence, and integration rules all mixed together ### 3. Keep one worker focused on one business activity Default recommendation: - one worker -> one routine If a process has multiple distinct behaviors: - split it into multiple workers - or compose several services behind one focused routine Do not make a worker a container for unrelated business scenarios. ### 4. Put business logic into routines and services Routine should contain: - business flow steps - domain service calls - business validation - integration calls - persistence orchestration If the routine becomes too large: - split business logic into dedicated services - keep routine as a thin application-level orchestrator ### 5. Let the worker define the run model The worker decides: - single-run or loop - one thread or multiple threads - interval between iterations - batch or long-running mode - stop conditions The routine does not decide lifecycle strategy. ### 6. Let the worker compute health Routine should not directly set platform health state. Instead: - routine completes successfully - or returns outcome information - or raises typed exceptions Then worker interprets that into: - `ok` - `degraded` - `unhealthy` ### 7. Use queues only as optional app-level utilities `InMemoryTaskQueue` may be used inside an application when buffering helps. But: - queue is not a core platform concept - queue usage should stay a local implementation choice - the app should still be described through workers and routines ### 8. Keep tracing vocabulary neutral Use tracing to describe operations and execution context, not legacy architectural roles. Prefer terms like: - operation - worker - routine - metadata - step Avoid making trace terminology define the application architecture. ### 9. Keep classes small and responsibilities clear Preferred shape: - thin `ApplicationModule` - thin `Worker` - focused `Routine` - dedicated domain services If a class grows too much, split it by responsibility instead of adding more platform abstractions. ## Checklist Before adding a new application component, check: 1. Is this runtime behavior or business behavior? 2. If runtime behavior, should it live in a `Worker`? 3. If business behavior, should it live in a `Routine` or service? 4. Does this component stay small and single-purpose? 5. Am I adding a queue because it is useful, or because of old mental models?