Практические рекомендации по Interactor
Один основной интерфейс на тип процесса
Перед созданием интерфейса найдите существующие @ProcessInteractorReference с нужным typeIds. Два независимых интерфейса для одного типа процесса быстро расходятся по параметрам, сообщениям и правилам кеширования.
Основной интерфейс собирайте из небольших аспектов:
-
With*— связанные сущности или отдельная возможность:WithSingleCustomer,WithProcessType; -
Has*— обязательная или характерная группа параметров:HasSingleAddress; -
CanBe*— допустимый переход состояния:CanBeClosed.
interface HasInstallationAddress : ProcessInteractor {
@BindAddressParam(PROCESS_PARAMETER_ADDRESS_ID)
@NotNull(message = "В процессе #objectId не указан адрес")
fun getAddress(): ParameterAddressValue
@BindAddressParam(PROCESS_PARAMETER_ADDRESS_ID)
fun getAddressOrNull(): ParameterAddressValue?
@BindAddressParam(PROCESS_PARAMETER_ADDRESS_ID)
@DropCache
fun setAddress(value: ParameterAddressValue?)
}
Разделяйте обязательное и необязательное чтение
Если отсутствие значения допустимо не всегда, предоставьте два явно названных метода: nullable-метод без валидации и обязательный метод с бизнес-сообщением.
@BindProcessLinkedCustomers
fun getCustomerOrNull(): Customer?
@BindProcessLinkedCustomers
@NotNull(message = "К процессу #objectId не привязан контрагент")
fun getCustomer(): Customer
Для одиночной связи добавляйте @Size(max = 1), иначе обработчик вернёт первый элемент и скроет некорректную множественную привязку.
Кешируйте только в пределах короткой операции
@EnableCache хранит значения в памяти proxy и не знает об изменениях вне него. Не сохраняйте proxy надолго и не рассматривайте его как актуальную модель сущности.
На интерфейсе с кешированием помечайте @DropCache все setters и операции add, remove, clear, смену статуса и любые косвенные изменения. Сброс происходит до изменения и очищает весь кеш экземпляра.
Если операция может завершиться ошибкой после сброса, кеш всё равно останется пустым — это безопаснее, чем сохранить устаревшие значения.
Используйте сигнатуру как часть контракта
Обработчик выбирает действие не только по аннотации, но и по типам и имени метода. Придерживайтесь глаголов get, set, add/plus, remove/delete, clear, а специальные проверки называйте по правилам конкретного обработчика (can…, isClosed…, new…).
Не добавляйте две @Bind*-аннотации на один метод: фабрика выбирает первое совпадение из своей таблицы, и результат станет зависеть от порядка регистрации.
Не скрывайте внешние вызовы
BindProcessTmcMoves и BindTmcUserLeftovers обращаются в Verdandi, а параметрические и процессные обработчики могут обращаться к БД через сервисы. Название бизнес-метода должно показывать, что данные загружаются, а вызывающий код должен учитывать ошибки интеграции и стоимость повторных вызовов.