TaskTonic: Dos and Don'ts
When building applications with TaskTonic, adhering to these core principles will ensure your code remains responsive, thread-safe, and easy to test.
Execution & Flow
-
DO think in atomic units of work called "Sparkles". Code within a Sparkle executes sequentially and cannot be interrupted by other Sparkles in the same Catalyst.
-
DON'T use
time.sleep(). Ever. It will freeze the Catalyst thread, blocking the entire queue and making your application unresponsive. -
DON'T use heavy, blocking
while Trueloops inside a Sparkle. -
DO use built-in timers (
ttTimerSingleShot,ttTimerRepeat) for delays and periodic tasks. They are non-blocking and automatically schedule Sparkles. -
DO use the Chunked Iterator pattern (processing small batches and explicitly re-queuing the next batch) when handling massive datasets to keep the queue flowing.
-
DON'T manually manage threads (
threading.Thread) or thread locks (Lock()) for application logic. TaskTonic's single-threaded Catalyst execution provides inherent thread safety per component. -
DO spin up a separate, dedicated worker Catalyst (
ttCatalyst) if you absolutely must execute a heavy, CPU-bound calculation (like a massive NumPy matrix operation) to keep the Main Catalyst free for UI and I/O.
## State Management
-
DO use the built-in State Machine (
self.to_state()) to manage complex, multi-step asynchronous flows (like network handshakes). -
DON'T litter your code with boolean flags (e.g.,
is_connected,is_waiting). Let the state machine handle the logical mode of your Tonic. -
DO rely on "Late State Binding". Remember that the state is checked when a Sparkle is executed from the queue, not when it is queued. This naturally protects against stale asynchronous calls.
-
DON'T force a state machine if your Tonic is a simple, stateless data pipeline. It's perfectly fine to remain in the default stateless mode (
state = -1).
## Data Store (ttStore)
-
DO use
.at('path')to create liveItemcursors if you access the same path repeatedly (e.g., in a fast timer loop) instead of parsing the path string every time. -
DO use "Smart Lists" (appending with
#syntax) when managing lists of entities in the store to ensure Pub/Sub subscriptions trigger correctly. -
DO use the
extractandtrigger_nowparameters when subscribing tottStorepaths to receive safe, flat dictionary snapshots immediately. -
DON'T update large collections item-by-item. Use
.set_each()or thegroup()context manager to batch updates and prevent redundant Pub/Sub notification storms. -
DO use the
source()context manager andignore_sourcein subscriptions when building bidirectional syncing to prevent infinite feedback loops. -
DON'T unsubscribe by raw path strings. Always unsubscribe by
owner(e.g.,self.ledger.formula.unsubscribe(self)) in yourttse__on_finishedhook to ensure clean garbage collection.
## Services & Architecture
-
DO use
_tt_is_serviceto define Singleton services (like Database Managers or shared API clients). -
DON'T modify Service attributes directly inside the
_tt_init_service_basehook if the Service runs on a different Catalyst thread. Use that hook solely to place an asynchronous Command Sparkle (ttsc__) onto the Service's queue. -
DO break large, monolithic logic into a hierarchy of Parent and Child Tonics (Base and Infusions). The Ledger will cleanly handle the teardown cascade automatically.
-
DO use
ttsc__finish()as the official stop command. Never attempt to manually destroy a Tonic or bypass the lifecycle hooks.
## Testing & Distiller
-
DO use the
ttDistillerfor unit and integration tests. It turns asynchronous flows into predictable, synchronous, inspectable steps. -
DON'T rely solely on
self.log()for testing. Console output cannot fail a CI/CD pipeline. -
DO use
distiller.sparkle(contract={...})to write declarative integration tests that pause execution the moment complex, multi-tonic conditions are met. -
DO use the Distiller's Markdown Generator (
md_create,md_add_trace_table, etc.) to produce living documentation of your test runs.
TaskTonic_Dos_and_Donts.md
TaskTonic_Dos_and_Donts.md weergeven.