Здравствуйте, Tissot, Вы писали:
T>Здравствуйте, gandjustas, Вы писали:
T>>>Валидатор не должен он просто преверяет. CountryCode должен знать тот, что получает валидатор. См. код выше. G>>Разницы нету, можно писать new ZipCodeValidator(Region.CountryCode), проблема останется таже. за время жизни кастомера валидатор может стать ... эээ ... невалидным.
T>Посмотри код, где он создается. Нет необходимости его хранить. Он легковесный.
То есть каждый раз лезть в базу и получать текущий CountryCode из связанной сущности?
G>>Кстати, при наличии CountryCode внутри кастомера невозжножно будет поменять этот самый CountryCode, потому что сразуже станет невалидным ZipCode (ну если у них случано не совпадут правила валидации).
T>Можно, через метод, меняющий CountryCode и Zip.
А если у нас WPF и свойства забайндены на контролы?
Да и слишком сложно для такой простой операции. Надеюсь стало понятно что работать с "невалидными сущностями" проще?
Здравствуйте, Tissot, Вы писали:
T>Здравствуйте, gandjustas, Вы писали:
G>>От них никуда не денешься. Я имел ввиду метод, который вызывает экшены.
T>Они приватные. Они должны протестироваться косвенным образом, через тестирование публичных методов.
Ну тогда понятно.
Здравствуйте, gandjustas, Вы писали:
T>>Посмотри код, где он создается. Нет необходимости его хранить. Он легковесный. G>То есть каждый раз лезть в базу и получать текущий CountryCode из связанной сущности?
Зачем каждый раз? Ты же говорил, что у тебя ленивая загрузка.
G>>>Кстати, при наличии CountryCode внутри кастомера невозжножно будет поменять этот самый CountryCode, потому что сразуже станет невалидным ZipCode (ну если у них случано не совпадут правила валидации).
T>>Можно, через метод, меняющий CountryCode и Zip. G>А если у нас WPF и свойства забайндены на контролы?
А нефик биндить сущности на контролы. А то тут скатиться до дельфевого подхода недалеко.
G>Да и слишком сложно для такой простой операции. Надеюсь стало понятно что работать с "невалидными сущностями" проще?
Здравствуйте, Tissot, Вы писали:
T>Здравствуйте, gandjustas, Вы писали:
T>>>Посмотри код, где он создается. Нет необходимости его хранить. Он легковесный. G>>То есть каждый раз лезть в базу и получать текущий CountryCode из связанной сущности?
T>Зачем каждый раз? Ты же говорил, что у тебя ленивая загрузка.
Ленивая или нет, все равно надо каждый раз лезть в базу чтобы обеспечитьвалидность сущности. Работать будет очень медленно.
G>>>>Кстати, при наличии CountryCode внутри кастомера невозжножно будет поменять этот самый CountryCode, потому что сразуже станет невалидным ZipCode (ну если у них случано не совпадут правила валидации).
T>>>Можно, через метод, меняющий CountryCode и Zip. G>>А если у нас WPF и свойства забайндены на контролы?
T>А нефик биндить сущности на контролы. А то тут скатиться до дельфевого подхода недалеко.
DataBinding плохой подход для UI?
Здравствуйте, gandjustas, Вы писали:
T>>Зачем каждый раз? Ты же говорил, что у тебя ленивая загрузка. G>Ленивая или нет, все равно надо каждый раз лезть в базу чтобы обеспечитьвалидность сущности. Работать будет очень медленно.
А чем же тогда ленивость?
T>>А нефик биндить сущности на контролы. А то тут скатиться до дельфевого подхода недалеко. G>DataBinding плохой подход для UI?
Нет, DataBinding прямиком на сущности — плохой прием.
Прекрасный пример. Давайте разберем его поподробнее.
1. Логика проверки зипкода инкапсулирована внутрь объекта "кастомер". Тебе это очень нравится, но на самом деле это означает, что у нас нет никакого способа узнать, валиден ли зип, не попробовав выполнить присваивание свойству. С точки зрения внешнего кода, кастомер — это чёрный ящик.
Возникают вопросы примерно такого рода:
а) как нам проверить валидность зипа прямо в UI, где недоступен экземпляр класса "кастомер"?
б) как нам получить осмысленный результат проверки, а не просто исключение и роллбэк? Ну, там, чтобы, к примеру, было сказано, где именно в индексе ошибка, и образец правильного заполнения?
2. Наша "сущность" начинает резко утяжеляться. Вот сейчас ей уже нужна по соседству табличка со всеми странами. Ну, то есть на самом деле надо будет еще и хранить историю правил формирования зип-кодов для всех стран.
Это еще уменьшает шансы "оторвать" ее от сервера приложений и обработать где-то еще.
Я уж не говорю про повторное использование в другой ситуации.
T>А теперь рассказывай, как ты будешь с этим бороться:
T>
T>update customer set zipCode = "любой невалидный zip";
T>
Очень просто. Такого кода в прикладном слое вовсе нет. Потому что модификация зип-кода проходит только через CustomerManager, который конечно же не забудет позвать все правила проверки пре-кондишнов. Это раз.
Два, в большом-большом количестве случаев лучше этот код разрешить. В частности, к примеру, потому, что далеко не всегда при создании кастомера есть информация про его зипкод. При таком подходе очень быстро окажется, что "ой, проверить стоимость остатков нельзя без проведения заказа, заказ нельзя ввести без кастомера, а кастомера нельзя завести без корректного зип-кода и ИНН". До свидания, бизнес сломался.
А если подумать головой, то окажется, что зип-код нужен только в тот момент, когда выполняется отгрузка товара. Если кастомер хочет заказать и заплатить, то нет никакой причины требовать от него валидность ненужного сейчас зип-кода.
В итоге, вместо вшитой в ZipCode { set ; } логики мы получаем Precondition для операции "отгрузить заказ", как я и говорил.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Tissot, Вы писали:
T>Возможно, я не сталкивался сподобного рода задачами, но мне доводилось работать с достаточно крупной erp-системой (Axapta). T>Там как раз было реализовано именно так, как я описывал — через объектную модель. Слышал краем уха что в том же SAP-е реализовано примерно таким же образом — логика не в базе, запросах, а в appserver cлое. Если все так плохо с работать через объектную модель, то почему в этих системах было реализовано именно так? Неужели тоже из-за недостатка опыта проектировщиков?
Не знаю, я свечку им не держал. Но обе системы новыми назвать сложно. Фаулер, собственно, свою книжку-то выпустил совсем недавно. Формализовав, с опозданием на пять лет, опыт передовых разработчиков 1998 года. Сейчас, в принципе, уже прошел 2008. Я думаю, современные системы сейчас еще только проектируются. Уж очень длинный у них лайфтайм.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Прекрасный пример. Давайте разберем его поподробнее. S>1. Логика проверки зипкода инкапсулирована внутрь объекта "кастомер". Тебе это очень нравится, но на самом деле это означает, что у нас нет никакого способа узнать, валиден ли зип, не попробовав выполнить присваивание свойству. С точки зрения внешнего кода, кастомер — это чёрный ящик. S>Возникают вопросы примерно такого рода: S>а) как нам проверить валидность зипа прямо в UI, где недоступен экземпляр класса "кастомер"? S>б) как нам получить осмысленный результат проверки, а не просто исключение и роллбэк? Ну, там, чтобы, к примеру, было сказано, где именно в индексе ошибка, и образец правильного заполнения?
S>2. Наша "сущность" начинает резко утяжеляться. Вот сейчас ей уже нужна по соседству табличка со всеми странами. Ну, то есть на самом деле надо будет еще и хранить историю правил формирования зип-кодов для всех стран. S>Это еще уменьшает шансы "оторвать" ее от сервера приложений и обработать где-то еще. S>Я уж не говорю про повторное использование в другой ситуации.
Что-то в этом есть.
T>>А теперь рассказывай, как ты будешь с этим бороться:
T>>
T>>update customer set zipCode = "любой невалидный zip";
T>>
S>Очень просто. Такого кода в прикладном слое вовсе нет. Потому что модификация зип-кода проходит только через CustomerManager, который конечно же не забудет позвать все правила проверки пре-кондишнов. Это раз.
Откуда CustomerManager и как он может помешать изменить Customer-а напрямую?
S>Два, в большом-большом количестве случаев лучше этот код разрешить. В частности, к примеру, потому, что далеко не всегда при создании кастомера есть информация про его зипкод. При таком подходе очень быстро окажется, что "ой, проверить стоимость остатков нельзя без проведения заказа, заказ нельзя ввести без кастомера, а кастомера нельзя завести без корректного зип-кода и ИНН". До свидания, бизнес сломался. S>А если подумать головой, то окажется, что зип-код нужен только в тот момент, когда выполняется отгрузка товара. Если кастомер хочет заказать и заплатить, то нет никакой причины требовать от него валидность ненужного сейчас зип-кода.
Ну это скорее аргумент в пользу изменени логики валидации — она должна запускаться только при определенном статусе заказа.
S>В итоге, вместо вшитой в ZipCode { set ; } логики мы получаем Precondition для операции "отгрузить заказ", как я и говорил.
Здравствуйте, gandjustas, Вы писали:
VGn>>>Разъясните мне-идиоту зачем полиморфизм данным?
T>>Данным, он наверное не нужен, а объектам domain model — вполне.
G>domain model не содержит данных?
Здравствуйте, Tissot, Вы писали:
T>>>А нефик биндить сущности на контролы. А то тут скатиться до дельфевого подхода недалеко. G>>DataBinding плохой подход для UI?
T>Нет, DataBinding прямиком на сущности — плохой прием.
Аргументы?
Здравствуйте, VGn, Вы писали:
VGn>Тогда вот это T>>>>>Методы. Интерфейсы. IB>>>>А это вообще никакого отношения к данным не имеет. T>>>Зато имеет к ООП. VGn>о чём?
Для тебя сущность — это данные и поэтому ты не видишь, зачем тут методы.
Для меня сущность — это сущность domain model и поэтому методам там самое место.
Как-то так.
VGn>Ты ответишь: как же? у нас же есть специальная прокладка с крылышками! VGn>Да?
Какая прокладка? Ты о чем вообще? Или у вас тут уже сложившаяся практика на этом форуме — хамить?
VGn>>Ты ответишь: как же? у нас же есть специальная прокладка с крылышками! VGn>>Да?
T>Какая прокладка? Ты о чем вообще? Или у вас тут уже сложившаяся практика на этом форуме — хамить?
Всё о том же — об ООП для доступа к данным.
Заметь, как раз я эмоциональных оценок твоему поведению не давал. Т.е. вёл дискуссию вполне в рамках формальных правил.
Здравствуйте, VGn, Вы писали:
VGn>>>Ты ответишь: как же? у нас же есть специальная прокладка с крылышками! VGn>>>Да?
T>>Какая прокладка? Ты о чем вообще? Или у вас тут уже сложившаяся практика на этом форуме — хамить?
VGn>Всё о том же — об ООП для доступа к данным. VGn>Заметь, как раз я эмоциональных оценок твоему поведению не давал. Т.е. вёл дискуссию вполне в рамках формальных правил.
"специальная прокладка с крылышками" — это видимо специальное такое формальное обращения?!
В топку такую дискуссию, адью.
T>"специальная прокладка с крылышками" — это видимо специальное такое формальное обращения?!
А как ещё назвать программную прослойку, усложняющую код изменением парадигмы доступа к данным, введением промежуточных хранилищ и ещё бог знает чем только для того, чтобы подстроить этот самый механизм доступа под любимый золотой молот разработчика?
T>В топку такую дискуссию, адью.
Как будет угодно
T>Откуда CustomerManager и как он может помешать изменить Customer-а напрямую?
Как откуда? Это и есть класс, в котором сосредоточены методы управления кастомерами.
Помешать он сам конечно не может, в том смысле, что у админа-злодея всегда есть шанс полезть в базу напрямую.
А вот запретить из прикладного кода вызовы апдейт-стейтментов можно в том числе и при помощи FxCop.
Это если не хватает культуры программирования.
Нужно просто отделить случайные ошибки от преднамеренных действий.
S>>А если подумать головой, то окажется, что зип-код нужен только в тот момент, когда выполняется отгрузка товара. Если кастомер хочет заказать и заплатить, то нет никакой причины требовать от него валидность ненужного сейчас зип-кода.
T>Ну это скорее аргумент в пользу изменени логики валидации — она должна запускаться только при определенном статусе заказа.
Это приведет к тому, что в приложении вообще не будет повторно используемого кода. Потому что в логику валидации зашито слишком много подробностей про окружение. А всего-то надо было применить регекс в нужный момент.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Tissot, Вы писали:
T>Еще раз прошу не переходить на личности. Если вам так хочется сказть мне что-то лично, мы можем встретиться и обсудить это в приватной беседе.
Хочешь сказать, что в приватной беседе у тебя появятся мысли отличные от Фаулера?
Здравствуйте, Tissot, Вы писали:
T>Мне кажется, я уже упоминал, что обсуждается не мнение (и уж тем более не их авторство), а идеи.
Тебе не кажется, что идеи было бы не плохо изложить, прежде чем обсуждать?
T>Отвечать на ваши сообщения я больше не намерен.
Аминь.