Skip to main content

refactoring

Safe code refactoring with step-by-step approach

소스 정보

저장소
vinilana/dotcontext
최근 소스 활동
2026년 3월 22일 00:29
감지된 SKILL.md 언어
영어
스타
570
포크
95

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
type
skill
name
Refactoring
description
Safe code refactoring with step-by-step approach
skillSlug
refactoring
phases
["E"]
generated
2026-03-18T00:00:00.000Z
status
filled
scaffoldVersion
2.0.0
# Refactoring Safe, systematic refactoring procedures for the `@dotcontext/cli` codebase. ## When to Use - Extracting logic into a new service or utility - Consolidating duplicate code across services or generators - Restructuring MCP gateway handlers - Improving type safety or removing `any` usage - Simplifying complex functions (high cyclomatic complexity) - Migrating between patterns (e.g., callback to async/await) ## Pre-Refactoring Checklist Before starting any refactoring: - [ ] All tests pass: `npm test` - [ ] Build succeeds: `npm run build` - [ ] Create a branch or ensure changes can be reverted - [ ] Identify all callers of the code being refactored (use grep or IDE references) ## Common Refactoring Scenarios ### Extracting a New Service The project follows a directory-per-service pattern. To extract logic into a new service: 1. Create `src/services/<name>/` directory 2. Create the service class: ```typescript // src/services/cache/cacheService.ts export interface CacheServiceOptions { repoPath: string; cacheDir?: string; } export class CacheService { private readonly repoPath: string; private readonly cacheDir: string; constructor(options: CacheServiceOptions) { this.repoPath = options.repoPath; this.cacheDir = options.cacheDir || '.context/.cache'; } async get(key: string): Promise<string | null> { /* ... */ } async set(key: string, value: string): Promise<void> { /* ... */ } } ``` 3. Create `src/services/<name>/index.ts` barrel: ```typescript export { CacheService, CacheServiceOptions } from './cacheService'; ``` 4. Update callers to import from the new service 5. Write tests in `src/services/<name>/cacheService.test.ts` ### Splitting a Large Gateway Handler Gateway handlers in `src/services/mcp/gateway/` can grow large. To split: 1. Identify action groups that share logic 2. Extract helper functions within the same file first 3. If helpers grow, extract into a separate utility or service 4. Keep the main handler function as a thin dispatcher: ```typescript export async function handleContext(params: ContextParams, options: ContextOptions): Promise<MCPToolResponse> { switch (params.action) { case 'check': return handleCheck(options); case 'init': return handleInit(params, options); // Each case delegates to a focused function } } ``` ### Improving Type Safety Common type improvements: 1. **Replace `any` with `unknown`**: Then add type guards: ```typescript // Before function process(data: any) { return data.value; } // After function process(data: unknown): string { if (typeof data === 'object' && data !== null && 'value' in data) { return String((data as { value: unknown }).value); } throw new Error('Invalid data shape'); } ``` 2. **Add discriminated unions** for action-based params: ```typescript type ContextParams = | { action: 'check'; repoPath?: string } | { action: 'init'; repoPath?: string; type?: string } | { action: 'fill'; repoPath?: string; target?: string }; ``` 3. **Extract interface from implementation**: When a class has grown, extract its public interface for dependency injection (pattern used by `AIContextMCPServer` with `contextBuilder`). ### Consolidating Duplicate Logic Common duplication spots in this project: - **Path resolution**: Multiple services resolve `repoPath` + `outputDir`. Extract to `src/services/shared/`. - **Frontmatter parsing**: Used in generators, scaffold tools, and MCP flows. Centralized in `src/utils/frontMatter.ts`. - **File listing with glob**: Used in semantic analysis, generators, and export. Check `src/services/shared/` for existing utilities. - **Error response creation**: MCP handlers should all use `createErrorResponse()` from `response.ts`. ### Updating Barrel Exports When moving or renaming files, update the export chain: ``` src/services/mcp/gateway/<file>.ts -- implementation -> src/services/mcp/gateway/index.ts -- gateway barrel -> src/services/mcp/gatewayTools.ts -- compatibility barrel -> src/services/mcp/mcpServer.ts -- consumer ``` ## Step-by-Step Refactoring Process 1. **Identify**: Find the code smell (large function, duplication, poor typing) 2. **Plan**: Determine the target structure and list affected files 3. **Test**: Ensure existing tests pass and cover the code being changed 4. **Extract**: Move code to the new location, keeping the old code as a thin wrapper 5. **Redirect**: Update all callers to use the new location 6. **Remove**: Delete the old wrapper once all callers are redirected 7. **Verify**: Run `npm test` and `npm run build` 8. **Commit**: Use `refactor(<scope>):` prefix ## Refactoring Safety Rails ### Tests as Safety Net - Never refactor code that lacks tests. Write tests first. - Run `npx jest --testPathPattern="<area>"` after each step. ### Preserve Public APIs - MCP tool names and schemas are public API. Do not rename tools or remove actions without a deprecation strategy. - CLI command names and flags are public API. - Barrel export paths are consumed by other modules. Keep backward-compatible re-exports. ### TypeScript Compiler as Guard - `npm run build` will catch broken imports, type mismatches, and missing exports. - Enable `noUnusedLocals` temporarily to find dead code after extraction. ### Small Commits - Commit after each logical step (extract, redirect, remove). - This makes it easy to bisect if something breaks. ## Anti-Patterns to Watch For - **Big bang refactors**: Changing everything at once. Prefer incremental changes. - **Refactoring while adding features**: Do one or the other per commit. - **Changing test behavior during refactoring**: Refactoring should not change test expectations. - **Forgetting barrel exports**: New file locations need updated export chains. - **Breaking MCP backward compatibility**: Clients depend on stable tool names and schemas.
GitHub에서 보기