unfuck edit workflow.
This commit is contained in:
@@ -71,9 +71,11 @@ is processed by AI agents, while preserving readability for human review.
|
||||
## 10. Anti-OOP Conventions
|
||||
|
||||
### Philosophy
|
||||
|
||||
AI agents consistently misinterpret class hierarchies, method resolution, and inheritance. Flat function-call graphs are deterministic and traceable. OOP introduces scoping complexity that compounds with indentation.
|
||||
|
||||
### Hard Rules (Enforced by lint)
|
||||
|
||||
- **Never write a class for a single method.** Use a function.
|
||||
- **Never use inheritance for code reuse.** Compose with standalone functions.
|
||||
- **Never use private methods (`_method`).** Module-level functions with clear names suffice.
|
||||
@@ -81,6 +83,7 @@ AI agents consistently misinterpret class hierarchies, method resolution, and in
|
||||
- **No decorator classes.** Use plain functions with decorators.
|
||||
|
||||
### Class Justification Required
|
||||
|
||||
Every class definition MUST include a comment explaining WHY it is a class and not a function group or struct:
|
||||
|
||||
```python
|
||||
@@ -97,13 +100,17 @@ class OperationHelper:
|
||||
```
|
||||
|
||||
### Acceptability Criteria
|
||||
|
||||
A class is justified ONLY when ALL of:
|
||||
|
||||
1. It holds mutable state that must be encapsulated
|
||||
2. It has 3+ related methods that share state
|
||||
3. It implements a behavioral interface used polymorphically (not just data grouping)
|
||||
|
||||
### Refactoring Existing Classes (Strangler Fig Pattern)
|
||||
|
||||
When refactoring a class to functions:
|
||||
|
||||
1. Write test validating current behavior (prevents regression)
|
||||
2. Extract one method at a time into module-level functions
|
||||
3. Create wrapper function that delegates to class until migration complete
|
||||
@@ -111,16 +118,19 @@ When refactoring a class to functions:
|
||||
5. Commit with `refactor(oop):` prefix
|
||||
|
||||
### Data Structures
|
||||
|
||||
- **Data-only containers:** Use `NamedTuple`, `dataclass(frozen=True)`, or plain `dict` — NOT classes
|
||||
- **State machines:** Use dict-based transitions, not class + inheritance
|
||||
- **Configuration:** Plain dict or `TypedDict`, not classes with defaults
|
||||
|
||||
### Anti-Patterns (Flagged by Ruff PLR rules)
|
||||
|
||||
- `PLR0912`: Too many branches — extract to functions
|
||||
- `PLR6301`: No public methods — class is a namespace anti-pattern
|
||||
- `PLR0206`: Descriptors in class body — use simple attributes
|
||||
|
||||
### Enforcement
|
||||
|
||||
```toml
|
||||
[tool.ruff.lint.select]
|
||||
select = ["E", "F", "W", "C90", "C4", "PLR0912", "PLR6301", "PLR0206"]
|
||||
@@ -137,6 +147,7 @@ To prevent `PopID` or `End` leaks in immediate-mode rendering, and to keep code
|
||||
|
||||
- **The Context Manager Pattern (Mandatory for complex blocks):**
|
||||
Wrap all `Begin/End` blocks in `imscope` context managers (from `src/imgui_scopes.py`).
|
||||
|
||||
```python
|
||||
with imscope.window("My Window") as (exp, opened):
|
||||
if exp:
|
||||
@@ -146,13 +157,17 @@ To prevent `PopID` or `End` leaks in immediate-mode rendering, and to keep code
|
||||
if exp:
|
||||
self._render_tab_content()
|
||||
```
|
||||
|
||||
This adds only 1 space of indentation (project standard) and guarantees the corresponding `End` is called even on early returns or exceptions. **Crucial:** Always check the `exp` (expanded/visible) state before rendering content to avoid ID conflicts and performance overhead.
|
||||
|
||||
- **The Flat Dispatch Pattern (Recommended for the main loop):**
|
||||
|
||||
To avoid nesting multiple window checks, use a dispatch helper that encapsulates the state check and the scope.
|
||||
|
||||
```python
|
||||
self._render_window_if_open("My Window", self._render_my_panel)
|
||||
```
|
||||
|
||||
This keeps the main GUI loop as a flat sequence of declarative calls.
|
||||
|
||||
## 12. Structural Dependency Mapping (SDM)
|
||||
@@ -172,6 +187,7 @@ To minimize token usage and enhance visual scanning for human reviewers, heavily
|
||||
- **Single-Line Conditionals:** Prefer `if cond: do_this()` over multiline blocks for simple assignments or function calls. **Note:** Function and method definition signatures (`def ...:`) must ALWAYS remain on their own isolated lines and should never be compacted.
|
||||
- **Semicolon Stacking:** Chain closely related framework calls on a single line using semicolons (e.g., `imgui.same_line(); imgui.text("Label")`).
|
||||
- **Alignment:** Align assignments and inline comments vertically when declaring batches of related variables or conditionals.
|
||||
|
||||
```python
|
||||
if status == 'running': col = (0.0, 1.0, 0.0, 1.0)
|
||||
elif status == 'starting': col = (1.0, 1.0, 0.0, 1.0)
|
||||
@@ -185,6 +201,7 @@ For extremely large files that violate the "Anti-OOP" rule by necessity (e.g., `
|
||||
## 15. Modular Controller Pattern
|
||||
|
||||
To prevent "God Object" bloat in core controllers (like `AppController`):
|
||||
|
||||
- **Extract Logic:** Move all state-independent or purely utility logic to module-level functions.
|
||||
- **Dependency Injection:** Module-level functions that require class state should accept the instance as their first argument (e.g., `def my_extracted_logic(controller: AppController, ...)`).
|
||||
- **Handler Maps:** Replace massive `if/elif` blocks (like those in event dispatchers) with dictionaries mapping keys to module-level handler functions.
|
||||
|
||||
Reference in New Issue
Block a user