71. Code Review: OrderService #
π₯ Π‘Π΄Π΅Π»Π°ΠΉ ΡΠ΅Π²ΡΡ ΠΊΠΎΠ΄Π° Π½ΠΈΠΆΠ΅. ΠΠ° ΡΡΠΎ ΠΎΠ±ΡΠ°ΡΠΈΡΡ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, ΡΡΠΎ ΠΈΡΠΏΡΠ°Π²ΠΈΡΡ, ΠΊΠ°ΠΊΠΈΠ΅ ΡΠΈΡΠΊΠΈ ΠΈ ΡΠ»ΡΡΡΠ΅Π½ΠΈΡ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ?
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Inject
private AuditRepository auditRepository;
public void save(Order order) throws OrderValidationException {
try {
saveOrderInternal(order);
} catch (Throwable e) {
e.printStackTrace();
throw new OrderSaveException(e, order);
}
}
@Transactional
private void saveOrderInternal(Order order) throws OrderValidationException {
auditRepository.save(order);
if (order.getClient().getName() == """") {
throw new OrderValidationException(""ΠΠΎΠ»Π΅ ΠΊΠ»ΠΈΠ΅Π½Ρ Π½Π΅ Π·Π°ΠΏΠΎΠ»Π½Π΅Π½ΠΎ."");
}
orderRepository.save(order);
}
}
public class OrderValidationException extends Exception {
// ...
}
Π‘ΠΏΠΎΠΉΠ»Π΅ΡΡ ΠΊ ΡΠ΅ΡΠ΅Π½ΠΈΡ
ΠΠΎΠ΄ΡΠΊΠ°Π·ΠΊΠΈ
π‘ ΠΠ΅ ΡΠΌΠ΅ΡΠΈΠ²Π°ΠΉ ΡΠ°Π·Π½ΡΠ΅ DI-Π°Π½Π½ΠΎΡΠ°ΡΠΈΠΈ: Π²ΡΠ±Π΅ΡΠΈ
π‘ ΠΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠΉ
π‘ ΠΠ°Π»ΠΈΠ΄Π°ΡΠΈΡ Π»ΡΡΡΠ΅ Π΄Π΅Π»Π°ΡΡ Π΄ΠΎ ΡΠΎΡ ΡΠ°Π½Π΅Π½ΠΈΡ, Π° Π½Π΅ ΠΏΠΎΡΡΠ΅Π΄ΠΈ ΡΡΠ°Π½Π·Π°ΠΊΡΠΈΠΈ.
π‘ ΠΠ»Ρ ΡΡΡΠΎΠΊ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠΉ
π‘ ΠΠ΅ΡΠΎΠ΄
π‘
π‘ ΠΡΡΡΠ΅ ΡΠ°Π±ΠΎΡΠ°ΡΡ Ρ ΠΊΠ°ΡΡΠΎΠΌΠ½ΡΠΌΠΈ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΡΠΌΠΈ: checked vs unchecked. ΠΠ±ΡΡΠ½ΠΎ Π΄Π»Ρ Π±ΠΈΠ·Π½Π΅Ρ-ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠΉ Π΄Π΅Π»Π°ΡΡ
π‘ ΠΠΎΠ³ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠ΅ΡΠ΅Π·
π‘ ΠΠ°ΡΡΡΠ΅Π½ΠΈΠ΅ SRP: ΠΊΠ»Π°ΡΡ ΠΎΠ΄Π½ΠΎΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΠΎ ΠΎΡΠ²Π΅ΡΠ°Π΅Ρ Π·Π° Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡ, ΡΠΎΡ ΡΠ°Π½Π΅Π½ΠΈΠ΅ ΠΈ Π°ΡΠ΄ΠΈΡ.
@Autowired
ΠΈΠ»ΠΈ @Inject
.π‘ ΠΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠΉ
Throwable
Π² catch
: Π»ΡΡΡΠ΅ Exception
ΠΈΠ»ΠΈ Π±ΠΎΠ»Π΅Π΅ ΡΠ·ΠΊΠΈΠΉ ΡΠΈΠΏ.π‘ ΠΠ°Π»ΠΈΠ΄Π°ΡΠΈΡ Π»ΡΡΡΠ΅ Π΄Π΅Π»Π°ΡΡ Π΄ΠΎ ΡΠΎΡ ΡΠ°Π½Π΅Π½ΠΈΡ, Π° Π½Π΅ ΠΏΠΎΡΡΠ΅Π΄ΠΈ ΡΡΠ°Π½Π·Π°ΠΊΡΠΈΠΈ.
π‘ ΠΠ»Ρ ΡΡΡΠΎΠΊ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠΉ
isEmpty()
ΠΈΠ»ΠΈ StringUtils.isBlank()
, Π° Π½Π΅ == ""
.π‘ ΠΠ΅ΡΠΎΠ΄
saveOrderInternal
ΠΏΡΠΈΠ²Π°ΡΠ½ΡΠΉ, Π½ΠΎ Π°Π½Π½ΠΎΡΠ°ΡΠΈΡ @Transactional
Π½Π΅ ΠΏΠΎΠ΄Π΅ΠΉΡΡΠ²ΡΠ΅Ρ Π½Π° Π²Π½ΡΡΡΠ΅Π½Π½ΠΈΠ΅ Π²ΡΠ·ΠΎΠ²Ρ.π‘
auditRepository.save(order)
Π΄ΠΎ Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΠΈ β ΠΌΠΎΠΆΠ΅Ρ ΠΎΡΡΠ°Π²ΠΈΡΡ βΠ³ΡΡΠ·Π½ΡΠ΅β Π·Π°ΠΏΠΈΡΠΈ.π‘ ΠΡΡΡΠ΅ ΡΠ°Π±ΠΎΡΠ°ΡΡ Ρ ΠΊΠ°ΡΡΠΎΠΌΠ½ΡΠΌΠΈ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΡΠΌΠΈ: checked vs unchecked. ΠΠ±ΡΡΠ½ΠΎ Π΄Π»Ρ Π±ΠΈΠ·Π½Π΅Ρ-ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠΉ Π΄Π΅Π»Π°ΡΡ
RuntimeException
.π‘ ΠΠΎΠ³ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠ΅ΡΠ΅Π·
logger.error(...)
, Π° Π½Π΅ printStackTrace()
.π‘ ΠΠ°ΡΡΡΠ΅Π½ΠΈΠ΅ SRP: ΠΊΠ»Π°ΡΡ ΠΎΠ΄Π½ΠΎΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΠΎ ΠΎΡΠ²Π΅ΡΠ°Π΅Ρ Π·Π° Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡ, ΡΠΎΡ ΡΠ°Π½Π΅Π½ΠΈΠ΅ ΠΈ Π°ΡΠ΄ΠΈΡ.
Π Π΅ΡΠ΅Π½ΠΈΠ΅
@Service
public class OrderService {
private final OrderRepository orderRepository;
private final AuditRepository auditRepository;
private final OrderValidator orderValidator;
private static final Logger log = LoggerFactory.getLogger(OrderService.class);
@Autowired
public OrderService(OrderRepository orderRepository,
AuditRepository auditRepository,
OrderValidator orderValidator) {
this.orderRepository = orderRepository;
this.auditRepository = auditRepository;
this.orderValidator = orderValidator;
}
@Transactional
public void save(Order order) {
try {
orderValidator.validate(order); // Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡ Π΄ΠΎ ΡΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΡ
orderRepository.save(order);
auditRepository.save(order);
} catch (OrderValidationException e) {
log.warn("ΠΡΠΈΠ±ΠΊΠ° Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΠΈ Π·Π°ΠΊΠ°Π·Π°: {}", order, e);
throw e;
} catch (Exception e) {
log.error("ΠΡΠΈΠ±ΠΊΠ° ΡΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΡ Π·Π°ΠΊΠ°Π·Π°: {}", order, e);
throw new OrderSaveException(e, order);
}
}
}
@Component
public class OrderValidator {
public void validate(Order order) throws OrderValidationException {
if (order.getClient() == null ||
order.getClient().getName() == null ||
order.getClient().getName().isBlank()) {
throw new OrderValidationException("ΠΠΎΠ»Π΅ ΠΊΠ»ΠΈΠ΅Π½Ρ Π½Π΅ Π·Π°ΠΏΠΎΠ»Π½Π΅Π½ΠΎ.");
}
}
}
ΠΠ°Π»ΠΈΠ΄Π°ΡΠΈΡ Π²ΡΠ½Π΅ΡΠ΅Π½Π° Π² ΠΎΡΠ΄Π΅Π»ΡΠ½ΡΠΉ ΠΊΠ»Π°ΡΡ.
ΠΡΠΊΠ»ΡΡΠ΅Π½ΠΈΡ ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°ΡΡΡΡ Ρ Π»ΠΎΠ³ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ.
@Transactional
ΠΏΡΠΈΠΌΠ΅Π½ΡΠ΅ΡΡΡ Π½Π° ΠΏΡΠ±Π»ΠΈΡΠ½ΡΠΉ ΠΌΠ΅ΡΠΎΠ΄, ΡΡΠΎΠ±Ρ AOP-ΠΏΡΠΎΠΊΡΠΈ ΡΡΠ°Π±ΠΎΡΠ°Π».auditRepository.save(order)
Π²ΡΠΏΠΎΠ»Π½ΡΠ΅ΡΡΡ ΠΏΠΎΡΠ»Π΅ ΡΡΠΏΠ΅ΡΠ½ΠΎΠ³ΠΎ ΡΠΎΡ ΡΠ°Π½Π΅Π½ΠΈΡ Π·Π°ΠΊΠ°Π·Π°.