All skills
asyrafhussin avatar

/clean-code-principles

@680deef

SOLID principles, design patterns, DRY, KISS, and clean code fundamentals. Use when reviewing architecture, checking code quality, refactoring, or discussing design decisions. Triggers on "review architecture", "check code quality", "SOLID principles", "design patterns", or "clean code".

Use this Skill: https://skilld.dev/gh/asyrafhussin/agent-skills/clean-code-principles

This session only. Nothing lands on disk.

rulescore-dry-extraction.md

≈2.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

DRY - Code Extraction

Don't Repeat Yourself. When you find duplicated code, extract it into a reusable function, method, or module. Every piece of knowledge should have a single, unambiguous representation.

Bad Example

// Anti-pattern: Same validation logic repeated in multiple places

class UserController {
  async createUser(req: Request, res: Response): Promise<void> {
    const { email, password, name } = req.body;

    // Email validation - duplicated
    if (!email) {
      res.status(400).json({ error: 'Email is required' });
      return;
    }
    if (!email.includes('@') || !email.includes('.')) {
      res.status(400).json({ error: 'Invalid email format' });
      return;
    }
    if (email.length > 255) {
      res.status(400).json({ error: 'Email too long' });
      return;
    }

    // Password validation - duplicated
    if (!password) {
      res.status(400).json({ error: 'Password is required' });
      return;
    }
    if (password.length < 8) {
      res.status(400).json({ error: 'Password must be at least 8 characters' });
      return;
    }
    if (!/[A-Z]/.test(password)) {
      res.status(400).json({ error: 'Password must contain uppercase letter' });
      return;
    }
    if (!/[0-9]/.test(password)) {
      res.status(400).json({ error: 'Password must contain a number' });
      return;
    }

    // Create user...
  }

  async updateUser(req: Request, res: Response): Promise<void> {
    const { email, password } = req.body;

    // Same email validation repeated
    if (email) {
      if (!email.includes('@') || !email.includes('.')) {
        res.status(400).json({ error: 'Invalid email format' });
        return;
      }
      if (email.length > 255) {
        res.status(400).json({ error: 'Email too long' });
        return;
      }
    }

    // Same password validation repeated
    if (password) {
      if (password.length < 8) {
        res.status(400).json({ error: 'Password must be at least 8 characters' });
        return;
      }
      if (!/[A-Z]/.test(password)) {
        res.status(400).json({ error: 'Password must contain uppercase letter' });
        return;
      }
      if (!/[0-9]/.test(password)) {
        res.status(400).json({ error: 'Password must contain a number' });
        return;
      }
    }

    // Update user...
  }

  async resetPassword(req: Request, res: Response): Promise<void> {
    const { email, newPassword } = req.body;

    // Email validation repeated again
    if (!email) {
      res.status(400).json({ error: 'Email is required' });
      return;
    }
    if (!email.includes('@') || !email.includes('.')) {
      res.status(400).json({ error: 'Invalid email format' });
      return;
    }

    // Password validation repeated again
    if (!newPassword) {
      res.status(400).json({ error: 'New password is required' });
      return;
    }
    if (newPassword.length < 8) {
      res.status(400).json({ error: 'Password must be at least 8 characters' });
      return;
    }
    if (!/[A-Z]/.test(newPassword)) {
      res.status(400).json({ error: 'Password must contain uppercase letter' });
      return;
    }
    if (!/[0-9]/.test(newPassword)) {
      res.status(400).json({ error: 'Password must contain a number' });
      return;
    }

    // Reset password...
  }
}

Good Example

// Correct approach: Extract reusable validation functions

// Validation result type
interface ValidationResult {
  isValid: boolean;
  errors: string[];
}

// Reusable validation functions
class Validators {
  static email(email: string | undefined, options: { required?: boolean } = {}): ValidationResult {
    const errors: string[] = [];

    if (!email) {
      if (options.required) {
        errors.push('Email is required');
      }
      return { isValid: !options.required, errors };
    }

    if (!email.includes('@') || !email.includes('.')) {
      errors.push('Invalid email format');
    }

    if (email.length > 255) {
      errors.push('Email must be 255 characters or less');
    }

    return { isValid: errors.length === 0, errors };
  }

  static password(password: string | undefined, options: { required?: boolean } = {}): ValidationResult {
    const errors: string[] = [];

    if (!password) {
      if (options.required) {
        errors.push('Password is required');
      }
      return { isValid: !options.required, errors };
    }

    if (password.length < 8) {
      errors.push('Password must be at least 8 characters');
    }

    if (!/[A-Z]/.test(password)) {
      errors.push('Password must contain at least one uppercase letter');
    }

    if (!/[a-z]/.test(password)) {
      errors.push('Password must contain at least one lowercase letter');
    }

    if (!/[0-9]/.test(password)) {
      errors.push('Password must contain at least one number');
    }

    return { isValid: errors.length === 0, errors };
  }

  static combine(...results: ValidationResult[]): ValidationResult {
    const errors = results.flatMap(r => r.errors);
    return { isValid: errors.length === 0, errors };
  }
}

// Reusable error response helper
function validationError(res: Response, errors: string[]): void {
  res.status(400).json({ errors });
}

// Clean controller using extracted validations
class UserController {
  async createUser(req: Request, res: Response): Promise<void> {
    const { email, password, name } = req.body;

    const validation = Validators.combine(
      Validators.email(email, { required: true }),
      Validators.password(password, { required: true })
    );

    if (!validation.isValid) {
      return validationError(res, validation.errors);
    }

    // Create user...
  }

  async updateUser(req: Request, res: Response): Promise<void> {
    const { email, password } = req.body;

    const validation = Validators.combine(
      Validators.email(email),
      Validators.password(password)
    );

    if (!validation.isValid) {
      return validationError(res, validation.errors);
    }

    // Update user...
  }

  async resetPassword(req: Request, res: Response): Promise<void> {
    const { email, newPassword } = req.body;

    const validation = Validators.combine(
      Validators.email(email, { required: true }),
      Validators.password(newPassword, { required: true })
    );

    if (!validation.isValid) {
      return validationError(res, validation.errors);
    }

    // Reset password...
  }
}

// Validators can be reused across the application
class AdminController {
  async inviteUser(req: Request, res: Response): Promise<void> {
    const { email } = req.body;

    const validation = Validators.email(email, { required: true });

    if (!validation.isValid) {
      return validationError(res, validation.errors);
    }

    // Send invite...
  }
}

// Easy to test in isolation
describe('Validators', () => {
  describe('email', () => {
    it('should reject invalid email format', () => {
      const result = Validators.email('invalid');
      expect(result.isValid).toBe(false);
      expect(result.errors).toContain('Invalid email format');
    });

    it('should accept valid email', () => {
      const result = Validators.email('user@example.com');
      expect(result.isValid).toBe(true);
    });

    it('should require email when required option is set', () => {
      const result = Validators.email(undefined, { required: true });
      expect(result.isValid).toBe(false);
      expect(result.errors).toContain('Email is required');
    });
  });

  describe('password', () => {
    it('should reject short passwords', () => {
      const result = Validators.password('short');
      expect(result.isValid).toBe(false);
      expect(result.errors).toContain('Password must be at least 8 characters');
    });

    it('should require uppercase letter', () => {
      const result = Validators.password('lowercase123');
      expect(result.isValid).toBe(false);
      expect(result.errors).toContain('Password must contain at least one uppercase letter');
    });
  });
});

Why

  1. Single Source of Truth: Password rules are defined once. Change them in one place, and all usages are updated.

  2. Consistency: All email validations behave the same way. No risk of inconsistent error messages or rules.

  3. Easier Testing: Test the validation logic once, thoroughly. No need to test the same logic in every controller.

  4. Bug Fixes Propagate: Fix a bug in Validators.email(), and it's fixed everywhere.

  5. Reduced Code Size: Less code means less to read, less to maintain, and fewer places for bugs.

  6. Better Abstraction: Controllers focus on HTTP concerns, validators focus on validation.

  7. Reusability: Same validators work in controllers, services, CLI tools, or anywhere else.

Source: SKILL.md on GitHub

1 warning16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    This skill contains language-agnostic guidelines, examples, and reference material for clean code and SOLID principles. It consists purely of static documentation and contains no executable code or security risks.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    5/29 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 680deef. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last month.

Steadyupdated 7 months ago
metadata
{
  "author": "AsyrafHussin",
  "version": "1.0.2"
}

README badge

README badge for asyrafhussin/agent-skills/clean-code-principles