- Keep modules focused: one module for one responsibility.
- Separate concerns: device bootstrap, network init, protocol client, business logic, persistence.
- Use composition over deep inheritance.
- Keep handlers and callbacks lightweight.
- Define stable function contracts: inputs, return, retry behavior, and error paths.
- Explicitly classify errors: retryable vs non-retryable.
- Include context in logs: module, step, error code/message.
- Keep memory usage predictable.
- Avoid unbounded buffers and large temporary objects.
- Use controlled polling intervals and timer cadence.
- Add watchdog/health checks where required by product profile.
- Keep topic names consistent and predictable.
- Keep payload fields stable across versions.
- Add throttling/debouncing for high-frequency events.