Всякие разные штуки сомнительной полезности сделанные в свободное от работы время.
Критика Presentation Model
Эта статья была написана по мотивам недавнего собеседования по приему на работу, где меня попоросили высказаться о presentation model и Parsley.
Если вы помните, год или два назад было очень модно писать архитектурные фреймворки. В то же время наметилось несколько различных направлений в этом неблагородном занятии. Неблагородном потому, что, переведя с заумного на обычный, цель написания и использования фреймворка такого рода в том, чтобы объяснить каждому конкретному программисту, что он бездарь, и не умеет строить приложение даже на минимально доступном ему уровне ответсвенности, не смотря на то, что на "вступительных" экзаменах его только и спрашивали что про архитекруру и использование шаблонов программирования.
Но цель этой статьи не в критике всех существующих фреймворков, а конкретного направления, с которым мне пришлось работать. Речь пойдет о Parsley и о presentation model, но этот фреймворк будет использован только как иллюстрация. Я надеюсь, что существующие недостатки и проблемы были логическим следствием проблем в теории, и никакая улучшенная реализация не спасет ситуацию, т.как теория в корне плохая.
В первую очередь, первоисточник: http://martinfowler.com/eaaDev/PresentationModel.html Martin Fowler - человек, с легкой руки которого мы сегодня используем термин presentation model, описал основные принципы работы в этой статье. К сожалению из документации к Parsley не понятно как именно нужно использовать эту библиотеку и большинство примеров в ней находятся на за гранью здравого смысла, но лучшего источника нет. Это так, отчасти, еще и потому, что Parsley одновременно еще и делает dependency injection - абсолютно лишнюю в AS3 вещь, и это во многом затрудняет понимание происходящего.
Для начала, если вам лень читать Мартина Фаулера, в двух словах о том, что из себя представляет presentation model. Это одновременно две разные вещи: название механизма взаимодействия между элементами интерфейса пользователя и логикой программы вцелом, и конкретной части механизма, отвественной за сохранение состояния элементов интерфейса пользователя. В дальнейшем я буду использовать presentation model (pm), понимая под этим конкретный класс, реализующий взаимодействие.
Концепция взаимодействия заключается в том, что компонент интерфейса централизовано сохраняет свое состояние в pm, и так же централизовано его оттуда восстанавливает. Это можно представить на примере чекбокса: когда вы над ним нажимаете клавишу мышки, чекбокс вызывает метод у pm, передавая ему сообщение о нажатии и ожидает от pm, что тот обработает нажатие и задаст новое значение.
Проблемы, которые возникают при детальном рассмотрении нашего примера:
Что случится, когда кроме одной возможной операции (нажатия мыши) компонент будет реагировать на другие события?
Следуя статье Фаулера - нам нужна одна функция для обновления всех значений во всех изменяемых частях компонента. Это значит, что если в нашем компоненте есть два чекбокса, при нажатии на один из них, значение для второго будет обновлятся точно так же, как и для первого, хотя это абсолютно не требовалось. Фаулер говорит в статье о разных уровнях детализации (или специфичности) обновления (coarse granularity vs fine granularity), понимая, что проблема существует, но не предлагая никакого решения. Не понятно зачем создавать проблему на пустом месте.
Кто должен зависеть от кого, или, перефразируя, кто должен знать о ком - pm о компоненте, или компонента о pm?
Следуя Фаулеру, опять же, нет универсального хорошего решения, решая в пользу одной из сторон, мы тем самым затрудняем себе тестирование другой стороны. Опять же - искусственно созданная проблема, которой могло бы не быть, если бы в принципе такой подход не использовался.
Что делать, когда компоненты не тривиальны, и состоят из других компонент, в которых тоже нужен свой pm?
Описание концепции не дает никакого ответа. Parsley предлагает для этого использовать dependency injection - т.е. неявным образом создавать глобальные переменные, и так же неявно передавать их дочерним компонентам. Естественно, такой подход превращает проект в монолитный блок кода не поддающегося тестированию, который нет возможности использовать повторно или обновлять по частям. Что еще хуже, найти то место где же действительно создаются те самые глобальные переменные, задаются очень важные настройки становится очень тяжело. Ситуация более типичная для монументальных продуктов написаных на Яве, с изобретенными по ходу написания настройками, распихаными по разным XML файлам в произвольных частях программы.
Если не использовать DI, то возможны два варианта: можно передать ссылку на дочерний pm дочерней компоненте в родительской компоненте, или спроектировать родительский pm так, чтобы он передал ссылку на дочерний компонент дочернему pm'у. Ни первый ни второй варианты не достаточно гибкие для того, чтобы позволить независимое тестирование родительской и дочерней компонент. В первом случае тестирование родительской компоненты, при наличие дочерней компоненты, не возможно без дочернего pm. Аналогично, во втором случае, нет возможности тестировать pm'ы без компонент.
На практике это выливается в то, что код просто никогда не тестируется. Вернее, он доводится до состояния, когда "вроде" работает и в этом состоянии доживает до момента, когда его полностью, со всеми потрохами, выбрасывают и пишут заново.
Реализация связывания между pm и компонентой - однообразный, механический труд. Человеку не хочется заниматься такими вещами, соответсвенно, напрашивается автоматизация. Автоматизация, очень часто, дело очень полезное, но не тогда, когда возможны исключения, и не тогда, когда автоматически сгенерированный код создает новые зависимости. На практике же, связывание (binding) создает зависимость к Flex Framework. Да и Parsley - это не генератор вашего кода, это библиотека (набор библиотек), которые вы подключаете к своему проекту, увеличивая общий размер, потребление памяти, количество окольных путей от одной точки интереса к другой (indirection layers); уменьшая при этом скорость работы.
Я думаю, что это очевидно, что альтернатива использованию presentation model и Parsley, или похожих библиотек, заключается в осознании того, что архитектурных фреймворков не бывает. Архитектура, это то, как вы строите вашу программу, и это не возможно импортировать в виде готового кода написаного другими людьми. Верить в то, что использовав архитектурный фреймворк ваш код вензапно превратится в логически правильно выстроенную, модульную, удобную в поддержке программу так же наивно, как и надеятся на то, что использовав те же краски, которыми пользовался ван Гог, ваши картины отправятся прямиком в известнейшие музеи мира
Всего комментариев 82
Комментарии
30.09.2012 00:53 | |
Цитата:
можно пользоваться DI и даже не знать что это такое...
|
30.09.2012 01:10 | |
конкретный способ реализации принципа это уже дело вкуса
|
30.09.2012 03:50 | |
Цитата:
DI не позволяет разрабатывать код от маленького к большому
Цитата:
Кроме того, DI заставляет заранее принимать решения, которые, возможно, нельзя правильно оценить на текущий момент.
Цитата:
...огромного количества служебного кода...
Второе: Простейший DI это совсем не много кода, просто вынести сборку конструктора в за пределы знаний деталей, не позволять кирпичиками самим решать что в конечном итоге получится. Третье: Да спагетти код будет работать быстрее и его быстрее писать, но вот как раз когда понадобится расширять, особенно расширять в тех местах где этого не планировалось изначально, вот тут и будет видна выгода. DI и Модульность тесно связанные вещи, ругая DI вы выступаете против модульности |
|
Обновил(-а) artcraft 30.09.2012 в 05:58
|
30.09.2012 04:01 | |
Цитата:
Где гарантия того, что SomeModel которым проинжектают наш объект - это именно тот его инстанс, который нам нужен? А еще учитывая что продебажить процесс инжекта невозможно довольно трудоемко, то радости от такого подхода вообще мало.
2. мне кажется вы так и не поняли что я говорил о инжекте зависящем от контекста (у меня возникает подозрение что возможно вы пользуетесь библиотекой которая не способна на такое... ) предоставлением нужной ссылки занимается некто находящийся вне модуля, тот кто собирает коструктор 3. Что именно мешает дебажить? Я не вижу никаких преград. |
|
Обновил(-а) artcraft 30.09.2012 в 05:16
|
02.10.2012 00:36 | |
В статье критикуется парслей вместе со встроенным в него инжектором. Конкретно по поводу парслея ничего не могу сказать.
Цитата:
Об надобности инверсии контроля вопрос вроде бы как и не поднимался.
Я согласен с тем что нельзя взять готовый фрйэмворк и рассчитывать что от этого ваш код сразу станет идеальным. Использование фрйэмворка не избавляет от необходимости принимать решения связанные с архитектурой приложения, кроме этого может наложить лишние ограничения... Сомневаюсь что возможно создать один фрэймворк одинаково хорошо подходящий для любой задачи. Я не согласен только с заявлениями о том что DI это плохо. Я настаиваю на том что DI (не конкретные библиотеки, а как частный случай инверсии контроля) это хорошо, и что следует знать о нём и понимать, и использовать его без фанатизма. |
|
Обновил(-а) artcraft 02.10.2012 в 00:54
|
Последние записи от wvxvw
- Dired - текстовый проводник по файловой системе (29.06.2013)
- Навигация по HTML с WASD (09.06.2012)
- JavaScript, все не так плохо (07.06.2012)
- Что такое tarball и чем его пакуют (11.04.2012)
- Критика Presentation Model (18.02.2012)