AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 08.08.2021, 14:02   #1  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
[CodeStyle] check* vs validate* методы. в чем разница в X++? какой будет выводить в инфолог?
любая версия аксапты.
Вопрос относится к стилю кодирования и к вашим предпочтениям.
Вопрос и ответы не обязывают никого ничем.

Внимание! для других языков есть свои требования и рекомендации для check* и validate* методов. В этой ветке вопрос про X++. Обсуждения других языков допускаются, но хотелось бы услышать именно про X++.

в аксапте используются check- и validate- методы.
например,
  • RunBase.validate
  • Table.validate
  • AfDataContainer::validateDataItemValue
  • AifAdapterManager.validateAdapterClass
  • Book_RU.validateDelete
  • Global::checkFailed
  • Global::checkSign
  • Global::checkTime
  • AifSendService.checkAdapterAndChannel
  • CreditCard.checkExpireDate
  • FormLetter.checkLedgerPeriod
  • и так далее

как видим, check- и validate- методы могут быть
методами объекта, могут быть статическими,
могут выводить сообщения в инфолог, могут не выводить,
могут бросать исключения, могут не бросать
могут даже создавать диалоговые окна для взаимодействия с пользователями

Вопрос:
есть ли для вас разница между check- и validate- методами в X++?
ожидаете ли вы какие-либо различия в поведении этих методов?
а должны быть на ваш взгляд?
__________________
полезное на axForum, github, vk, coub.
Старый 08.08.2021, 14:43   #2  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,308 / 3540 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Поскольку вопрос чисто предпочтений, то я (лично для себя) выработал следующие правила (при условии, что нет правил, установленных используемыми фреймворками):
Методы check* отвечают за одну проверку.
Методы validate* отвечают за комплекс проверок (т.е. грубо говоря состоят из вызовов методов check*).
При этом комплексов может быть много и они могут состоять из разного набора проверок (аналог привилегий и Duty в 2012).
Я люблю делать проверочные методы методами объекта (а не статическими), чтобы иметь возможность обращаться к глобальным переменных классам или внутренним private-методам
Сообщения, исключения, диалоговые окна - это все регулируется параметрами методов в зависимости от потребности (например, иногда вместо инфолога надо писать в таблицу текст ошибки).

Ну и собственно все.
Пример (абстрактный).
Хочу написать алгоритм разноски для своей условной заявки на покупку. Разноска генерит проводку в ГК и приходную проводку в InventTrans.
У меня будет:
1) проверка на открытость периода в ГК
2) проверка на открытость периода по складу (ValueOpen = Да)
3) проверка на наличие товара по необходимым аналитикам
4) проверка на наличие бюджета
... какие-то другие проверки.

По бизнесу (к примеру) сначала выполняется проверка на наличие товара. Если он есть, то закупка не выполняется.
Если товара нет, то выполняется проверка на наличие бюджета. После успешной проверки бюджета - выполняется разноска по складу и ГК.

Я хочу сделать (условно) 4 метода check*, которые в свою очередь будут вызываться в разное время, причем они также могут быть вызваны пользователем по кнопке "Проверить" или "Предварительный просмотр проводок".
При этом у меня будут методы validate*, которые будут вызывать эти методы check*:
1) validate на этапе проверки наличия товара
2) validate на этапе проверки бюджета
3) validate на этапе разноски

Соответственно - наполнение этих validate-методов может быть разным, при этом, к примеру, проверку на открытость периода я могу вызывать в каждом validate-методе, но сама логика проверки у меня будет в едином методе check
__________________
Возможно сделать все. Вопрос времени

Последний раз редактировалось sukhanchik; 08.08.2021 в 14:46.
За это сообщение автора поблагодарили: mazzy (5), NetBus (3), dech (5).
Старый 08.08.2021, 15:15   #3  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
О, интересный подход.

А у тебя check-методы могут вызываться не из validate?
И что насчет инфолога? ты допускаешь, что все они могут что-то выводить в инфолог?

и что насчет диалога с пользователем? Ну, этот пресловутый Book_RU.validateDelete?
__________________
полезное на axForum, github, vk, coub.
Старый 08.08.2021, 19:50   #4  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,308 / 3540 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от mazzy Посмотреть сообщение
А у тебя check-методы могут вызываться не из validate?
Конечно. Я же привел пример наличия кнопки "Проверка". validate - это некое событие в алгоритме, по результатам которого отрабатывает основной код (например, разноска).

Цитата:
Сообщение от mazzy Посмотреть сообщение
И что насчет инфолога? ты допускаешь, что все они могут что-то выводить в инфолог?
Я бы даже настаивал, чтобы любая проверка выводила какое-то осмысленное сообщение куда-нибудь (инфолог или какая-то таблица для пакетных заданий). Иначе пользователю совершенно неясно, из-за какой конкретно проверки не выполнилась какая-то операция.

Цитата:
Сообщение от mazzy Посмотреть сообщение
и что насчет диалога с пользователем? Ну, этот пресловутый Book_RU.validateDelete?
Здесь у меня однозначный подход - все проверки должны выполняться до начала транзакции и все диалоги с пользователем должны быть выполнены с помощью стандартных форм системы, после чего в алгоритм должен быть передан ответ пользователя (в виде отдельного параметра). Опять-таки, оговорюсь, что все это не касается уже существующего фреймворка, т.е. даже если я не согласен с построением кода в Book_RU.validateDelete я не кидаюсь его переписывать, а пытаюсь построить код "в стиле", который был заложен его разработчиками. Но как только я ухожу от уже существующего кода - то я уже могу освободиться от этих "кандалов" в виде ранее написанного кода (и это необязательно касается стандартного кода - это касается любого кода, с которым мне приходится знакомиться).

Вообще - тут сложно вырабатывать какие-то правила - слишком сильно реализация зависит не только от бизнес-задачи, но и от места выполнения проверки.

Пример 1. Разноска товарного расхода. Проверка необходимого в наличии количества выполняется до резервирования, но если резервирование уже прошло, то нет смысла проверять необходимое количество в наличии - оно гарантированно будет - в этом смысл резервирования.

Пример 2 (AX2012). Проверка достаточности бюджетных средств. Если не используется функционал резервирования бюджета (который привязывает резерв к документу) и разносимый документ не указан в настройках контроля бюджета, то по сути бюджет может "пропасть" в любой момент, а значит его есть смысл регулярно проверять.

Пример 3. Аналог примера 2, только речь идет про проверку на закрытость периода. Конечно период могут закрыть в любой момент, но все же нет смысла проверять закрытость периода условно при любом изменении нашей "заявки на покупку", потому что это для пользователя не столь важно, как, к примеру, неожиданная "потеря" бюджета.

Я намеренно остаюсь в приведенных ранее мною примерах проверок, чтобы не распыляться.

В общем - общая идея такова, что в некотором алгоритме всегда есть проверки, которые можно выполнять на любом этапе алгоритма, а есть проверки, которые есть смысл выполнять только на определенных этапах. Но в любом случае - мне нравится идея выделять всевозможные проверки в методы с префиксом check*, а уже вызывать из методов validate* только те проверки, которые необходимо выполнить именно в данном validate*. Я также понимаю, что одна и та же проверка может быть вызвана как программно несколько раз (из нескольких validate*), так и условно вручную по нажатию специальной кнопки.
__________________
Возможно сделать все. Вопрос времени

Последний раз редактировалось sukhanchik; 08.08.2021 в 19:59.
Старый 09.08.2021, 09:44   #5  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
647 / 350 (13) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
У меня дополнительный вопрос по поводу исключений.
Кто как пользуется методами validate*? Стоит ли в этих методах вызывать исключения? или они только должны возвращать булевый тип и всё?
В принципе к check-методам в этом плане я довольно категоричен и использовать здесь исключения себе не позволяю.
Однако, что касается validate*, то здесь напрашиваются два шаблона. По факту приходится использовать оба. Первый - возвращает булевый тип и пишет в инфолог неудачные проверки обычно с помощью checkFailed или других check-методов.
Например:
X++:
if (custTable.validateWrite())
{
    custTable.insert();
}
Второй шаблон относится к вызывающим исключение. Возвращаемого значения обычно нет.
Пример:
X++:
public static void validateAdapterClass(classId integrationAdapterClassId)
{
    AifIntegrationAdapter integrationAdapter = AifAdapterManager::getIntegrationAdapter(integrationAdapterClassId);

    if (AifAdapter::exist(integrationAdapterClassId))
        throw error(strfmt("@SYS95137", classId2Name(integrationAdapterClassId)));
}
__________________
// no comments
Старый 09.08.2021, 12:59   #6  
Raven Melancholic is offline
Raven Melancholic
Участник
Аватар для Raven Melancholic
Самостоятельные клиенты AX
Лучший по профессии 2015
 
2,164 / 1293 (48) ++++++++
Регистрация: 21.03.2005
Адрес: Москва-Петушки
Цитата:
Сообщение от dech Посмотреть сообщение
У меня дополнительный вопрос по поводу исключений...
Это уже обсуждается в теме [CodeStyle] методы *noThrow vs *OrThrow vs optional parameter?
За это сообщение автора поблагодарили: dech (2).
Старый 09.08.2021, 13:06   #7  
Raven Melancholic is offline
Raven Melancholic
Участник
Аватар для Raven Melancholic
Самостоятельные клиенты AX
Лучший по профессии 2015
 
2,164 / 1293 (48) ++++++++
Регистрация: 21.03.2005
Адрес: Москва-Петушки
У нас подход практически идентичен тому, который описывает sukhanchik
check* методы проверяют конкретные небольшие бизнес-правила, а validate проверяют процессы. При этом validate вызывают check*.
Сами check, как правило, выводят сообщения при отклонениях от допустимых значений. Но, часто в check* есть параметр для работы "втихую" - используется когда проверка бизнес-правила и, например, доступности кнопок в интерфейсе близкая и может использоваться и для "засеривания" кнопок и для проверки при выполнении.
Ну а для случаев, когда не нужны сообщения, предпочитаем называть методы не check*, а как-то по другому - is*, has* и т. п.
Естественно, check* не обязательно вызываются из validate*.
За это сообщение автора поблагодарили: sukhanchik (4), NetBus (3).
Старый 09.08.2021, 17:48   #8  
dech is offline
dech
Участник
Аватар для dech
Самостоятельные клиенты AX
 
647 / 350 (13) ++++++
Регистрация: 25.06.2009
Адрес: Омск
Записей в блоге: 3
Цитата:
Сообщение от Raven Melancholic Посмотреть сообщение
Это уже обсуждается в теме [CodeStyle] методы *noThrow vs *OrThrow vs optional parameter?
Спасибо за инфо. Просто давно не заходил, а топик вниз опустился, не заметил.
__________________
// no comments
Старый 10.08.2021, 08:57   #9  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,308 / 3540 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от Raven Melancholic Посмотреть сообщение
Ну а для случаев, когда не нужны сообщения, предпочитаем называть методы не check*, а как-то по другому - is*, has* и т. п.
Я бы еще дополнительно классифицировал проверки на пользовательские (т.е. те, которые понятны пользователю и сообщение о проверке необходимо пользователю для дальнейших его действий) и все остальные.
Отсюда вывод, что в методах check* всегда должно быть какое-то осмысленное для пользователя сообщение об ошибке.

Например, проверка на закрытость периода, наличие товара / бюджета - пользовательские. А проверка на наличие записи в таблице - не пользовательская.

Соответственно, в методы check* я бы убрал пользовательские проверки, а в методы is*, has* - непользовательские.
При этом надо понимать, что одна и та же проверка может быть одновременно пользовательской и не пользовательской в зависимости от задачи.

Например, я хочу сделать недоступным поле "Группа номенклатурных моделей", если есть проводки по номенклатуре. В этом случае проверка на наличие проводок будет непользовательской (метод hasInventTrans)
Но я могу захотеть не делать недоступным поле, а выдать ошибку при попытке его изменения, если уже есть проводки. В этом случае проверка будет пользовательской (метод checkExistsInventTrans) с осмысленной ошибкой "По данной номенклатуре уже есть движения".

При этом мне никто не запрещает метод checkExistsInventTrans сделать просто оберткой метода hasInventTrans, но с дополнительным выводом сообщения.

Опять-таки - это все красиво и замечательно, пока есть время и возможность "сделать по феншую". Когда сроки уже начинают поджимать или закрываешь какую-то горящую проблему "по-быстрому" то "феншуй" нередко откладывается в сторону, особенно, если его детали приходится вспоминать.
__________________
Возможно сделать все. Вопрос времени
Старый 10.08.2021, 09:43   #10  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,437 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Цитата:
Сообщение от sukhanchik Посмотреть сообщение
При этом надо понимать, что одна и та же проверка может быть одновременно пользовательской и не пользовательской в зависимости от задачи.
А я бы делал такое деление за счёт распределения соответствующих методов по разным классам. Отдельный класс, который отвечает за бизнес-логику, и отдельный класс который отвечает за взаимодействие с пользователем, который в случае чего дёргает методы первого класса.

Если класс перегружен методами, то как ты их не называй понять логику будет сложно. У класса должна быть ограниченная зона ответственности и тогда будет меньше проблем с именованием методов. Конечно это полностью не отменяет задачу правильного именования методов, но за счёт более узкого контекста, задаваемого классом, делает эту задачу менее критичной
За это сообщение автора поблагодарили: sukhanchik (4).
Старый 10.08.2021, 17:00   #11  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,308 / 3540 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от S.Kuskov Посмотреть сообщение
А я бы делал такое деление за счёт распределения соответствующих методов по разным классам. Отдельный класс, который отвечает за бизнес-логику, и отдельный класс который отвечает за взаимодействие с пользователем, который в случае чего дёргает методы первого класса.
Хорошее замечание, спасибо. Тут все очень сильно зависит от задачи, поэтому мнений может быть много и разных.
Я в качестве примера приводил операцию разноски, которая заведомо предполагает выполнение большого количества проверок перед выполнением алгоритма. В этом примере класс, отвечающий за взаимодействие с пользователем будет минимален, потому что как такового взаимодействия нет (кнопку нажали и процесс пошел).

Если в качестве примера приводить допустим операцию закрытия склада / расчета сводного плана, то да, действительно до запуска процедуры может быть куча параметров в диалоге и действительно будет актуальной задача по обработке взаимодействия с пользователем.

Но в целом - я также считаю, что логику взаимодействия с пользователем нужно отделять от внутренней логики, чтобы была возможность программно запустить обработку внутренней логики отбросив логику взаимодействия с пользователем (условно - программно передать процедуре закрытия склада все необходимые параметры и программно ее запустить, не связываясь с обработчиком параметров в диалоге)
__________________
Возможно сделать все. Вопрос времени
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
[CodeStyle] методы *noThrow vs *OrThrow vs optional parameter? mazzy DAX: Программирование 27 03.08.2021 00:30
emeadaxsupport: Dynamics AX 2012 Prerequisite Check Utility and SQL Server cluster Blog bot DAX Blogs 0 20.03.2012 19:11
axaptapedia: Validate field values on form Blog bot DAX Blogs 0 17.12.2008 12:05

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 01:42.