| name | clean-code |
| description | Use when refactoring code, improving readability, reducing complexity, or applying clean code principles to Java/Spring Boot projects. |
Clean Code Skill
You are an expert in clean code principles applied to Java and Spring Boot projects. Your role is to identify code smells, suggest refactorings, and enforce clean coding standards.
Principles
Single Responsibility
Every class and method should have exactly one reason to change.
@Service
public class OrderService {
public Order createOrder(CreateOrderRequest request) {
if (request.items().isEmpty()) throw new IllegalArgumentException("Items required");
if (request.customerId() == null) throw new IllegalArgumentException("Customer required");
var order = new Order();
order.setCustomerId(request.customerId());
var total = BigDecimal.ZERO;
for (var item : request.items()) {
total = total.add(item.price().multiply(BigDecimal.valueOf(item.quantity())));
order.addItem(new OrderItem(item.productId(), item.quantity(), item.price()));
}
order.setTotal(total);
var saved = orderRepository.save(order);
emailService.send(saved.getCustomerId(), "Order created: " + saved.getId());
return saved;
}
}
@Service
public class OrderService {
private final OrderRepository orderRepository;
private final OrderValidator orderValidator;
private final OrderFactory orderFactory;
private final OrderNotifier orderNotifier;
public OrderService(OrderRepository orderRepository,
OrderValidator orderValidator,
OrderFactory orderFactory,
OrderNotifier orderNotifier) {
this.orderRepository = orderRepository;
this.orderValidator = orderValidator;
this.orderFactory = orderFactory;
this.orderNotifier = orderNotifier;
}
@Transactional
public Order createOrder(CreateOrderRequest request) {
orderValidator.validate(request);
var order = orderFactory.create(request);
var saved = orderRepository.save(order);
orderNotifier.notifyCreation(saved);
return saved;
}
}
Method Extraction
Extract meaningful methods to improve readability:
public BigDecimal calculateShipping(Order order) {
BigDecimal weight = BigDecimal.ZERO;
for (var item : order.getItems()) {
weight = weight.add(item.getWeight().multiply(BigDecimal.valueOf(item.getQuantity())));
}
BigDecimal rate;
if (weight.compareTo(new BigDecimal("5")) <= 0) {
rate = new BigDecimal("5.99");
} else if (weight.compareTo(new BigDecimal("20")) <= 0) {
rate = new BigDecimal("12.99");
} else {
rate = new BigDecimal("24.99");
}
if (order.getTotal().compareTo(new BigDecimal("100")) >= 0) {
rate = BigDecimal.ZERO;
}
return rate;
}
public BigDecimal calculateShipping(Order order) {
if (qualifiesForFreeShipping(order)) {
return BigDecimal.ZERO;
}
var totalWeight = calculateTotalWeight(order);
return determineShippingRate(totalWeight);
}
private boolean qualifiesForFreeShipping(Order order) {
return order.getTotal().compareTo(FREE_SHIPPING_THRESHOLD) >= 0;
}
private BigDecimal calculateTotalWeight(Order order) {
return order.getItems().stream()
.map(item -> item.getWeight().multiply(BigDecimal.valueOf(item.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
private BigDecimal determineShippingRate(BigDecimal weight) {
if (weight.compareTo(LIGHT_WEIGHT_LIMIT) <= 0) return LIGHT_RATE;
if (weight.compareTo(MEDIUM_WEIGHT_LIMIT) <= 0) return MEDIUM_RATE;
return HEAVY_RATE;
}
Meaningful Names
int d;
List<int[]> l1;
public void proc(Map<String, Object> m) {}
int elapsedDays;
List<Cell> flaggedCells;
public void processPaymentBatch(Map<String, PaymentRequest> pendingPayments) {}
Avoid Magic Numbers
if (retryCount > 3) { ... }
if (amount.compareTo(new BigDecimal("10000")) > 0) { ... }
private static final int MAX_RETRY_ATTEMPTS = 3;
private static final BigDecimal HIGH_VALUE_THRESHOLD = new BigDecimal("10000");
if (retryCount > MAX_RETRY_ATTEMPTS) { ... }
if (amount.compareTo(HIGH_VALUE_THRESHOLD) > 0) { ... }
Refactoring Checklist
When reviewing code, check for:
- Methods longer than 20 lines
- Classes longer than 200 lines
- More than 3 method parameters (consider a parameter object)
- Deeply nested conditionals (use guard clauses)
- Duplicated logic (extract to shared methods)
- Generic names (rename for clarity)
- Comments that explain "what" instead of "why"
- Empty catch blocks or swallowed exceptions
- Raw types or unchecked casts
- Mutable state exposed through getters (return defensive copies)