From kent-beck-style
Reviews code using Kent Beck's refactoring philosophy and simple design principles. Detects code smells, guides refactoring, and promotes YAGNI/KISS.
How this skill is triggered — by the user, by Claude, or both
Slash command
/kent-beck-style:kent-beck-styleThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill analyzes and reviews code based on Kent Beck's refactoring philosophy and simple design principles. It focuses on code smells detection, refactoring techniques, and incremental design improvement.
This skill analyzes and reviews code based on Kent Beck's refactoring philosophy and simple design principles. It focuses on code smells detection, refactoring techniques, and incremental design improvement.
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand." - Martin Fowler (Refactoring, foreword by Kent Beck)
Kent Beck's rules in priority order:
// Bad: Speculative generality
interface DataProcessor<T, U, V> {
process(input: T, options: U): V;
processAsync(input: T, options: U): Promise<V>;
processBatch(inputs: T[], options: U): V[];
// We only need one sync method right now!
}
// Good: Build what you need
interface DataProcessor {
process(input: string): Result;
}
Code that has grown too large to handle.
// Bad: Long method doing many things
function processOrder(order: Order) {
// Validate order (10 lines)
// Calculate discount (15 lines)
// Apply tax (10 lines)
// Update inventory (20 lines)
// Send notification (15 lines)
// Generate invoice (25 lines)
}
// Good: Extracted into focused methods
function processOrder(order: Order) {
validateOrder(order);
const discount = calculateDiscount(order);
const total = applyTax(order.subtotal - discount);
updateInventory(order.items);
sendOrderConfirmation(order);
generateInvoice(order, total);
}
// Bad: Primitive obsession
function createUser(
name: string,
email: string,
phone: string,
street: string,
city: string,
zipCode: string
) { ... }
// Good: Value objects
function createUser(
name: Name,
email: Email,
phone: Phone,
address: Address
) { ... }
Improper application of OO principles.
// Bad: Switch statement
function calculateArea(shape: Shape): number {
switch (shape.type) {
case 'circle':
return Math.PI * shape.radius ** 2;
case 'rectangle':
return shape.width * shape.height;
case 'triangle':
return (shape.base * shape.height) / 2;
}
}
// Good: Polymorphism
interface Shape {
calculateArea(): number;
}
class Circle implements Shape {
calculateArea(): number {
return Math.PI * this.radius ** 2;
}
}
Code that makes changes difficult.
Code that is unnecessary.
// Bad: Duplicate code
function validateEmail(email: string): boolean {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
}
function isValidEmail(input: string): boolean {
const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return pattern.test(input);
}
// Good: Single source of truth
const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
function isValidEmail(email: string): boolean {
return EMAIL_PATTERN.test(email);
}
// Bad: Comment explaining what
// Check if user is adult
if (user.age >= 18) { ... }
// Good: Self-documenting code
const LEGAL_ADULT_AGE = 18;
if (user.isAdult()) { ... }
// Good use of comments: explaining why
// Using >= instead of > because legal age includes 18th birthday
if (user.age >= LEGAL_ADULT_AGE) { ... }
Code with excessive coupling.
// Bad: Feature envy
class OrderPrinter {
print(order: Order) {
console.log(`Order: ${order.id}`);
console.log(`Customer: ${order.customer.name}`);
console.log(`Total: ${order.items.reduce((sum, item) =>
sum + item.price * item.quantity, 0)}`);
}
}
// Good: Move calculation to Order
class Order {
getTotal(): number {
return this.items.reduce((sum, item) =>
sum + item.price * item.quantity, 0);
}
}
The most important refactoring. Turn code fragments into methods with intention-revealing names.
// Before
function printOwing() {
printBanner();
// Print details
console.log(`name: ${name}`);
console.log(`amount: ${getOutstanding()}`);
}
// After
function printOwing() {
printBanner();
printDetails();
}
function printDetails() {
console.log(`name: ${name}`);
console.log(`amount: ${getOutstanding()}`);
}
When method body is as clear as its name.
Replace temporary variables with method calls.
// Before
const basePrice = quantity * itemPrice;
if (basePrice > 1000) {
return basePrice * 0.95;
}
// After
if (getBasePrice() > 1000) {
return getBasePrice() * 0.95;
}
function getBasePrice() {
return quantity * itemPrice;
}
Move method to the class that uses it most.
Move field to where it's used most.
When a class does work that should be done by two.
When a class isn't doing much.
Always name your constants!
// Bad: Magic numbers
if (age >= 18) { ... }
const tax = price * 0.1;
setTimeout(callback, 86400000);
// Good: Named constants
const LEGAL_ADULT_AGE = 18;
const TAX_RATE = 0.1;
const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
if (age >= LEGAL_ADULT_AGE) { ... }
const tax = price * TAX_RATE;
setTimeout(callback, MILLISECONDS_PER_DAY);
Make fields private, provide accessors.
When a data item needs additional behavior.
Extract condition and branches into methods.
// Before
if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
charge = quantity * winterRate + winterServiceCharge;
} else {
charge = quantity * summerRate;
}
// After
if (isWinter(date)) {
charge = winterCharge(quantity);
} else {
charge = summerCharge(quantity);
}
Combine conditionals that have the same result.
Use early returns to reduce nesting.
// Before
function getPayAmount() {
let result;
if (isDead) {
result = deadAmount();
} else {
if (isSeparated) {
result = separatedAmount();
} else {
if (isRetired) {
result = retiredAmount();
} else {
result = normalPayAmount();
}
}
}
return result;
}
// After
function getPayAmount() {
if (isDead) return deadAmount();
if (isSeparated) return separatedAmount();
if (isRetired) return retiredAmount();
return normalPayAmount();
}
Names should reveal intent.
// Bad names
function calc(a, b) { ... }
function doIt() { ... }
function process(data) { ... }
// Good names
function calculateTotalPrice(items, taxRate) { ... }
function sendOrderConfirmation() { ... }
function validateUserCredentials(credentials) { ... }
Keep parameter lists minimal and meaningful.
Group related parameters.
Pass the object instead of extracting values.
Always replace magic numbers with named constants.
// Bad
if (response.status === 200) { ... }
if (password.length < 8) { ... }
const timeout = 30000;
// Good
const HTTP_OK = 200;
const MIN_PASSWORD_LENGTH = 8;
const DEFAULT_TIMEOUT_MS = 30000;
if (response.status === HTTP_OK) { ... }
if (password.length < MIN_PASSWORD_LENGTH) { ... }
const timeout = DEFAULT_TIMEOUT_MS;
// Bad naming
const d = new Date();
const flag = true;
function calc() { ... }
// Good naming
const currentDate = new Date();
const isUserAuthenticated = true;
function calculateShippingCost() { ... }
Code should express its intent without comments.
// Bad: Needs comment to explain
// Check if user can access premium content
if (user.subscription !== null &&
user.subscription.endDate > new Date() &&
user.subscription.tier === 'premium') { ... }
// Good: Self-documenting
if (user.hasPremiumAccess()) { ... }
class User {
hasPremiumAccess(): boolean {
return this.subscription?.isActive() &&
this.subscription?.tier === SubscriptionTier.PREMIUM;
}
}
// Step 1: Identify code to extract
function printOwing() {
printBanner();
// START: Code to extract
console.log(`name: ${name}`);
console.log(`amount: ${getOutstanding()}`);
// END: Code to extract
}
// Step 2: Create new method with extracted code
function printDetails() {
console.log(`name: ${name}`);
console.log(`amount: ${getOutstanding()}`);
}
// Step 3: Call new method from original location
function printOwing() {
printBanner();
printDetails();
}
// Step 4: Run tests, commit
Provide review results in this format:
# Kent Beck Style Code Review Report
## Summary
- Overall Code Health: [Good/Needs Improvement/Critical]
- Key findings summary
## Code Smells Detected
### [Smell Category]: [Specific Smell]
- **Location**: file:line
- **Description**: What the problem is
- **Impact**: Why it matters
- **Suggested Refactoring**: How to fix it
## Refactoring Recommendations
### High Priority
1. [Most impactful improvements]
### Medium Priority
1. [Moderate improvements]
### Low Priority (Nice to Have)
1. [Minor improvements]
## Positive Aspects
- What the code does well
// Code Smell: Primitive Obsession + Magic Numbers
function createDiscount(percent: number, startDate: string, endDate: string) {
if (percent < 0 || percent > 100) throw new Error('Invalid');
// ...
}
// Refactored
const MIN_DISCOUNT_PERCENT = 0;
const MAX_DISCOUNT_PERCENT = 100;
class DiscountPercent {
constructor(private value: number) {
if (value < MIN_DISCOUNT_PERCENT || value > MAX_DISCOUNT_PERCENT) {
throw new InvalidDiscountError(value);
}
}
}
class DateRange {
constructor(
private start: Date,
private end: Date
) {
if (start > end) throw new InvalidDateRangeError();
}
}
function createDiscount(percent: DiscountPercent, period: DateRange) { ... }
# Code Smell: Long Method + Feature Envy
def process_order(order):
# Validation (should be in Order)
if order['items'] is None or len(order['items']) == 0:
raise ValueError('Empty order')
# Calculation (should be in Order)
total = 0
for item in order['items']:
total += item['price'] * item['quantity']
# More processing...
# Refactored
class Order:
def __init__(self, items: list[OrderItem]):
self._validate_items(items)
self.items = items
def _validate_items(self, items):
if not items:
raise EmptyOrderError()
def calculate_total(self) -> Money:
return sum(item.subtotal for item in self.items)
def process_order(order: Order):
total = order.calculate_total()
# Processing with clear responsibilities...
// Code Smell: Switch Statement + Primitive Obsession
fun calculateShipping(type: String, weight: Double): Double {
return when (type) {
"standard" -> weight * 1.5
"express" -> weight * 3.0
"overnight" -> weight * 5.0
else -> throw IllegalArgumentException()
}
}
// Refactored
sealed class ShippingMethod {
abstract fun calculateCost(weight: Weight): Money
object Standard : ShippingMethod() {
private const val RATE_PER_KG = 1.5
override fun calculateCost(weight: Weight) =
Money(weight.kilograms * RATE_PER_KG)
}
object Express : ShippingMethod() {
private const val RATE_PER_KG = 3.0
override fun calculateCost(weight: Weight) =
Money(weight.kilograms * RATE_PER_KG)
}
object Overnight : ShippingMethod() {
private const val RATE_PER_KG = 5.0
override fun calculateCost(weight: Weight) =
Money(weight.kilograms * RATE_PER_KG)
}
}
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub nathankim0/clean-architecture-skills --plugin kent-beck-style