# Coding style and best practices
## Basic rules:
- Use full, descriptive names for variables, functions, types, and modules. NEVER shorten the names, as it makes it extremely hard to read and review.
- Functions should be small and avoid deep nesting, well-structured and documented. The new developer onboarding to the project should be able to easily grasp what the code does and why.
- Group all `use` imports at the top of the file (no local import islands). Prefer ordering: std → third-party → workspace crates.
- Do not define structs/enums/traits inside function bodies. Keep types at module/file scope unless there is a compelling, strictly local reason.
- Use of `unwrap` is discouraged except in tests or in cases where failure is impossible (e.g., after checking `Option::is_some`). Prefer using `?` to propagate errors or handle them gracefully. Log errors using tracing crate macros (e.g., `tracing::error!`, `tracing::warn!`) instead of panicking, unless it's a critical, unrecoverable error.
- When fixing a bug, first write a test that reproduces the bug, then fix the bug, and finally ensure the test passes.
- Avoid dynamic dispatch wherever possible. Use generics and `impl Trait` instead of `Box<dyn Trait>`/`Arc<dyn Trait>`.
- All e2e tests must be as watertight as possible.
- No global state whatsoever. It makes reliable and quick testing a very hard task.
- Run `cargo clippy --fix --all-features --tests -D warnings` to ensure there are no clippy warnings.
- Run `cargo fmt --all` to format the code automatically after you've done necessary changes.
- Avoid pyramids of doom and deep nesting, break down things into small, readable functions.
- Make sure comments are short and descriptive, don't contain the thought process or plans - they should strictly clarify parts that might be unobvious from surrounding code, nothing more.
- Use `thiserror` and derive `thiserror::Error` for error types.
## Project-specific guidelines:
- Avoid heap allocations in the render method/loop. Try to reuse values allocated on the heap as much as possible in general.
- `tests/visual_regression.rs` always must be run to check that no regression has been introduced.
- In case of adding a new feature, expand `tests/visual_regression.rs` to test that it works as expected, with all possible permutations of the added feature and existing ones. Study other cases in the test for reference.
In case when a new bug is found, make sure it is fixed, and add the permutation that caused it to `tests/visual_regression.rs`.
- You should add new tiles to the visual regression test to ensure that the new feature works as expected with all
possible permutations of existing features. Keep everything as tiles as much as possible. The only exception to create a
whole new test should be when the feature absolutely cannot be tested with a new tile.