22.01.2018, 08:54 | #21 |
Участник
|
Цитата:
Цитата:
P.S. Ой, извините, я - EVGL - по ошибке отредактировал ваш текст. Надо отнять у меня права модератора, что-ли?
P.S. Может быть вынесем это обсуждение в отдельную тему? Потому, что к данной теме оно относится ОЧЕНЬ косвенно. |
|
22.01.2018, 17:52 | #22 |
Участник
|
Кстати да, не в обиду, но хорошее замечание. т.е. нарушается одно из правил кодеревью что код не должен быть персонализирован(а так в АХ больше никто не пишет)
читать такой код на мой взгляд сложно(непонятно на каком классе вызывается методы), да и отлаживать подозреваю тоже как вообще такое пропускают |
|
23.01.2018, 09:04 | #23 |
Участник
|
За несколько лет никто не жаловался именно на это. Это не фирменный стиль belugin это FluentInterface - распространенный прием в языках, где нет property и collection initializers (например в java, с которой слизали X++).
Их не надо отлаживать особо - там никакой логики нет, только передача параметров. BTW у отладчика в VS гораздо больше возможностей, чем то, к чему мы привыкли на предыдущих версиях AX (step into specific, tracepoints, conditional breakpoints, etc) если вдруг кто-то не знает что-то из этого, рекомендую почитать доку. |
|
|
За это сообщение автора поблагодарили: Link (5). |
23.01.2018, 19:22 | #24 |
Banned
|
Цитата:
Сообщение от belugin
За несколько лет никто не жаловался именно на это. Это не фирменный стиль belugin это FluentInterface - распространенный прием в языках, где нет property и collection initializers (например в java, с которой слизали X++).
Их не надо отлаживать особо - там никакой логики нет, только передача параметров. BTW у отладчика в VS гораздо больше возможностей, чем то, к чему мы привыкли на предыдущих версиях AX (step into specific, tracepoints, conditional breakpoints, etc) если вдруг кто-то не знает что-то из этого, рекомендую почитать доку. X++: c1.FirstName("vinod").LastName("srivastav").Sex("male").Address("bangalore").Print(); А по теме, раз отчет то делайте временную таблицу и забудьте о нюансах join, делайте максимально тупо. Вот на форме, да стоит думать, но для отчета нет смысла. Для отчета нужна гибкость, а это временная таблица. |
|
|
За это сообщение автора поблагодарили: S.Kuskov (5). |
23.01.2018, 20:56 | #25 |
Участник
|
Цитата:
Цитата:
И категорически запрещать. Каждый раз проклинаю. И ни разу не порадовался.
Цитата:
А по теме, раз отчет то делайте временную таблицу и забудьте о нюансах join, делайте максимально тупо.
|
|
23.01.2018, 22:50 | #26 |
Banned
|
Цитата:
Сам каждый раз поражаюсь требованиям и ситуациям. Возможность дебажить и расширять. Вот что нужно "прикладному" программисту. Экономия на переменных и строках, для красоты - это говнокод на самом деле. То есть красиво придавленное но г@вно. Даже инициализацию параметров требуется дебажить и иногда менять. А когда иерархия и все в строку да с запуском в конце то уматываешься проходить по всем параметрам пока до нужного метода доберешься. Часто приходиться переписывать такой код добавляя переменные для удобства дебага. Те же join это примерно такая же "оптимизация" как и сокращенный код. В топку такую оптимизацию. Лучше лишний раз сходить на SQL Server. Не нужно ничего оптимизировать заранее и без реальной на то необходимости. |
|
|
За это сообщение автора поблагодарили: Link (5), Pandasama (1), Stitch_MS (2). |
24.01.2018, 00:34 | #27 |
Британский учённый
|
Коллега конечно излишне эмоционален, но я тоже считаю, что такого кода не должно быть в стандарте. Ну и сам X++ Coding Standards:
General Guidelines
__________________
Людям физического труда для восстановления своих сил нужен 7-8 часовой ночной сон. Людям умственного труда нужно спать часов 9-10. Ну а программистов будить нельзя вообще. |
|
|
За это сообщение автора поблагодарили: skuull (1), Stitch_MS (2), Vadik (1), AlGol (3). |
24.01.2018, 19:02 | #28 |
Участник
|
Про возможность дебажить я согласен, что она меньше. На практике жалоб от коллег, что это сильно мешает не слышал (может слышал, но забыл) но это не тот вопрос, которые регулярно всплывает.
У нас не очень много такого кода в production но много такого в тестах. Учтите, что в AX7 можно просто провалиться по F12 в метод и поставить breakpoint уже там. К сожалению, в X++ (в отличие от C#) не работает "step into specific" и бряки по имени функции. Собственно те же проблемы возникают при отладке вызова с несколькими аргументами, только там нет имен параметров. Про возможность расширять, я не очень понял. EVGL сказал, нашел две проблемы: 1. private методы 2. создание запроса не выделено в отдельный метод По-моему, это ортогонально стилю заполнения параметров. Цитата:
Вот что нужно "прикладному" программисту.
Экономия на переменных и строках, для красоты - это говнокод на самом деле. То есть красиво придавленное но г@вно. Цитата:
Даже инициализацию параметров требуется дебажить и иногда менять. А когда иерархия и все в строку
Цитата:
да с запуском в конце то уматываешься проходить по всем параметрам пока до нужного метода доберешься. Часто приходиться переписывать такой код добавляя переменные для удобства дебага.
Цитата:
Те же join это примерно такая же "оптимизация" как и сокращенный код. В топку такую оптимизацию.
Лучше лишний раз сходить на SQL Server. Не нужно ничего оптимизировать заранее и без реальной на то необходимости. |
|
24.01.2018, 19:17 | #29 |
Участник
|
Цитата:
Цитата:
Only one statement per line.
Цитата:
Break up complex expressions that are more than one line - make it visually clear.
Цитата:
Use a single blank line to separate entities.
|
|
24.01.2018, 23:38 | #30 |
Banned
|
Цитата:
Цитата:
(class InventAvailabilityByUnit, AX2012R3) Бодрый Java стиль который не плох сам по себе но неуместен в AX. Параметр.Параметр.Метод. КрасивоЖ! Читать легко. Дак то ж его читает то? Дебажат его, а не читают. X++: /// <summary> /// Gets the the quantity available for physical reservation. /// </summary> /// <returns> /// The quantity in the inventory and catch weight units. /// </returns> public PmfQtyDataCarrier availPhysical() { PmfQtyDataCarrier result = new PmfQtyDataCarrier(); result.parmCwQty(this.parmPdsCWInventAvailability().pdsCWAvailPhysical()); result.parmInventQty(this.parmInventAvailability().availPhysical()); return result; } Но такая вот инициализация это зуд программиста писать изящно. И не только private делает больно но и сокращение кода. На тот же level вообще не повлиять никак. Согласен что не в точках дело, но там где программисту хочется в одну строку то отдельный метод для определения level он точно писать не будет. Как бы симптом болезни. (class WHSInventReserveQtyCalculator, AX2012R3) X++: private void initializeCalculations() { InventUpdateOnhand inventUpdateOnhand; if (!needsInitializeCalculations) { return; } inventUpdateOnhand = appl.inventUpdateOnhandGlobal().inventUpdateOnhand(); productDimensions = EcoResProductDimGroupSetup::newInventTable(inventTable); includeDelta = inventUpdateOnhand.mustAddInventSumDeltaOnhand(inventTable.ItemId); ttsId = inventUpdateOnhand.ttsId(); level = WHSReservationHierarchyInventDimUtil::deepestLevelFromInventDimParm( WHSReservationHierarchyProvider::construct() .getDimListAllFromInventTable(inventTable, WHSReservationHierarchySortOrder::BottomUp), requestedInventDimParm); optimizedInventDimParm = this.calculateOptimizedInventDimParm(inventDimCriteria, requestedInventDimParm); needsInitializeCalculations = false; } In software engineering, a fluent interface (as first coined by Eric Evans and Martin Fowler) is a method for constructing object oriented APIs, where the readability of the source code is close to that of ordinary written prose. Проза блин Цитата:
Совсем не факт что эти 200000 раз будут дольше чем join. Вот когда будет 200000 тогда и надо думать о join но не раньше. Вот пример. И кому такое надо? Оно типа быстрое? Сомнительно, просто читать удобнее, прямо как прозу (class PdsRebateFindAndCreate.findPdsRebateAgreementAndCreateClaim, AX2012R3) X++: //Find all applicable Rebate Agreements. while select validTimeState(dateMin, dateMax) pdsRebateAgreement where (pdsRebateAgreement.PdsCustRebateCode == TableGroupAll::All || (pdsRebateAgreement.PdsCustRebateCode == TableGroupAll::GroupId && pdsRebateAgreement.PdsRebateProgramType == PdsRebateProgramType::Rebate && pdsRebateAgreement.PdsCustRebateRelation == pdsRebateCustInvoiceTrans.SalesTablePdsCustRebateGroupId) || (pdsRebateAgreement.PdsCustRebateCode == TableGroupAll::GroupId && pdsRebateAgreement.PdsRebateProgramType == PdsRebateProgramType::Freight && pdsRebateAgreement.PdsCustRebateRelation == custTable.PartyCountry) || (pdsRebateAgreement.PdsCustRebateCode == TableGroupAll::GroupId && pdsRebateAgreement.PdsRebateProgramType == PdsRebateProgramType::TMA && pdsRebateAgreement.PdsCustRebateRelation == pdsRebateCustInvoiceTrans.SalesTablePdsRebateProgramTMAGroup) || (pdsRebateAgreement.PdsCustRebateCode == TableGroupAll::Table && pdsRebateAgreement.PdsCustRebateRelation == custTable.AccountNum)) && (pdsRebateAgreement.PdsItemRebateCode == PdsRebateItemCode::All || ((pdsRebateAgreement.PdsRebateProgramType == PdsRebateProgramType::Rebate || pdsRebateAgreement.PdsRebateProgramType == PdsRebateProgramType::TMA) && pdsRebateAgreement.PdsItemRebateCode == PdsRebateItemCode::GroupId && pdsRebateAgreement.PdsItemRebateRelation == pdsRebateCustInvoiceTrans.SalesLinePdsItemRebateGroupId) || (pdsRebateAgreement.PdsRebateProgramType == PdsRebateProgramType::Freight && pdsRebateAgreement.PdsItemRebateCode == PdsRebateItemCode::GroupId && pdsRebateAgreement.PdsItemRebateRelation == inventTable.PdsFreightAllocationGroupId) || (pdsRebateAgreement.PdsItemRebateCode == PdsRebateItemCode::Table && pdsRebateAgreement.PdsItemRebateRelation == custInvoiceTrans.ItemId) || pdsRebateAgreement.PdsItemRebateCode == PdsRebateItemCode::Selection) && ((pdsRebateAgreement.RebateCalcDateType == PdsRebateCalcDateType::CreatedDate && (!pdsRebateAgreement.ValidFrom || pdsRebateAgreement.ValidFrom <= pdsRebateCustInvoiceTrans.SalesLineCreatedDate) && (!pdsRebateAgreement.ValidTo || pdsRebateAgreement.ValidTo >= pdsRebateCustInvoiceTrans.SalesLineCreatedDate)) || (pdsRebateAgreement.RebateCalcDateType == PdsRebateCalcDateType::RequestedReceiptDate && (!pdsRebateAgreement.ValidFrom || pdsRebateAgreement.ValidFrom <= pdsRebateCustInvoiceTrans.SalesLineReceiptDateRequested) && (!pdsRebateAgreement.ValidTo || pdsRebateAgreement.ValidTo >= pdsRebateCustInvoiceTrans.SalesLineReceiptDateRequested)) || (pdsRebateAgreement.RebateCalcDateType == PdsRebateCalcDateType::RequestedShipDate && (!pdsRebateAgreement.ValidFrom || pdsRebateAgreement.ValidFrom <= pdsRebateCustInvoiceTrans.SalesLineShippingDateRequested) && (!pdsRebateAgreement.ValidTo || pdsRebateAgreement.ValidTo >= pdsRebateCustInvoiceTrans.SalesLineShippingDateRequested))) && (pdsRebateAgreement.RebateGenericCurrency == NoYes::Yes || pdsRebateAgreement.RebateCurrency == custInvoiceTrans.CurrencyCode) && (pdsRebateAgreement.RebateUOMOption == PdsRebateUOMOption::Convert || (pdsRebateAgreement.PdsUnitType == PdsUnitType::InventoryUnit && pdsRebateAgreement.PdsRebateUnit == custInvoiceTrans.SalesUnit) || (pdsRebateAgreement.PdsUnitType == PdsUnitType::CWUnit && pdsRebateAgreement.PdsRebateUnit == custInvoiceTrans.pdsCWUnitId())) && pdsRebateAgreement.Validated && pdsRebateAgreement.Verifier #FreightAccruedCondition(custTable.PdsFreightAccrued) #CatchWeightCondition(custInvoiceTrans.ItemId) #TAMRebateInventDimExistsJoin(pdsRebateAgreement.InventDimId, inventDim, custInvoiceTransInventDim) #JoinPdsRebate #NotExistRebateTable(pdsRebateAgreement, custInvoiceTrans) При этом необходимость join крайне сомнительна. 2 while select или join? Не говоря уже о об услових выборки в самом SQL. А для отчета важнее правдивость и гибкость, пусть хоть 1000000 раз в базу лезть чем мучить join который если не очевиден, то и не нафиг не нужен. Последний раз редактировалось ax_mct; 24.01.2018 в 23:53. Причина: Зы |
|
25.01.2018, 09:07 | #31 |
Участник
|
Цитата:
Цитата:
Цитата:
Совсем не факт что эти 200000 раз будут дольше чем join.
Вот когда будет 200000 тогда и надо думать о join но не раньше. |
|
|
За это сообщение автора поблагодарили: ax_mct (3). |