| name | code-quality-standards |
| description | Code quality standards including SOLID principles, design patterns, code smells, refactoring techniques, naming conventions, and technical debt management. Use when reviewing code, refactoring, ensuring quality, or detecting code smells. |
Code Quality Standards
This skill provides comprehensive guidance for writing clean, maintainable, and high-quality code.
SOLID Principles
S - Single Responsibility Principle
Definition: A class should have only one reason to change.
class UserManager {
createUser(data: UserData) {
if (!data.email.includes('@')) throw new Error('Invalid email');
const user = database.insert('users', data);
emailService.send(data.email, 'Welcome!');
logger.info(`User created: ${data.email}`);
return user;
}
}
class UserValidator {
validate(data: UserData): void {
if (!data.email.includes('@')) {
throw new Error('Invalid email');
}
}
}
class UserRepository {
create(data: UserData): User {
return database.insert('users', data);
}
}
class UserNotificationService {
sendWelcomeEmail(email: string): void {
emailService.send(email, 'Welcome!');
}
}
class UserService {
constructor(
private validator: UserValidator,
private repository: UserRepository,
private notificationService: UserNotificationService,
private logger: Logger
) {}
async createUser(data: UserData): Promise<User> {
this.validator.validate(data);
const user = await this.repository.create(data);
await this.notificationService.sendWelcomeEmail(user.email);
this.logger.info(`User created: ${user.email}`);
return user;
}
}
O - Open/Closed Principle
Definition: Classes should be open for extension but closed for modification.
class PaymentProcessor {
process(type: string, amount: number) {
if (type === 'credit_card') {
} else if (type === 'paypal') {
} else if (type === 'bitcoin') {
}
}
}
interface PaymentMethod {
process(amount: number): Promise<PaymentResult>;
}
class CreditCardPayment implements PaymentMethod {
async process(amount: number): Promise<PaymentResult> {
return { success: true };
}
}
class PayPalPayment implements PaymentMethod {
async process(amount: number): Promise<PaymentResult> {
return { success: true };
}
}
class PaymentProcessor {
async process(method: PaymentMethod, amount: number): Promise<PaymentResult> {
return await method.process(amount);
}
}
class BitcoinPayment implements PaymentMethod {
async process(amount: number): Promise<PaymentResult> {
return { success: true };
}
}
L - Liskov Substitution Principle
Definition: Subtypes must be substitutable for their base types.
class Rectangle {
constructor(protected width: number, protected height: number) {}
setWidth(width: number) {
this.width = width;
}
setHeight(height: number) {
this.height = height;
}
getArea(): number {
return this.width * this.height;
}
}
class Square extends Rectangle {
setWidth(width: number) {
this.width = width;
this.height = width;
}
setHeight(height: number) {
this.width = height;
this.height = height;
}
}
interface Shape {
getArea(): number;
}
class Rectangle implements Shape {
constructor(private width: number, private height: number) {}
getArea(): number {
return this.width * this.height;
}
}
class Square implements Shape {
constructor(private side: number) {}
getArea(): number {
return this.side * this.side;
}
}
I - Interface Segregation Principle
Definition: Clients shouldn't be forced to depend on interfaces they don't use.
interface Worker {
work(): void;
eat(): void;
sleep(): void;
getPaid(): void;
}
class HumanWorker implements Worker {
work() { }
eat() { }
sleep() { }
getPaid() { }
}
class RobotWorker implements Worker {
work() { }
eat() { }
sleep() { }
getPaid() { }
}
interface Workable {
work(): void;
}
interface Eatable {
eat(): void;
}
interface Sleepable {
sleep(): void;
}
interface Payable {
getPaid(): void;
}
class HumanWorker implements Workable, Eatable, Sleepable, Payable {
work() { }
eat() { }
sleep() { }
getPaid() { }
}
class RobotWorker implements Workable {
work() { }
}
D - Dependency Inversion Principle
Definition: Depend on abstractions, not concretions.
class UserService {
private database = new MySQLDatabase();
async getUser(id: string) {
return this.database.query(`SELECT * FROM users WHERE id = ${id}`);
}
}
interface Database {
query(sql: string): Promise<any>;
}
class MySQLDatabase implements Database {
async query(sql: string): Promise<any> {
}
}
class PostgreSQLDatabase implements Database {
async query(sql: string): Promise<any> {
}
}
class UserService {
constructor(private database: Database) {}
async getUser(id: string) {
return this.database.query(`SELECT * FROM users WHERE id = ${id}`);
}
}
const userService = new UserService(new PostgreSQLDatabase());
DRY (Don't Repeat Yourself)
Identifying Duplication
function createUser(data: UserData) {
if (!data.email || !data.email.includes('@')) {
throw new Error('Invalid email');
}
if (!data.password || data.password.length < 8) {
throw new Error('Password too short');
}
}
function updateUser(id: string, data: UserData) {
if (!data.email || !data.email.includes('@')) {
throw new Error('Invalid email');
}
if (!data.password || data.password.length < 8) {
throw new Error('Password too short');
}
}
function validateUserData(data: UserData): void {
if (!data.email || !data.email.includes('@')) {
throw new Error('Invalid email');
}
if (!data.password || data.password.length < 8) {
throw new Error('Password too short');
}
}
function createUser(data: UserData) {
validateUserData(data);
}
function updateUser(id: string, data: UserData) {
validateUserData(data);
}
KISS (Keep It Simple, Stupid)
class NumberProcessor {
private strategy: ProcessingStrategy;
constructor(strategy: ProcessingStrategy) {
this.strategy = strategy;
}
process(numbers: number[]): number[] {
return this.strategy.execute(numbers);
}
}
interface ProcessingStrategy {
execute(numbers: number[]): number[];
}
class MultiplyByTwoStrategy implements ProcessingStrategy {
execute(numbers: number[]): number[] {
return numbers.map(n => n * 2);
}
}
function multiplyByTwo(numbers: number[]): number[] {
return numbers.map(n => n * 2);
}
YAGNI (You Aren't Gonna Need It)
class User {
id: string;
email: string;
name: string;
preferences?: UserPreferences;
badges?: Badge[];
followers?: User[];
following?: User[];
achievements?: Achievement[];
notifications?: Notification[];
}
class User {
id: string;
email: string;
name: string;
}
Design Patterns
Factory Pattern
interface Animal {
speak(): string;
}
class Dog implements Animal {
speak(): string {
return 'Woof!';
}
}
class Cat implements Animal {
speak(): string {
return 'Meow!';
}
}
class AnimalFactory {
static create(type: 'dog' | 'cat'): Animal {
switch (type) {
case 'dog':
return new Dog();
case 'cat':
return new Cat();
default:
throw new Error('Unknown animal type');
}
}
}
const dog = AnimalFactory.create('dog');
console.log(dog.speak());
Strategy Pattern
interface SortStrategy {
sort(data: number[]): number[];
}
class QuickSort implements SortStrategy {
sort(data: number[]): number[] {
return data.sort((a, b) => a - b);
}
}
class MergeSort implements SortStrategy {
sort(data: number[]): number[] {
return data.sort((a, b) => a - b);
}
}
class Sorter {
constructor(private strategy: SortStrategy) {}
setStrategy(strategy: SortStrategy) {
this.strategy = strategy;
}
sort(data: number[]): number[] {
return this.strategy.sort(data);
}
}
const sorter = new Sorter(new QuickSort());
sorter.sort([3, 1, 4, 1, 5]);
sorter.setStrategy(new MergeSort());
sorter.sort([3, 1, 4, 1, 5]);
Observer Pattern
interface Observer {
update(data: any): void;
}
class Subject {
private observers: Observer[] = [];
attach(observer: Observer): void {
this.observers.push(observer);
}
detach(observer: Observer): void {
const index = this.observers.indexOf(observer);
if (index > -1) {
this.observers.splice(index, 1);
}
}
notify(data: any): void {
for (const observer of this.observers) {
observer.update(data);
}
}
}
class EmailNotifier implements Observer {
update(data: any): void {
console.log(`Sending email: ${data}`);
}
}
class SMSNotifier implements Observer {
update(data: any): void {
console.log(`Sending SMS: ${data}`);
}
}
const subject = new Subject();
subject.attach(new EmailNotifier());
subject.attach(new SMSNotifier());
subject.notify('New user registered!');
Singleton Pattern
class Database {
private static instance: Database;
private connection: any;
private constructor() {
this.connection = this.createConnection();
}
static getInstance(): Database {
if (!Database.instance) {
Database.instance = new Database();
}
return Database.instance;
}
private createConnection() {
return {};
}
query(sql: string) {
}
}
const db1 = Database.getInstance();
const db2 = Database.getInstance();
console.log(db1 === db2);
Code Smells and Detection
Long Method
function processOrder(order: Order) {
}
function processOrder(order: Order) {
validateOrder(order);
const total = calculateTotal(order);
const discounted = applyDiscounts(total, order.promoCode);
processPayment(discounted);
sendConfirmation(order.email);
updateInventory(order.items);
logTransaction(order.id);
}
Large Class
class User {
}
class User {
id: string;
email: string;
name: string;
}
class UserValidator {
validate(user: User): boolean { }
}
class UserRepository {
save(user: User): Promise<void> { }
find(id: string): Promise<User> { }
}
class UserAuthService {
authenticate(credentials: Credentials): Promise<Token> { }
}
Duplicate Code
function calculateEmployeeSalary(employee: Employee) {
let salary = employee.baseSalary;
salary += employee.baseSalary * 0.1;
salary += employee.baseSalary * 0.05;
return salary;
}
function calculateContractorSalary(contractor: Contractor) {
let salary = contractor.baseSalary;
salary += contractor.baseSalary * 0.1;
salary += contractor.baseSalary * 0.05;
return salary;
}
function calculateSalary(baseSalary: number): number {
let salary = baseSalary;
salary += baseSalary * 0.1;
salary += baseSalary * 0.05;
return salary;
}
function calculateEmployeeSalary(employee: Employee) {
return calculateSalary(employee.baseSalary);
}
function calculateContractorSalary(contractor: Contractor) {
return calculateSalary(contractor.baseSalary);
}
God Object
class Application {
database: Database;
emailService: EmailService;
paymentProcessor: PaymentProcessor;
createUser() { }
sendEmail() { }
processPayment() { }
generateReport() { }
validateInput() { }
}
class UserService {
createUser() { }
}
class NotificationService {
sendEmail() { }
}
class PaymentService {
processPayment() { }
}
Refactoring Patterns
Extract Method
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}`);
}
function printOwing(invoice: Invoice) {
printBanner();
const outstanding = calculateOutstanding(invoice);
printDetails(invoice.customer, 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(customer: string, outstanding: number) {
console.log(`Name: ${customer}`);
console.log(`Amount: ${outstanding}`);
}
Introduce Parameter Object
function createUser(
firstName: string,
lastName: string,
email: string,
phone: string,
address: string,
city: string,
state: string,
zip: string
) {
}
interface UserDetails {
firstName: string;
lastName: string;
email: string;
phone: string;
address: Address;
}
interface Address {
street: string;
city: string;
state: string;
zip: string;
}
function createUser(details: UserDetails) {
}
Replace Conditional with Polymorphism
class Bird {
type: 'european' | 'african' | 'norwegian';
getSpeed(): number {
switch (this.type) {
case 'european':
return 35;
case 'african':
return 40;
case 'norwegian':
return 24;
}
}
}
abstract class Bird {
abstract getSpeed(): number;
}
class EuropeanBird extends Bird {
getSpeed(): number {
return 35;
}
}
class AfricanBird extends Bird {
getSpeed(): number {
return 40;
}
}
class NorwegianBird extends Bird {
getSpeed(): number {
return 24;
}
}
Naming Conventions
Variables
const userEmail = 'user@example.com';
const totalPrice = 100;
const isActive = true;
const hasPermission = false;
const e = 'user@example.com';
const temp = 100;
const flag = true;
const data = {};
Functions
function getUserById(id: string): User { }
function calculateTotalPrice(items: Item[]): number { }
function isValidEmail(email: string): boolean { }
function hasPermission(user: User, resource: string): boolean { }
function user(id: string): User { }
function price(items: Item[]): number { }
function email(email: string): boolean { }
Classes
class UserRepository { }
class EmailValidator { }
class PaymentProcessor { }
class DatabaseConnection { }
class Manager { }
class Handler { }
class Process { }
Constants
const MAX_RETRY_ATTEMPTS = 3;
const API_BASE_URL = 'https://api.example.com';
const DEFAULT_TIMEOUT_MS = 5000;
const databaseConfig = {
host: 'localhost',
port: 5432,
};
Function/Method Size Guidelines
Keep Functions Under 20 Lines
function processOrder(order: Order) {
}
function processOrder(order: Order) {
validateOrder(order);
const total = calculateTotal(order);
const payment = processPayment(order, total);
sendConfirmation(order, payment);
updateInventory(order);
}
function validateOrder(order: Order) {
}
function calculateTotal(order: Order): number {
}
Maximum 3-4 Parameters
function createUser(
firstName: string,
lastName: string,
email: string,
phone: string,
role: string,
department: string
) { }
interface CreateUserParams {
firstName: string;
lastName: string;
email: string;
phone: string;
role: string;
department: string;
}
function createUser(params: CreateUserParams) { }
Cyclomatic Complexity
Keep Complexity Under 10
function calculatePrice(item: Item, user: User): number {
let price = item.basePrice;
if (user.isPremium) {
price *= 0.9;
}
if (item.category === 'electronics') {
if (item.brand === 'Apple') {
price *= 1.2;
} else if (item.brand === 'Samsung') {
price *= 1.1;
}
}
if (user.location === 'CA') {
price *= 1.08;
} else if (user.location === 'NY') {
price *= 1.09;
} else if (user.location === 'TX') {
price *= 1.06;
}
return price;
}
function calculatePrice(item: Item, user: User): number {
let price = item.basePrice;
price = applyUserDiscount(price, user);
price = applyBrandMarkup(price, item);
price = applyLocationTax(price, user.location);
return price;
}
function applyUserDiscount(price: number, user: User): number {
return user.isPremium ? price * 0.9 : price;
}
function applyBrandMarkup(price: number, item: Item): number {
const markups = {
'Apple': 1.2,
'Samsung': 1.1,
};
return item.category === 'electronics'
? price * (markups[item.brand] || 1)
: price;
}
function applyLocationTax(price: number, location: string): number {
const taxRates = {
'CA': 1.08,
'NY': 1.09,
'TX': 1.06,
};
return price * (taxRates[location] || 1);
}
Technical Debt Management
Document Technical Debt
Track in Issue Tracker
## Technical Debt Items
### High Priority
- [ ] Refactor UserService - violates SRP (Est: 8h)
- [ ] Replace deprecated payment API (Est: 16h)
- [ ] Fix race condition in order processing (Est: 4h)
### Medium Priority
- [ ] Optimize slow database queries (Est: 8h)
- [ ] Add missing unit tests for AuthService (Est: 6h)
### Low Priority
- [ ] Improve error messages (Est: 2h)
- [ ] Update documentation (Est: 4h)
Allocate Time for Refactoring
20% Rule: Spend 20% of sprint capacity on technical debt
- 4 out of 10 story points
- 1 out of 5 days per sprint
- Prevents debt from accumulating
Code Review Checklist
Functionality:
Design:
Readability:
Tests:
Performance:
Security:
When to Use This Skill
Use this skill when:
- Reviewing code in pull requests
- Refactoring existing code
- Setting code standards for team
- Onboarding new developers
- Conducting code quality audits
- Planning technical debt reduction
- Designing new features
- Improving codebase maintainability
- Training team on best practices
- Establishing coding guidelines
Remember: Code quality is not about perfection, but about maintainability. Write code that your future self and team members will thank you for.