Java: ревью сервиса бронирования мест SeatBookingService

В представленном коде есть несколько ошибок и потенциальных проблем:

Короткий ответ

Что ответить на собеседовании

В представленном коде есть несколько ошибок и потенциальных проблем:

Подробный разбор

Ответ с пояснениями

Условие

Прочитайте код и подсветите ошибки

/**

  • Клиент с купленным билетом может за дополнительную плату выбрать конкретное место.

  • Базовая цена мест определяется тарифами (внешним сервисом).

  • Для клиентов с определенными тарифами (PREMIUM, ULTRA) необходимо сделать скидку при оплате.

  • При бронировании клиенту выставляется инвойс на оплату. Управление оплатой осуществляется в стороннем сервисе. */ @Service public class SeatBookingService {

    @Autowired private SeatBookingRepository seatBookingRepository; @Autowired private TicketRepository ticketRepository; @Autowired private TariffClient tariffClient; @Autowired private CustomerClient customerClient; @Autowired private PaymentClient paymentClient;

    /**

    • Бронирование.

    • @param seatCode код места (например 19А)

    • @param ticketId ид билета */ @Transactional public void bookSeat(String seatCode, UUID ticketId) { var ticket = ticketRepository.findById(ticketId); //бронируем var seatBooking = new SeatBooking(seatCode, ticket.get().getFlightId(), ticketId, BookingStatus.BOOKED); seatBookingRepository.save(seatBooking);

      //ищем базовый тариф для выбранного места в самолете var basePrice = tariffClient.getBasePrice(ticket.get().getPlaneModel(), seatCode); //ищем данные о клиенте Long userId = (Long) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); var userData = customerClient.getCustomer(userId); System.out.println("Найден пользователь " + userData.getFio() + " номер документа " + userData.getDocument()); var price = basePrice; if (userData.getTariff() == "PREMIUM") { //скидка 50% price = basePrice * 0.5d; } if (userData.getTariff() == "ULTRA") { //скидка 20% price = basePrice * 0.8d; } var invoice = new Invoice(price, ticketId, userId); //выставляем платежку paymentClient.sendInvoice(invoice); System.out.println("Счет выставлен"); }

@Data @Table("seat_booking") public class SeatBooking {

@Column
private String seatCode;
@Column
private UUID flightId;
@Column
private UUID ticketId;
@Column
private BookingStatus status;

}

public enum BookingStatus { BOOKED, PAID; }

Ответ

В представленном коде есть несколько ошибок и потенциальных проблем:

  1. Неправильное сравнение строк: В Java строки нельзя сравнивать через ==, нужно использовать метод .equals(). В коде:

    if (userData.getTariff() == "PREMIUM") {
        //...
    }
    

    нужно заменить на:

    if ("PREMIUM".equals(userData.getTariff())) {
        //...
    }
    

    Аналогично для "ULTRA".

  2. Отсутствие проверки наличия билета: ticketRepository.findById(ticketId) возвращает Optional, но сразу вызывается ticket.get() без проверки, что билет существует. Это может привести к NoSuchElementException. Нужно проверить наличие:

    var ticketOpt = ticketRepository.findById(ticketId);
    if (ticketOpt.isEmpty()) {
        throw new IllegalArgumentException("Ticket not found");
    }
    var ticket = ticketOpt.get();
    
  3. Получение userId из SecurityContext: Приведение getPrincipal() к Long может быть неверным, так как обычно там хранится объект UserDetails или другой тип. Нужно привести к правильному типу или получить ID другим способом.

  4. Отсутствие обработки ошибок внешних сервисов: Вызовы tariffClient.getBasePrice(), customerClient.getCustomer(), paymentClient.sendInvoice() могут выбрасывать исключения или возвращать null, что не обрабатывается.

  5. Отсутствие логирования: Использование System.out.println не рекомендуется в продакшене, лучше использовать логгер.

  6. Отсутствие проверки доступности места: Нет проверки, что место с seatCode свободно для бронирования.

  7. Отсутствие обновления статуса после оплаты: В коде нет логики изменения статуса бронирования с BOOKED на PAID.


Пример исправления сравнения строк:

if ("PREMIUM".equals(userData.getTariff())) {
    price = basePrice * 0.5d;
}
if ("ULTRA".equals(userData.getTariff())) {
    price = basePrice * 0.8d;
}

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее