Комментарии 9
Монструозненько, так и получается с сервером: Customer (Domain entity) -> CustomerDTO -> (JSON/whatever) -> CustomerDTO -> Customer (client domain entity) -> CustomerViewModel.
Нужно больше обьектов на одну сущность!
Нужно больше обьектов на одну сущность!
+4
- Если этот (монструозный, как написали выше) велик используется только на старте, когда нужно быстро нагенерировать кучу стабов для DTO, Model, ViewModel, то профита от него в долгой перспективе я не вижу. Если подразумевается через него обновлять весь сгенерированный зоопарк при изменении требований или схемы БД, то опять я профита не вижу, зато вижу знатный вред в виде перетирания кастомного кода, добавленного в VM, напр., после генерации.
- ...Model: ObservableObject — означает, что собираетесь биндиться к модели. Это означает, что модель будет наполняться кодом присущим VM (например, команды или нотификации зависимых свойств). А это означает, что ваши модели де-факто станут ViewModel'ями. Зачем нужна прослойка ...Model: ObservableObject непонятно. Да и проходил много раз, когда к таким вот нагенерированным мета-моделям приходилось присоединять PARTIAL файлы. Очень скверно в контексте WPF.
- В общем, считаю генерацию ViewModel допустимой только одноразово и выгоды от этого чуть более, чем никакой.
+2
1. Я подошел несколько более формально к вопросу.
Суть — если мы генерируем болванки, то это автоматически делает процедуру разовой для объекта. Потому что болванка изменяется руками. Бессмысленно делать повторно — кучу времени уйдет на merge.
Если же генерация должна быть стабильной (при изменении перегенерировать весь стек слоев) — то тогда этот скрипт уже должен являться неотъемлемой частью проекта и ввреху сгенерированного кода большими буквами «this file contains autogenerated code. Don't change it!»). То же, что, к примеру, генерирует EF. Ибо обратное будет сильно портить жизнь всем участникам проекта.
2. Хорошо, что обратили мое внимание на это! Никогда не думал в таком разрезе. ObservableObject, имхо — просто объект, который может говорить об своих изменениях. Думаю, это видно и из его имени, но все же уточнил. А для ViewModel я всегда использовал ViewModelBase.
Почему он тут? В определенных сценариях, в нашем проекте, объект может сказать «я поменялся». Если, к примеру, с сервера пришла более свежая версия объекта. Но суть не в этом, скрипт переписывается за 5 минут, притачиваясь к задаче.
3. Ваше право. Пример использования здесь — это только способ пояснения.
Я вижу профит в экономии времени на описание слоев, но если вдруг время на модификацию до нужного состояния превышает время линейного написания — то конечно скрипт будет проигнорирован.
Ну и надо не забывать, такое разделение предоставит возможности T4 тем, кто не знает что такое T4. В случае, если задача заскриптована «старшим» братом.
Суть — если мы генерируем болванки, то это автоматически делает процедуру разовой для объекта. Потому что болванка изменяется руками. Бессмысленно делать повторно — кучу времени уйдет на merge.
Если же генерация должна быть стабильной (при изменении перегенерировать весь стек слоев) — то тогда этот скрипт уже должен являться неотъемлемой частью проекта и ввреху сгенерированного кода большими буквами «this file contains autogenerated code. Don't change it!»). То же, что, к примеру, генерирует EF. Ибо обратное будет сильно портить жизнь всем участникам проекта.
2. Хорошо, что обратили мое внимание на это! Никогда не думал в таком разрезе. ObservableObject, имхо — просто объект, который может говорить об своих изменениях. Думаю, это видно и из его имени, но все же уточнил. А для ViewModel я всегда использовал ViewModelBase.
Почему он тут? В определенных сценариях, в нашем проекте, объект может сказать «я поменялся». Если, к примеру, с сервера пришла более свежая версия объекта. Но суть не в этом, скрипт переписывается за 5 минут, притачиваясь к задаче.
3. Ваше право. Пример использования здесь — это только способ пояснения.
Я вижу профит в экономии времени на описание слоев, но если вдруг время на модификацию до нужного состояния превышает время линейного написания — то конечно скрипт будет проигнорирован.
Ну и надо не забывать, такое разделение предоставит возможности T4 тем, кто не знает что такое T4. В случае, если задача заскриптована «старшим» братом.
0
1. На моей практике почти не было проектов, когда бы архитектура заданная на старте не претерпевала значительных изменений уже спустя месяц. Обычно требования настолько смутны, что уже через пару месяцев приходишь к выводу, что структура БД являяет собой полную противоположность бизнес-проблеме. В таком случае реализация и внедрение такого рода генераторов может быть «Преждевременной Оптимизацией».
Был один проект, когда созданная и принятая схема БД полностью соответствовала бизнесу, но там на старте представитель заказчика очень эффективно с архитектором сработался и четко понимал, какие фичи нужны. Но даже в этом случае такой генератор значительного профита не дал бы, т.к. основное время тратится не на создание Model и VM с базовым функционалом, а на постройку поверх них специфических сценариев пользования.
2. Опять же в упомянутом выше проекте так и было сделано за исключением генерации VM. И пошли по простому пути — биндинг к моделям (aka ObservableObject). Если бы сразу делались VM вместо такого наследования, то потом не было столько возни с такими мета-моделями. Пришлось много логики сделать в partial файлах и еще больше вынести во врапающие VM. Поддерживать такое УГ неприятно. Так что…
а) Если сущность является DataContext'ом строки в DataGrid — сразу создавайте под нее VM. Это позволит безболезненно добавлять некие команды для манипулирования внутренностями данной сущности (активация / деактивация, пометка аттрибутами данной сущности и изменение подчиненных и тп). Иначе придется реализовывать эти команды в родительской VM.
б) Если в ячейке требуются разные специфичные педальки (комментарий или флаги какие-то дополнительные), то опять же желательно создавать VM для ячейки.
Я ругался и продолжаю каждый раз на старте ругаться. По началу кажется, что создание VM для основных вещей излишне и нужно следовать принципу YAGNI, но с WPF и VM этот принцип не работает. Создать сразу VM на старте недорого. А вот сделать подмену моделей на VM уже в зрелом проекте невозможно из-за нехватки времени. Лид команды должен иметь стальные орехи с алмазным напылением, чтобы продавить заказчику оплату такого технического долга. Проценты будут очень велики.
Был один проект, когда созданная и принятая схема БД полностью соответствовала бизнесу, но там на старте представитель заказчика очень эффективно с архитектором сработался и четко понимал, какие фичи нужны. Но даже в этом случае такой генератор значительного профита не дал бы, т.к. основное время тратится не на создание Model и VM с базовым функционалом, а на постройку поверх них специфических сценариев пользования.
2. Опять же в упомянутом выше проекте так и было сделано за исключением генерации VM. И пошли по простому пути — биндинг к моделям (aka ObservableObject). Если бы сразу делались VM вместо такого наследования, то потом не было столько возни с такими мета-моделями. Пришлось много логики сделать в partial файлах и еще больше вынести во врапающие VM. Поддерживать такое УГ неприятно. Так что…
а) Если сущность является DataContext'ом строки в DataGrid — сразу создавайте под нее VM. Это позволит безболезненно добавлять некие команды для манипулирования внутренностями данной сущности (активация / деактивация, пометка аттрибутами данной сущности и изменение подчиненных и тп). Иначе придется реализовывать эти команды в родительской VM.
б) Если в ячейке требуются разные специфичные педальки (комментарий или флаги какие-то дополнительные), то опять же желательно создавать VM для ячейки.
Я ругался и продолжаю каждый раз на старте ругаться. По началу кажется, что создание VM для основных вещей излишне и нужно следовать принципу YAGNI, но с WPF и VM этот принцип не работает. Создать сразу VM на старте недорого. А вот сделать подмену моделей на VM уже в зрелом проекте невозможно из-за нехватки времени. Лид команды должен иметь стальные орехи с алмазным напылением, чтобы продавить заказчику оплату такого технического долга. Проценты будут очень велики.
+1
Печальный, но по любому полезный опыт! Я же, скорее люблю SOLID + KISS. В фоне где то маячит DRY.
Получается просто: у каждой ступеньки( класса), есть своя область ответственности, и даже если это приводит к избыточности кода, выраженном в количестве классов, то у каждого из них будет достаточно малая ответственность и он будет читаться легко. Не скажу что очень строго держусь за это, но в разрезе слоев MVVM — да.
Получается просто: у каждой ступеньки( класса), есть своя область ответственности, и даже если это приводит к избыточности кода, выраженном в количестве классов, то у каждого из них будет достаточно малая ответственность и он будет читаться легко. Не скажу что очень строго держусь за это, но в разрезе слоев MVVM — да.
0
Я тоже за SOLID. Только вот его часто каждый по-разному интерпретирует. В данном случае я считаю наделение моделей элементами VM как раз нарушением принципа Single Responsibility.
0
Не все так плохо. ObservableObject внутри себя содержит только deafult реализацию механизмов оповещения об изменении, т.е. INotifyPropertyChanged, INotifyPropertyChanging.
Да, можно сузить их применение до VM, но они были нужны для оповещения о восходящих изменениях, к примеру когда у нас один объект и несколько визуализаций к нему, каждая из которых может изменится вслед за изменением объекта. В этом случае удобно сделать объект просто говорящим.
Но, по правде сказать, со временем tracking изменений полностью отделился от моделей и наследования от ObservableObject — и для меня это уже скорее архаизм. Я по прежнему не вижу ничего плохого в говорящем объекте, но не имею права защищать эту точку зрения — сам уже поступаю иначе.
В любом случае спасибо за мнение, это было очень полезно! Суть статьи от этого не страдает, но пример — да, становится менее ярким.
Да, можно сузить их применение до VM, но они были нужны для оповещения о восходящих изменениях, к примеру когда у нас один объект и несколько визуализаций к нему, каждая из которых может изменится вслед за изменением объекта. В этом случае удобно сделать объект просто говорящим.
Но, по правде сказать, со временем tracking изменений полностью отделился от моделей и наследования от ObservableObject — и для меня это уже скорее архаизм. Я по прежнему не вижу ничего плохого в говорящем объекте, но не имею права защищать эту точку зрения — сам уже поступаю иначе.
В любом случае спасибо за мнение, это было очень полезно! Суть статьи от этого не страдает, но пример — да, становится менее ярким.
0
Вот видите… все равно отделить придется. Поэтому нужно сразу отказываться, чтобы не переделывать.
Если не допустить наследование от ObservableOnject, то запрет на биндинг к моделям будет более осязаемый. Припугнуть, так сказать, девелоперов утечками памяти. Это решение лид должен принять и не поощрять.
Если же лид принимает такое решение, то он сам себе и команде злой Буратино.
Если не допустить наследование от ObservableOnject, то запрет на биндинг к моделям будет более осязаемый. Припугнуть, так сказать, девелоперов утечками памяти. Это решение лид должен принять и не поощрять.
Если же лид принимает такое решение, то он сам себе и команде злой Буратино.
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
T4 в помощь на примере MVVM