Skip to main content

refactor

Refactors code following Ousterhout's design principles. Analyzes complexity, creates prioritized refactoring plan, and executes with safety-first approach. Optimized for Vite/React, Tauri/Rust, Zustand stack.

Source facts

Repository
atilladeniz/Kubeli
Last source activity
February 22, 2026 at 09:29
Detected SKILL.md language
English
Stars
384
Forks
33

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
refactor
description
Refactors code following Ousterhout's design principles. Analyzes complexity, creates prioritized refactoring plan, and executes with safety-first approach. Optimized for Vite/React, Tauri/Rust, Zustand stack.
argument-hint
["file_or_directory_path"]
# Strategic Refactoring Skill You are a senior software architect performing strategic refactoring based on John Ousterhout's "A Philosophy of Software Design" principles. **Your Goal**: Transform code to reduce complexity while maintaining functionality. Every change should make the system look like it was designed with this feature in mind from the start. ## Kubeli Tech Stack - **Frontend**: Vite 7+, React 19, TypeScript - **Desktop**: Tauri 2.0 (Rust backend) - **State**: Zustand - **Styling**: Tailwind CSS - **K8s Client**: kube-rs (Rust) --- ## Phase 1: Analysis (Use /software-design-review principles) Before any refactoring, analyze the code against these 15 Ousterhout principles: 1. Strategic vs. Tactical Programming 2. Module Depth (Deep vs. Shallow) 3. Somewhat General-Purpose (Generalization) 4. Different Layers, Different Abstractions 5. Information Hiding & Leaks 6. Pull Complexity Downward 7. Together or Separate? 8. Define Errors Out of Existence 9. Design Twice 10. Consistency 11. Code Should Be Obvious 12. Comments & Documentation 13. Names 14. Write Comments First 15. Modifying Existing Code --- ## Phase 2: Safety Checklist **Before ANY refactoring:** - [ ] Tests exist for the code being refactored - [ ] All tests pass currently - [ ] Code is committed (clean git state) - [ ] You understand what the code does (read it first!) **If tests don't exist:** 1. Write characterization tests first 2. Test the component as a black box 3. Validate end results, not implementation details --- ## Phase 3: Clean Code Smells Checklist (Robert Martin) In addition to Ousterhout's principles, check for these code smells: ### Comments (C1-C5) | Code | Smell | Fix | |------|-------|-----| | C1 | Ungeeignete Informationen (Change history, author info) | Remove, use git | | C2 | Überholte Kommentare | Update or delete | | C3 | Redundante Kommentare | Delete if code is self-explanatory | | C4 | Schlecht geschriebene Kommentare | Rewrite clearly | | C5 | Auskommentierter Code | Delete (git has history) | ### Functions (F1-F4) | Code | Smell | Fix | |------|-------|-----| | F1 | Zu viele Argumente (>3) | Use object parameter | | F2 | Output-Argumente | Return value instead | | F3 | Flag-Argumente (boolean params) | Split into two functions | | F4 | Tote Funktionen (never called) | Delete | ### General (G1-G36) - Most Important | Code | Smell | Fix | |------|-------|-----| | G2 | Offensichtliches Verhalten fehlt | Implement expected behavior | | G3 | Falsches Verhalten an Grenzen | Add boundary tests | | G5 | **Duplizierung (DRY)** | Extract common code | | G6 | Falsche Abstraktionsebene | Move to correct layer | | G8 | Zu viele Informationen (large interface) | Hide details, minimize API | | G9 | Toter Code | Delete | | G10 | Vertikale Trennung (related code far apart) | Move together | | G11 | Inkonsistenz | Follow established patterns | | G13 | Künstliche Kopplung | Decouple unrelated code | | G14 | **Funktionsneid (Feature Envy)** | Move method to correct class | | G16 | Verdeckte Absicht (obscure code) | Make obvious | | G17 | Falsche Zuständigkeit | Move to responsible module | | G23 | If/Else statt Polymorphismus | Use polymorphism | | G25 | **Magische Zahlen** | Named constants | | G28 | Bedingungen nicht eingekapselt | Extract to named function | | G29 | Negative Bedingungen | Use positive conditions | | G30 | **Mehr als eine Aufgabe** | Split function | | G31 | Verborgene zeitliche Kopplungen | Make dependencies explicit | | G33 | Grenzbedingungen nicht eingekapselt | Encapsulate bounds | | G34 | Mehrere Abstraktionsebenen gemischt | One level per function | | G36 | **Transitive Navigation (Law of Demeter)** | Don't talk to strangers | ### Names (N1-N7) | Code | Smell | Fix | |------|-------|-----| | N1 | Nicht deskriptiv | Rename to describe purpose | | N2 | Falsche Abstraktionsebene | Match name to abstraction level | | N4 | Nicht eindeutig | Make unambiguous | | N5 | Zu kurz für großen Scope | Longer names for wider scope | | N7 | Nebeneffekte nicht im Namen | Include side effects in name | ### Tests (T1-T9) | Code | Smell | Fix | |------|-------|-----| | T1 | Unzureichende Tests | Add more tests | | T3 | Triviale Tests übersprungen | Test everything | | T5 | Grenzbedingungen nicht getestet | Add boundary tests | | T6 | Bug-Nachbarschaft nicht getestet | Test around bugs | | T9 | Langsame Tests | Optimize test speed | ### F.I.R.S.T. Test Principles - **Fast**: Tests should run quickly - **Independent**: Tests shouldn't depend on each other - **Repeatable**: Same result every time - **Self-Validating**: Boolean output (pass/fail) - **Timely**: Written before/with production code ### Clean Code Function Rules 1. **Klein!** Functions should be small (ideally < 20 lines) 2. **Eine Aufgabe** - Do ONE thing and do it well 3. **Eine Abstraktionsebene** - Don't mix abstraction levels 4. **Stepdown Rule** - Read code top-down like a story 5. **Max 3 Arguments** - Prefer 0-2, use object for more ```typescript // BEFORE: Too many args, mixed abstraction levels async function processPod( namespace: string, name: string, action: string, force: boolean, gracePeriod: number, callback: () => void ) { const pod = await invoke('get_pod', { namespace, name }); if (action === 'delete') { if (force) { await invoke('force_delete', { namespace, name }); } else { await invoke('delete', { namespace, name, gracePeriod }); } } callback(); } // AFTER: Single purpose, one abstraction level interface PodActionRequest { pod: PodRef; action: PodAction; } async function executePodAction({ pod, action }: PodActionRequest): Promise<void> { const handler = getPodActionHandler(action); await handler.execute(pod); } ``` ### Law of Demeter (G36: Transitive Navigation) **Principle**: A method should only call methods on: - Its own object (`this`) - Objects passed as parameters - Objects it creates - Its direct component objects ```typescript // VIOLATES Law of Demeter: "Train wreck" const street = user.getAddress().getCity().getStreet(); // BETTER: Tell, don't ask const street = user.getStreetAddress(); // Kubeli Example: // BAD: Navigating through objects const podName = store.getState().cluster.selectedPod.metadata.name; // GOOD: Direct access with selector const podName = useSelectedPodName(); ``` ### Pfadfinder-Regel (Boy Scout Rule) **"Leave the code cleaner than you found it."** Every time you touch code: - Fix one small thing - Improve one name - Extract one function - Add one missing test --- ## Phase 4: Stack-Specific Refactoring Patterns ### Vite/React (Frontend) **Component Organization:** ```typescript // BEFORE: Monolithic component with mixed concerns export function PodList({ namespace }: Props) { const [pods, setPods] = useState([]); const [filter, setFilter] = useState(''); useEffect(() => { fetchPods().then(setPods); }, []); return ( <div> <input value={filter} onChange={e => setFilter(e.target.value)} /> <ul>{pods.filter(p => p.name.includes(filter)).map(p => <PodItem pod={p} />)}</ul> </div> ); } // AFTER: Separate data from presentation, use Zustand // stores/resource-store.ts export const useResourceStore = create((set) => ({ pods: [], fetchPods: async (ns) => { /* ... */ }, })); // components/PodList.tsx export function PodList() { const pods = useResourceStore(s => s.pods); const [filter, setFilter] = useState(''); return <ul>{pods.filter(p => p.name.includes(filter)).map(p => <PodItem pod={p} />)}</ul>; } ``` **Anti-Patterns to Fix:** | Smell | Refactoring | |-------|-------------| | Props drilling through 3+ levels | Use Zustand store or Context | | Giant `utils.ts` file | Split into logical modules in `lib/` | | Inline Tauri `invoke()` calls | Centralize in `lib/tauri/commands/` | | State in components that should be global | Move to Zustand store | --- ### Zustand (State Management) **Selective State Access:** ```typescript // BEFORE: Re-renders on ANY state change function PodCount() { const store = useClusterStore(); // BAD: subscribes to everything return <span>{store.pods.length}</span>; } // AFTER: Only re-renders when pods change function PodCount() { const podCount = useClusterStore((s) => s.pods.length); // GOOD: selective return <span>{podCount}</span>; } ``` **Modular Stores with Slices:** ```typescript // BEFORE: Monolithic store const useStore = create((set) => ({ pods: [], deployments: [], services: [], selectedPod: null, selectedDeployment: null, // ... 50 more properties })); // AFTER: Composable slices // stores/pods-slice.ts export const createPodsSlice = (set, get) => ({ pods: [], selectedPod: null, fetchPods: async (ns) => { ... }, selectPod: (id) => set({ selectedPod: id }), }); // stores/deployments-slice.ts export const createDeploymentsSlice = (set, get) => ({ deployments: [], fetchDeployments: async (ns) => { ... }, }); // stores/index.ts export const useStore = create((...a) => ({ ...createPodsSlice(...a), ...createDeploymentsSlice(...a), })); ``` **Custom Hook Abstraction:** ```typescript // BEFORE: Direct store access everywhere function PodDetails({ id }: Props) { const pods = useClusterStore((s) => s.pods); const pod = pods.find(p => p.id === id); // ... } // AFTER: Domain-specific hooks // hooks/usePod.ts export function usePod(id: string) { return useClusterStore((s) => s.pods.find(p => p.id === id)); } // components/PodDetails.tsx function PodDetails({ id }: Props) { const pod = usePod(id); // ... } ``` --- ### Tauri 2.0 / Rust (Backend) **Command Organization:** ```rust // BEFORE: All commands in one file // src-tauri/src/main.rs #[tauri::command] fn get_pods() { ... } #[tauri::command] fn get_deployments() { ... } #[tauri::command] fn get_services() { ... } // ... 50 more commands // AFTER: Modular command structure // src-tauri/src/commands/mod.rs pub mod pods; pub mod deployments; pub mod services; // src-tauri/src/commands/pods.rs #[tauri::command] pub async fn get_pods(state: State<'_, AppState>, namespace: &str) -> Result<Vec<Pod>, Error> { let client = state.client_manager.get_client()?; client.list_pods(namespace).await } // src-tauri/src/main.rs fn main() { tauri::Builder::default() .invoke_handler(tauri::generate_handler![ commands::pods::get_pods, commands::pods::delete_pod, commands::deployments::get_deployments, ]) .run(tauri::generate_context!()) .expect("error running app"); } ``` **Separation: main.rs vs lib.rs:** ```rust // BEFORE: Logic in main.rs // src-tauri/src/main.rs fn main() {
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub