# Code Style and Best Practices

> **Language note:** Code examples in this file use Python. Apply the equivalent
> idioms and tools for your language ecosystem.

## General Principles

1. **Specification-First Development**: `docs/specification.md` is authoritative. Code discrepancies → align code to spec (never adjust spec to match code). Architectural changes require ADR process first.
2. **Modern Tooling**: Use modern, idiomatic build tools and workflows for the project's language ecosystem. Avoid legacy approaches such as Makefiles or wrapper shell scripts. All tooling should be from the current ecosystem and used as designed — not wrapped in custom scripts.
3. **Prefer Existing Tooling**: Don't add new dependencies when existing tools suffice. Keep the toolchain simple and consistent.
4. **Modular Design**: Files under 500 lines. Break large files into focused, cohesive modules.
5. **Environment Safety**: NEVER hardcode secrets or sensitive information.
6. **Test-First Development**: Write tests before implementation.
7. **Clean Architecture**: Separate concerns, clear layer boundaries.
8. **Documentation**: Keep docs updated alongside code changes in same commit.

---

## SOLID Principles (required — use liberally)

- **SRP (Single Responsibility)**: Each class has one reason to change; one responsibility only.
- **OCP (Open/Closed)**: Open for extension, closed for modification.
- **LSP (Liskov Substitution)**: Subtypes substitutable for base types without altering correctness.
- **ISP (Interface Segregation)**: Small, specific interfaces; don't force clients to depend on unused methods.
- **DIP (Dependency Inversion)**: Depend on abstractions, not concretions; high-level modules don't depend on low-level.

---

## Required Design Patterns (use liberally)

### Creational
Factory, Abstract Factory, Builder, Prototype, Singleton (sparingly — prefer DI), Object Pool, Dependency Injection

### Structural
Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy, Module

### Behavioral
Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor, Null Object

### Architectural
Repository, Unit of Work, Service Layer, MVC, CQRS, Event Sourcing, Specification

---

## Import / Dependency Declaration Guidelines

- Declare all imports at the top of the file — never inside functions, methods, or blocks.
- Prefer specific imports over wildcard or whole-module imports:
  - Python: `from module import ClassName` (not `import module` or `import *`)
  - Java: explicit class imports (not `import java.util.*`)
  - TypeScript: named imports (`import { Foo } from './foo'`)
- No wildcard imports in any language.
- Exception: type-only imports used solely to avoid circular dependencies:
  - Python: `if TYPE_CHECKING:` block
  - TypeScript: `import type { Foo } from './foo'`

---

## Error and Exception Handling

### Argument Validation — MANDATORY in all public/protected methods

Always validate arguments FIRST before any other logic (Python example):

```python
def process_data(self, data: list[str], threshold: int) -> None:
    # Always validate arguments FIRST before any other logic
    if data is None:
        raise ValueError("data cannot be None")
    if not data:
        raise ValueError("data cannot be empty")
    if not all(isinstance(item, str) for item in data):
        raise TypeError("data must contain only strings")
    if threshold < 0 or threshold > 100:
        raise ValueError(f"threshold must be between 0 and 100, got {threshold}")
    # ... actual logic here
```

Apply the same fail-fast pattern in any language: check value ranges, null/nil/None,
types, empty strings, empty collections, and invalid object states at the entry point.

### Exception Propagation Rules

- NEVER suppress errors — let exceptions propagate to top-level.
- NEVER catch just to log and re-raise (let them propagate naturally).
- NEVER use bare catch-all handlers without re-raising unless you have specific recovery logic.
- Only catch when you can meaningfully handle (retry, cleanup, add context).
- Raise exceptions rather than returning null/nil/None on error.

### Fail-Fast Principles

- Check preconditions at function entry, not deep in logic.
- No silent failures (no returning null/default when error exists).
- Make failure conditions explicit.

### Checks to Perform in Every Public/Protected Method

- **Value Range**: numeric values within acceptable bounds.
- **Null Checks**: reject null/nil/None where not expected.
- **Type Verification**: via static type system where possible; runtime checks otherwise.
- **Empty Strings**: reject where non-empty required.
- **Empty Collections**: check if must contain elements.
- **Invalid States**: verify object state valid for operation.

---

## Type Safety

Use static typing pervasively whenever the language supports it. Run the type checker
as part of the standard build pipeline — it must pass before work is considered done.

- **Full annotations**: every function signature, variable declaration, and return type.
- **No suppression**: never disable the type checker via config and never use inline
  suppression comments:
  - Python: no `# type: ignore`
  - TypeScript: no `// @ts-ignore` or `// @ts-nocheck`
  - Java/Kotlin: no `@SuppressWarnings` for type issues
- **Continuous enforcement**: type checking runs on every commit via the task runner.
  - Python example: `nox -s typecheck` (Pyright)
  - TypeScript example: `npm run typecheck` (tsc --noEmit)
  - Java example: `./gradlew compileJava`
