원클릭으로
clean-code
Use when reviewing or writing code to enforce DRY, KISS, and YAGNI principles with Java-specific guidance.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Use when reviewing or writing code to enforce DRY, KISS, and YAGNI principles with Java-specific guidance.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Use when implementing Spring Boot 3.x applications. Provides hands-on implementation patterns for web, data, security, testing, and cloud-native development.
Review REST API contracts for HTTP semantics, versioning, backward compatibility, and response consistency. Use when user asks "review API", "check endpoints", "REST review", or before releasing API changes.
Use when designing Spring Boot 3.x application architecture, making technology decisions, or planning project structure. Provides architectural patterns and references for project setup, JPA, security, testing, and reactive programming.
Use when designing, reviewing, or modifying REST API endpoints to enforce proper HTTP verbs, status codes, versioning, and API contract best practices.
Use when implementing or reviewing code that benefits from established design patterns like Builder, Factory, Strategy, Observer, Decorator, or Adapter.
Use when designing Spring Boot 3.x application architecture, making technology decisions, or planning project structure. Provides architectural patterns and references for project setup, JPA, security, testing, and reactive programming.
| name | clean-code |
| description | Use when reviewing or writing code to enforce DRY, KISS, and YAGNI principles with Java-specific guidance. |
Extract repeated logic into reusable methods or classes.
@RestController
@RequestMapping("/api")
public class OrderController {
@PostMapping("/orders")
public ResponseEntity<Order> createOrder(@RequestBody OrderRequest request) {
if (request.getCustomerId() == null || request.getCustomerId().isBlank()) {
throw new IllegalArgumentException("Customer ID is required");
}
if (request.getAmount() == null || request.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("Amount must be positive");
}
// ... create order
}
@PutMapping("/orders/{id}")
public ResponseEntity<Order> updateOrder(@PathVariable Long id, @RequestBody OrderRequest request) {
if (request.getCustomerId() == null || request.getCustomerId().isBlank()) {
throw new IllegalArgumentException("Customer ID is required");
}
if (request.getAmount() == null || request.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("Amount must be positive");
}
// ... update order
}
}
public record OrderRequest(
@NotBlank(message = "Customer ID is required")
String customerId,
@NotNull(message = "Amount is required")
@Positive(message = "Amount must be positive")
BigDecimal amount,
@NotEmpty(message = "At least one item is required")
List<@Valid OrderItemRequest> items
) {}
public record OrderItemRequest(
@NotBlank String productId,
@Min(1) int quantity
) {}
@RestController
@RequestMapping("/api/orders")
public class OrderController {
private final OrderService orderService;
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
@PostMapping
public ResponseEntity<OrderResponse> createOrder(@Valid @RequestBody OrderRequest request) {
return ResponseEntity.status(HttpStatus.CREATED)
.body(orderService.create(request));
}
@PutMapping("/{id}")
public ResponseEntity<OrderResponse> updateOrder(
@PathVariable Long id,
@Valid @RequestBody OrderRequest request) {
return ResponseEntity.ok(orderService.update(id, request));
}
}
@Component
public class OrderMapper {
public Order toEntity(OrderRequest request) {
Order order = new Order();
order.setCustomerId(request.customerId());
order.setAmount(request.amount());
order.setItems(request.items().stream()
.map(this::toItemEntity)
.toList());
return order;
}
public OrderResponse toResponse(Order order) {
return new OrderResponse(
order.getId(),
order.getCustomerId(),
order.getAmount(),
order.getStatus().name(),
order.getCreatedAt()
);
}
private OrderItem toItemEntity(OrderItemRequest request) {
OrderItem item = new OrderItem();
item.setProductId(request.productId());
item.setQuantity(request.quantity());
return item;
}
}
Avoid unnecessary complexity. Prefer straightforward solutions.
public abstract class AbstractGenericCrudService<T, ID, R extends JpaRepository<T, ID>> {
protected final R repository;
protected final Function<T, ?> entityToDto;
protected final Function<?, T> dtoToEntity;
// ... 200 lines of generic plumbing
}
@Service
public class ProductService {
private final ProductRepository productRepository;
private final ProductMapper productMapper;
public ProductService(ProductRepository productRepository, ProductMapper productMapper) {
this.productRepository = productRepository;
this.productMapper = productMapper;
}
public ProductResponse findById(Long id) {
Product product = productRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Product", id));
return productMapper.toResponse(product);
}
public Page<ProductResponse> findAll(Pageable pageable) {
return productRepository.findAll(pageable)
.map(productMapper::toResponse);
}
@Transactional
public ProductResponse create(ProductRequest request) {
Product product = productMapper.toEntity(request);
Product saved = productRepository.save(product);
return productMapper.toResponse(saved);
}
}
// Simple, centralized exception handling
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(ex.getMessage()));
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException ex) {
List<String> errors = ex.getBindingResult().getFieldErrors().stream()
.map(f -> f.getField() + ": " + f.getDefaultMessage())
.toList();
return ResponseEntity.badRequest()
.body(new ErrorResponse("Validation failed", errors));
}
}
public record ErrorResponse(String message, List<String> details) {
public ErrorResponse(String message) {
this(message, List.of());
}
}
Do not build features or abstractions until they are needed.
// Building a plugin system when you only have one implementation
public interface NotificationStrategy {
void send(Notification notification);
}
public class NotificationStrategyFactory {
private final Map<String, NotificationStrategy> strategies;
// ... when you only ever send emails
}
@Service
public class NotificationService {
private final JavaMailSender mailSender;
public NotificationService(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
public void sendOrderConfirmation(Order order, String recipientEmail) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(recipientEmail);
message.setSubject("Order Confirmation #" + order.getId());
message.setText("Your order has been confirmed. Total: " + order.getAmount());
mailSender.send(message);
}
}
public OrderResponse processOrder(OrderRequest request) {
// validate customer (10 lines)
// check inventory (15 lines)
// calculate price (20 lines)
// apply discounts (15 lines)
// create order (10 lines)
// send notification (10 lines)
// return response (5 lines)
}
@Service
public class OrderProcessingService {
private final CustomerService customerService;
private final InventoryService inventoryService;
private final PricingService pricingService;
private final OrderRepository orderRepository;
private final NotificationService notificationService;
private final OrderMapper orderMapper;
public OrderProcessingService(CustomerService customerService,
InventoryService inventoryService,
PricingService pricingService,
OrderRepository orderRepository,
NotificationService notificationService,
OrderMapper orderMapper) {
this.customerService = customerService;
this.inventoryService = inventoryService;
this.pricingService = pricingService;
this.orderRepository = orderRepository;
this.notificationService = notificationService;
this.orderMapper = orderMapper;
}
@Transactional
public OrderResponse processOrder(OrderRequest request) {
Customer customer = customerService.getVerifiedCustomer(request.customerId());
inventoryService.reserveItems(request.items());
BigDecimal total = pricingService.calculateTotal(request.items(), customer);
Order order = orderMapper.toEntity(request);
order.setTotalAmount(total);
order.setStatus(OrderStatus.CONFIRMED);
Order saved = orderRepository.save(order);
notificationService.sendOrderConfirmation(saved, customer.getEmail());
return orderMapper.toResponse(saved);
}
}
PascalCase - OrderService, ProductControllercamelCase - findById, calculateTotalUPPER_SNAKE_CASE - MAX_RETRY_COUNTpl.piomin.services.order.controlleris, has, can - isActive, hasPermissionList<Order> orders, Set<String> tags