From a7adc85a398b13f8084dc4f60b14887fc1781e0a Mon Sep 17 00:00:00 2001 From: Zhongwei Li Date: Sat, 29 Nov 2025 18:21:08 +0800 Subject: [PATCH] Initial commit --- .claude-plugin/plugin.json | 14 + README.md | 3 + agents/code-quality-improver.md | 139 +++++++ commands/refactoring-patterns.md | 665 +++++++++++++++++++++++++++++++ plugin.lock.json | 49 +++ 5 files changed, 870 insertions(+) create mode 100644 .claude-plugin/plugin.json create mode 100644 README.md create mode 100644 agents/code-quality-improver.md create mode 100644 commands/refactoring-patterns.md create mode 100644 plugin.lock.json diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..4302677 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,14 @@ +{ + "name": "code-quality-refactoring", + "description": "Code quality improvement and refactoring patterns with SOLID principles and clean code practices", + "version": "1.0.0", + "author": { + "name": "Brock" + }, + "agents": [ + "./agents" + ], + "commands": [ + "./commands" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4af92bc --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# code-quality-refactoring + +Code quality improvement and refactoring patterns with SOLID principles and clean code practices diff --git a/agents/code-quality-improver.md b/agents/code-quality-improver.md new file mode 100644 index 0000000..2f9ff08 --- /dev/null +++ b/agents/code-quality-improver.md @@ -0,0 +1,139 @@ +# Code Quality Improver Agent + +You are an autonomous agent specialized in improving code quality through refactoring, applying SOLID principles, and eliminating code smells. + +## Your Mission + +Transform legacy and poorly structured code into clean, maintainable, testable software following industry best practices. + +## Core Responsibilities + +### 1. Analyze Code Quality +- Identify code smells +- Detect SOLID violations +- Find duplicated code +- Analyze complexity metrics +- Review naming conventions + +### 2. Apply SOLID Principles + +**Single Responsibility:** +```typescript +// Before: Multiple responsibilities +class UserManager { + saveUser(user) { /* DB logic */ } + sendEmail(user) { /* Email logic */ } +} + +// After: Single responsibility +class UserRepository { + save(user) { /* DB logic */ } +} + +class UserEmailService { + sendWelcome(user) { /* Email logic */ } +} +``` + +**Dependency Inversion:** +```typescript +// Before: Tight coupling +class Service { + db = new MySQL(); +} + +// After: Depend on abstraction +class Service { + constructor(private db: Database) {} +} +``` + +### 3. Refactor Code Smells + +**Long Method → Extract Method** +```typescript +// Before +function process() { + // 100 lines of code +} + +// After +function process() { + validate(); + calculate(); + save(); +} +``` + +**Duplicated Code → Extract Function** +```typescript +// Before +const a = data.map(x => x * 2).filter(x => x > 10); +const b = other.map(x => x * 2).filter(x => x > 10); + +// After +const transform = (arr) => arr.map(x => x * 2).filter(x => x > 10); +const a = transform(data); +const b = transform(other); +``` + +### 4. Improve Naming +```typescript +// Before +function d(t) { return t * 86400000; } + +// After +const MS_PER_DAY = 86400000; +function daysToMilliseconds(days: number) { + return days * MS_PER_DAY; +} +``` + +### 5. Reduce Complexity +- Break down large functions +- Simplify conditionals +- Remove nested loops +- Use early returns +- Apply design patterns + +### 6. Enhance Testability +- Inject dependencies +- Separate concerns +- Remove static methods +- Make side effects explicit +- Use interfaces + +### 7. Document Architecture Decisions +- Why code was refactored +- What patterns were applied +- Trade-offs considered +- Future improvements + +## Refactoring Approach + +1. **Understand the code** - Read and comprehend +2. **Add tests** - Ensure behavior preservation +3. **Identify smells** - Find problem areas +4. **Make small changes** - Incremental refactoring +5. **Run tests** - Verify nothing broke +6. **Repeat** - Continue improving + +## Best Practices + +- Keep functions small +- Use meaningful names +- Follow SOLID principles +- Eliminate duplication +- Write tests first +- Refactor continuously +- Review regularly +- Document decisions + +## Deliverables + +1. Refactored codebase +2. Improved test coverage +3. Code quality metrics +4. Refactoring documentation +5. Architecture diagrams +6. Best practices guide diff --git a/commands/refactoring-patterns.md b/commands/refactoring-patterns.md new file mode 100644 index 0000000..ab61231 --- /dev/null +++ b/commands/refactoring-patterns.md @@ -0,0 +1,665 @@ +# Code Quality & Refactoring Patterns + +Comprehensive refactoring patterns, SOLID principles, and clean code practices for maintainable software. + +## SOLID Principles + +### Single Responsibility Principle (SRP) +A class should have one, and only one, reason to change. + +```typescript +// Bad: Multiple responsibilities +class User { + constructor(public name: string, public email: string) {} + + save() { + // Database logic + db.query('INSERT INTO users...'); + } + + sendEmail() { + // Email logic + emailService.send(this.email, 'Welcome!'); + } + + generateReport() { + // Report generation logic + return `User: ${this.name}`; + } +} + +// Good: Single responsibility per class +class User { + constructor(public name: string, public email: string) {} +} + +class UserRepository { + save(user: User) { + db.query('INSERT INTO users...', user); + } +} + +class UserEmailService { + sendWelcomeEmail(user: User) { + emailService.send(user.email, 'Welcome!'); + } +} + +class UserReportGenerator { + generate(user: User): string { + return `User: ${user.name}`; + } +} +``` + +### Open/Closed Principle (OCP) +Software entities should be open for extension, but closed for modification. + +```typescript +// Bad: Must modify class to add new shapes +class AreaCalculator { + calculate(shapes: any[]) { + let area = 0; + for (const shape of shapes) { + if (shape.type === 'circle') { + area += Math.PI * shape.radius ** 2; + } else if (shape.type === 'square') { + area += shape.side ** 2; + } + // Need to modify for new shapes + } + return area; + } +} + +// Good: Open for extension, closed for modification +interface Shape { + area(): number; +} + +class Circle implements Shape { + constructor(public radius: number) {} + + area(): number { + return Math.PI * this.radius ** 2; + } +} + +class Square implements Shape { + constructor(public side: number) {} + + area(): number { + return this.side ** 2; + } +} + +class Triangle implements Shape { + constructor(public base: number, public height: number) {} + + area(): number { + return (this.base * this.height) / 2; + } +} + +class AreaCalculator { + calculate(shapes: Shape[]): number { + return shapes.reduce((total, shape) => total + shape.area(), 0); + } +} +``` + +### Liskov Substitution Principle (LSP) +Objects of a superclass should be replaceable with objects of its subclasses without breaking the application. + +```typescript +// Bad: Violates LSP +class Bird { + fly() { + console.log('Flying'); + } +} + +class Penguin extends Bird { + fly() { + throw new Error('Penguins cannot fly!'); + } +} + +// Good: Proper abstraction +interface Bird { + move(): void; +} + +class FlyingBird implements Bird { + move() { + this.fly(); + } + + fly() { + console.log('Flying'); + } +} + +class Penguin implements Bird { + move() { + this.swim(); + } + + swim() { + console.log('Swimming'); + } +} +``` + +### Interface Segregation Principle (ISP) +Clients should not be forced to depend on interfaces they don't use. + +```typescript +// Bad: Fat interface +interface Worker { + work(): void; + eat(): void; + sleep(): void; +} + +class Human implements Worker { + work() { console.log('Working'); } + eat() { console.log('Eating'); } + sleep() { console.log('Sleeping'); } +} + +class Robot implements Worker { + work() { console.log('Working'); } + eat() { throw new Error('Robots dont eat'); } + sleep() { throw new Error('Robots dont sleep'); } +} + +// Good: Segregated interfaces +interface Workable { + work(): void; +} + +interface Eatable { + eat(): void; +} + +interface Sleepable { + sleep(): void; +} + +class Human implements Workable, Eatable, Sleepable { + work() { console.log('Working'); } + eat() { console.log('Eating'); } + sleep() { console.log('Sleeping'); } +} + +class Robot implements Workable { + work() { console.log('Working'); } +} +``` + +### Dependency Inversion Principle (DIP) +High-level modules should not depend on low-level modules. Both should depend on abstractions. + +```typescript +// Bad: High-level depends on low-level +class MySQLDatabase { + save(data: any) { + console.log('Saving to MySQL'); + } +} + +class UserService { + private db = new MySQLDatabase(); // Tight coupling + + saveUser(user: User) { + this.db.save(user); + } +} + +// Good: Both depend on abstraction +interface Database { + save(data: any): void; +} + +class MySQLDatabase implements Database { + save(data: any) { + console.log('Saving to MySQL'); + } +} + +class PostgreSQLDatabase implements Database { + save(data: any) { + console.log('Saving to PostgreSQL'); + } +} + +class UserService { + constructor(private db: Database) {} // Dependency injection + + saveUser(user: User) { + this.db.save(user); + } +} + +// Usage +const service = new UserService(new MySQLDatabase()); +``` + +## Common Code Smells and Refactoring + +### Long Method +```typescript +// Bad: Long method +function processOrder(order: Order) { + // Validate order (20 lines) + if (!order.items || order.items.length === 0) { + throw new Error('No items'); + } + // Calculate totals (30 lines) + let total = 0; + for (const item of order.items) { + total += item.price * item.quantity; + } + // Apply discounts (25 lines) + if (order.coupon) { + total -= total * order.coupon.discount; + } + // Process payment (40 lines) + // Send notifications (20 lines) + // Update inventory (30 lines) +} + +// Good: Extract methods +function processOrder(order: Order) { + validateOrder(order); + const total = calculateTotal(order); + const finalTotal = applyDiscounts(total, order.coupon); + processPayment(order, finalTotal); + sendNotifications(order); + updateInventory(order); +} + +function validateOrder(order: Order) { + if (!order.items || order.items.length === 0) { + throw new Error('Order must contain items'); + } +} + +function calculateTotal(order: Order): number { + return order.items.reduce( + (sum, item) => sum + item.price * item.quantity, + 0 + ); +} + +function applyDiscounts(total: number, coupon?: Coupon): number { + if (!coupon) return total; + return total * (1 - coupon.discount); +} +``` + +### Duplicated Code +```typescript +// Bad: Duplicated logic +class UserController { + async getUser(req, res) { + try { + const user = await userService.findById(req.params.id); + if (!user) { + return res.status(404).json({ error: 'User not found' }); + } + res.json(user); + } catch (error) { + console.error(error); + res.status(500).json({ error: 'Internal server error' }); + } + } + + async updateUser(req, res) { + try { + const user = await userService.findById(req.params.id); + if (!user) { + return res.status(404).json({ error: 'User not found' }); + } + const updated = await userService.update(req.params.id, req.body); + res.json(updated); + } catch (error) { + console.error(error); + res.status(500).json({ error: 'Internal server error' }); + } + } +} + +// Good: Extract common logic +class UserController { + private async handleRequest( + req: Request, + res: Response, + handler: (user: User) => Promise + ) { + try { + const user = await userService.findById(req.params.id); + if (!user) { + return res.status(404).json({ error: 'User not found' }); + } + const result = await handler(user); + res.json(result); + } catch (error) { + console.error(error); + res.status(500).json({ error: 'Internal server error' }); + } + } + + async getUser(req: Request, res: Response) { + await this.handleRequest(req, res, (user) => user); + } + + async updateUser(req: Request, res: Response) { + await this.handleRequest(req, res, (user) => + userService.update(user.id, req.body) + ); + } +} +``` + +### Large Class (God Object) +```typescript +// Bad: Too many responsibilities +class Order { + items: Item[]; + customer: Customer; + total: number; + + calculateTotal() { /* ... */ } + applyDiscount() { /* ... */ } + validateOrder() { /* ... */ } + processPayment() { /* ... */ } + sendEmail() { /* ... */ } + updateInventory() { /* ... */ } + generateInvoice() { /* ... */ } + shipOrder() { /* ... */ } +} + +// Good: Split responsibilities +class Order { + constructor( + public items: Item[], + public customer: Customer + ) {} +} + +class OrderCalculator { + calculateTotal(order: Order): number { /* ... */ } + applyDiscount(order: Order, discount: Discount): number { /* ... */ } +} + +class OrderValidator { + validate(order: Order): boolean { /* ... */ } +} + +class PaymentProcessor { + process(order: Order, amount: number): Payment { /* ... */ } +} + +class OrderNotificationService { + sendConfirmation(order: Order): void { /* ... */ } +} + +class InventoryService { + updateFromOrder(order: Order): void { /* ... */ } +} + +class InvoiceGenerator { + generate(order: Order): Invoice { /* ... */ } +} + +class ShippingService { + ship(order: Order): Shipment { /* ... */ } +} +``` + +### Feature Envy +```typescript +// Bad: Method more interested in other class +class Order { + items: Item[]; + + getTotalWeight() { + let weight = 0; + for (const item of this.items) { + weight += item.product.weight * item.quantity; + } + return weight; + } +} + +// Good: Move method to where data is +class Order { + items: Item[]; + + getTotalWeight(): number { + return this.items.reduce((sum, item) => sum + item.getWeight(), 0); + } +} + +class Item { + constructor( + public product: Product, + public quantity: number + ) {} + + getWeight(): number { + return this.product.weight * this.quantity; + } +} +``` + +## Refactoring Patterns + +### Extract Method +```typescript +// Before +function printOwing(invoice: Invoice) { + console.log('***********************'); + console.log('**** Customer Owes ****'); + console.log('***********************'); + + let outstanding = 0; + for (const order of invoice.orders) { + outstanding += order.amount; + } + + console.log(`name: ${invoice.customer}`); + console.log(`amount: ${outstanding}`); +} + +// After +function printOwing(invoice: Invoice) { + printBanner(); + const outstanding = calculateOutstanding(invoice); + printDetails(invoice, outstanding); +} + +function printBanner() { + console.log('***********************'); + console.log('**** Customer Owes ****'); + console.log('***********************'); +} + +function calculateOutstanding(invoice: Invoice): number { + return invoice.orders.reduce((sum, order) => sum + order.amount, 0); +} + +function printDetails(invoice: Invoice, outstanding: number) { + console.log(`name: ${invoice.customer}`); + console.log(`amount: ${outstanding}`); +} +``` + +### Replace Conditional with Polymorphism +```typescript +// Before +class Bird { + type: string; + + getSpeed(): number { + switch (this.type) { + case 'european': + return this.getBaseSpeed(); + case 'african': + return this.getBaseSpeed() - this.getLoadFactor() * this.numberOfCoconuts; + case 'norwegian': + return this.isNailed ? 0 : this.getBaseSpeed(); + default: + throw new Error('Unknown type'); + } + } +} + +// After +abstract class Bird { + abstract getSpeed(): number; + protected abstract getBaseSpeed(): number; +} + +class EuropeanBird extends Bird { + getSpeed(): number { + return this.getBaseSpeed(); + } + + protected getBaseSpeed(): number { + return 35; + } +} + +class AfricanBird extends Bird { + constructor(private numberOfCoconuts: number) { + super(); + } + + getSpeed(): number { + return this.getBaseSpeed() - this.getLoadFactor() * this.numberOfCoconuts; + } + + protected getBaseSpeed(): number { + return 40; + } + + private getLoadFactor(): number { + return 2; + } +} + +class NorwegianBird extends Bird { + constructor(private isNailed: boolean) { + super(); + } + + getSpeed(): number { + return this.isNailed ? 0 : this.getBaseSpeed(); + } + + protected getBaseSpeed(): number { + return 30; + } +} +``` + +### Replace Magic Numbers with Constants +```typescript +// Before +function calculatePrice(quantity: number, price: number): number { + if (quantity > 100) { + return quantity * price * 0.9; // What is 0.9? + } + return quantity * price; +} + +// After +const BULK_ORDER_THRESHOLD = 100; +const BULK_DISCOUNT_RATE = 0.1; + +function calculatePrice(quantity: number, price: number): number { + if (quantity > BULK_ORDER_THRESHOLD) { + return quantity * price * (1 - BULK_DISCOUNT_RATE); + } + return quantity * price; +} +``` + +## Clean Code Principles + +### Meaningful Names +```typescript +// Bad +function d(t: number) { + return t * 86400000; +} + +// Good +const MILLISECONDS_PER_DAY = 86400000; + +function daysToMilliseconds(days: number): number { + return days * MILLISECONDS_PER_DAY; +} +``` + +### Functions Should Do One Thing +```typescript +// Bad +function emailClients(clients: Client[]) { + clients.forEach(client => { + const clientRecord = database.lookup(client); + if (clientRecord.isActive()) { + email(client); + } + }); +} + +// Good +function emailActiveClients(clients: Client[]) { + clients + .filter(isActiveClient) + .forEach(email); +} + +function isActiveClient(client: Client): boolean { + const clientRecord = database.lookup(client); + return clientRecord.isActive(); +} +``` + +### Use Default Parameters +```typescript +// Bad +function createMenu(title: string, body: string, buttonText: string, cancellable: boolean) { + title = title || 'Default Title'; + body = body || 'Default Body'; + buttonText = buttonText || 'OK'; + cancellable = cancellable !== undefined ? cancellable : true; +} + +// Good +function createMenu( + title: string = 'Default Title', + body: string = 'Default Body', + buttonText: string = 'OK', + cancellable: boolean = true +) { + // ... +} +``` + +## Best Practices + +1. **Follow SOLID principles** +2. **Keep functions small and focused** +3. **Use meaningful names** +4. **Avoid code duplication (DRY)** +5. **Write self-documenting code** +6. **Refactor continuously** +7. **Test your code** +8. **Use consistent formatting** +9. **Handle errors properly** +10. **Review and improve regularly** diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..d58f318 --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,49 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:Dieshen/claude_marketplace:plugins/code-quality-refactoring", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "f5c0dd004c3ea168fc3142bb7d9423f115fd698f", + "treeHash": "a05f50e19ad1a2535e0930df0bdb5260ad6d89fd1b100e0218cd6befa8605b00", + "generatedAt": "2025-11-28T10:10:24.831226Z", + "toolVersion": "publish_plugins.py@0.2.0" + }, + "origin": { + "remote": "git@github.com:zhongweili/42plugin-data.git", + "branch": "master", + "commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390", + "repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data" + }, + "manifest": { + "name": "code-quality-refactoring", + "description": "Code quality improvement and refactoring patterns with SOLID principles and clean code practices", + "version": "1.0.0" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "e562f2d35e4ef2c1857bdda35cb4315b7ba95b67c2b76d21d1ab828674a4c796" + }, + { + "path": "agents/code-quality-improver.md", + "sha256": "222251c846c952cea3a3f838e4aeb30bac9f254684dd2f93e23e42c235d63729" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "38ad568d4d8d8616d11b3b036d555e4a73abe5ef9384f3aabb0a85d64d343341" + }, + { + "path": "commands/refactoring-patterns.md", + "sha256": "4f2fbf58dd0ee27724475b4da725f29d2b9b176bb450b5adfb034608316123d3" + } + ], + "dirSha256": "a05f50e19ad1a2535e0930df0bdb5260ad6d89fd1b100e0218cd6befa8605b00" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file