> Почему нельзя было в момент сдачи платежки сразу прописывать текущий курс и передавать дальше (Go)
Уровень: middle · Роль: backend · Категория: Технические вопросы
Компании: Автомакон
Стек: Go
> Пример ответа
Короткий ответ
Потому что курс валют - это изменяемая сущность, а платёж - это факт хозяйственной деятельности, который должен быть зафиксирован один раз и не зависеть от последующих изменений курса. Если прописать курс в момент сдачи платёжки, то при пересчёте, реконсиляции или аудите возникнут расхождения: курс на момент создания документа, на момент списания и на момент зачисления может отличаться. Кроме того, платёжка может быть отклонена, отозвана или изменена, и тогда зафиксированный курс станет некорректным. Правильный подход - хранить сумму в валюте, а курс вычислять на момент исполнения операции или фиксировать отдельным справочником курсов с датой.
Подробное объяснение
Основная проблема - семантика времени. Платёжка проходит несколько стадий: создание, валидация, отправка в банк, списание, зачисление. Курс валюты меняется между этими стадиями. Если зафиксировать курс при создании, то:
- при списании банк использует свой курс, который может отличаться;
- при зачислении на счёт получателя курс может быть уже другим;
- при возврате или частичном исполнении платёжки зафиксированный курс становится нерелевантным.
Второй аспект - консистентность данных. Если курс хранится в платёжке, то для аналитики и отчётности придётся делать join по дате и валюте, но при этом курс уже "зашит" в документ. Это приводит к дублированию данных и риску рассинхронизации: курс в платёжке может отличаться от курса в справочнике за ту же дату.
Третий аспект - бухгалтерский учёт. В финансовых системах принято хранить сумму в валюте операции, а рублёвый эквивалент вычислять по курсу ЦБ или внутреннему курсу на дату операции. Это стандарт, который позволяет корректно отражать курсовые разницы и переоценку остатков.
Четвёртый аспект - гибкость. Если курс фиксируется в момент сдачи, то нельзя пересчитать платёжку при изменении условий (например, при частичной оплате или изменении даты исполнения). Лучше хранить курс в отдельной таблице курсов с датой и валютой, а в платёжке ссылаться на дату операции.
На практике
В реальных системах (банковские API, платёжные шлюзы, ERP) используется подход:
- платёжка хранит сумму в исходной валюте и валюту;
- курс берётся из справочника курсов на дату операции (или на дату списания);
- если требуется зафиксировать курс для клиента (например, при предоплате), то это делается отдельным механизмом - "блокировкой курса" на срок, но это уже отдельная бизнес-сущность, а не поле в платёжке.
Пример из практики: при интеграции с банком, банк возвращает в ответе на платёжку свой курс и сумму в рублях. Эти данные сохраняются в отдельном поле "фактический курс" уже после исполнения, а не на этапе создания.
Пример кода
GOtype Payment struct {ID stringAmount decimal.Decimal // сумма в валютеCurrency stringCreatedAt time.TimeExecutedAt *time.TimeRate *decimal.Decimal // заполняется после исполнения}type RateService struct {rates map[string]map[time.Time]decimal.Decimal // currency -> date -> rate}func (s *RateService) GetRate(currency string, date time.Time) (decimal.Decimal, error) {// берём курс на дату, а не на момент созданияif rates, ok := s.rates[currency]; ok {if rate, ok := rates[date.Truncate(24*time.Hour)]; ok {return rate, nil}}return decimal.Zero, fmt.Errorf("rate not found for %s on %s", currency, date)}func (s *RateService) ExecutePayment(p *Payment) error {rate, err := s.GetRate(p.Currency, time.Now())if err != nil {return err}p.Rate = &ratenow := time.Now()p.ExecutedAt = &nowreturn nil}
Как отвечать на собеседовании
Начни с того, что курс - это динамическая величина, а платёж - это документ с жизненным циклом. Затем перечисли проблемы: расхождение курсов на разных этапах, проблемы с пересчётом, бухгалтерские требования, риск некорректных данных при изменении статуса платёжки. Подчеркни, что правильный подход - хранить валюту и сумму, а курс вычислять на дату операции или хранить в отдельном справочнике. Если спросят про "блокировку курса" - скажи, что это отдельный механизм, который используется в e-commerce и требует отдельной сущности с сроком действия.
Что проверяет интервьюер
- понимание жизненного цикла финансового документа;
- знание принципов хранения валютных операций;
- умение видеть проблемы консистентности данных;
- понимание разницы между моментом создания и моментом исполнения;
- способность аргументировать архитектурное решение.
Типичные ошибки
- утверждение, что курс можно хранить в платёжке, если "он не меняется в течение дня" - это не гарантия, а допущение;
- смешивание понятий "курс на дату" и "курс на момент создания";
- предложение хранить курс в платёжке и пересчитывать при изменении - это создаёт лишнюю сложность и риск ошибок;
- игнорирование бухгалтерских требований и стандартов учёта;
- отсутствие упоминания о том, что банк может вернуть свой курс в ответе - это важный практический момент.
> Похожие задачи по backend
Как пришли в Go
Где и как применялась Kafka
Что значит исключить проскальзывание цены и как это реализовать
За счет чего достигается параллелизм и кооперативность в Go
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью