В коде есть ошибки компиляции, денежной точности и бизнес-логики: const для объектов недопустим, Double ненадёжен для денег, тарифные if пересекаются, а исключение отправки чека скрывается.
Обзор кода в финансовом сервисе
В коде есть ошибки компиляции, денежной точности и бизнес-логики: const для объектов недопустим, Double ненадёжен для денег, тарифные if пересекаются, а исключение отправки чека скрывается.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Вообрази, что ты старший разработчик в финтех‑компании, а младший коллега прислал тебе модуль для проверки. Тебе необходимо выполнить ревью кода.
const val receiptRestClient = ReceiptRestClient()
const val cbrRestClient = CbrRestClient()
@Service
class PaymentService {
@Autowired
private var paymentRepository: PaymentRepository? = null
@Autowired
private lateinit var userRepository: UserRepository
@Transactional
fun doPayment(
amount: Double,
currency: Currency,
recipientId: Long?,
userId: Long
) {
val amountInRub: Double = amount * cbrRestClient.getRates().get(currency.getCode())
val user: User = userRepository.findUserById(userId)!!
val payment: Payment = Payment(amountInRub, user, recipientId)
paymentRepository!!.save(payment)
if (amountInRub < 1000) {
val fee = Fee(amountInRub * 0.015, user)
paymentRepository!!.saveFee(fee)
}
if (amountInRub > 1000) {
val fee = Fee(amountInRub * 0.01, user)
paymentRepository!!.saveFee(fee)
}
if (amountInRub > 5000) {
val fee = Fee(amountInRub * 0.005, user)
paymentRepository!!.saveFee(fee)
}
try {
receiptRestClient.notify(payment)
} catch (t: Throwable) {
// do nothing
}
}
}
Ответ
В коде есть ошибки компиляции, денежной точности и бизнес-логики: const для объектов недопустим, Double ненадёжен для денег, тарифные if пересекаются, а исключение отправки чека скрывается.
Используйте constructor injection и BigDecimal либо целые минимальные денежные единицы с явным округлением. При amountInRub = 1000 комиссия не создаётся, а при сумме > 5000 создаются две комиссии; границы диапазонов сначала согласуйте и выразите одной таблицей правил или when. Проверяйте сумму, валюту, получателя, права пользователя и наличие курса без !!.\n\nВнешний вызов курса не должен неоправданно удерживать DB-транзакцию. Сохраняйте использованный курс и идемпотентный идентификатор платежа. Уведомление о чеке доставляйте через outbox с повтором, не проглатывайте Throwable. Запись строки Payment в БД сама по себе ещё не доказывает успешное движение денег.