Posts Tagged “MVC”

В продолжение предыдущей теоретический темы про ActionScheme-driven Development — пример реализации такого подхода к разработке. Вообще, сам подход не зависит от языка программирования или фреймворка, но здесь я буду приводить примеры с использованием ASP.NET MVC.

Для реализации такого подхода, когда есть отдельное описание схемы взаимодействия с пользователем и отдельное описание модели данных, можно вместо привычных контроллеров создавать их generic-версии. В паттерне MVC контроллеры (как и вьюшки) зависят от модели, и каждая связка Controller+View работает со своей моделью данных, в то время как их generic-версии будут зависеть от класса однотипных моделей.

Comments View Comments

Если верить Скотту Гатри и его компании (1, 2), то одна из [используемых] философий дизайна ASP.NET MVC Framework — DRY (Don’t Repeat Yourself). Это хорошо, конечно, но одна вещь меня до сих пор не оставляла в покое, т.к., имхо, она еще недостаточно «осушена» (DRY-ed :) ). И эта вещь — проверка прав доступа в UI-представлениях (view).

Чему обычно «учат» люди, пишущие в своих блогах про MVC, когда  дело доходит до момента, что «вот этот кусок HTML нужно показывать не всем пользователям»? В лучшем случае (из того, что видел я, если видели лучше — делитесь :) ) предложат сделать helper для проверки типа «является ли текущий пользователь админом». На первый взгляд кажется логичным.

Но, ведь точно такие же проверки мы уже, наверняка, прописали в виде атрибутов к нашим action-методам в наших контроллерах. И любой активный элемент пользовательского интерфейса в нашем view, такой как кнопка, ссылка, и т.д., будет связан именно с action-ом какого-либо контроллера. По сути, у нас уже описаны условия, которые уже описывают когда есть смысл рендерить ту или иную часть пользовательского интерфейса. Ведь будет глупо показывать кнопку «Удалить», если контроллер вернет ошибку, сказав, что нам не хватаем прав? И, кроме того, если мы при написании своих view снова используем язык пользователей и ролей, как это делали при описании прав на action-методы, то мы снова повторяем себя. Ладно, если таких поверок минимум, или изменений в правах не будет еще лет 100, или вместо поддержки нашего кода все будет переписано заново. Не ракеты строим, все таки :) Хотя, последний пункт — это уже откровенное неуважение своего же труда.

И, мне кажется, было бы логично делать проверку UserCan(<ссылка на LawsController Decline>), это ведь и читается легче: «может ли пользователь отменять новые законы?», и код во view из «если пользователь — президент, то покажи кнопку Отменить» превращается в «если пользователь может отменять новые законы, то покажи ему эту кнопку».

Имхо, самая большая проблема тут — ссылка на action-методы. Эта проблема, в общем-то, уже решалась в MVC Futures для Html.ActionLink<>, и в дополнительных t4 шаблонах, выложенных на codeplex в релизах mvc. Еще важно разделять action-ы с одинаковыми именами. Но, т.к. все это работает в рамках .NET Framework, то все наши методы либо имеют разные параметры, либо разные имена [методов], чем можно пользоваться. Так же можно пользоваться атрибутами AcceptVerbs (например, трансформировать проверку в UserCan(Post, <ссылка на LawsController Decline>)), и в этом случае, возможно, не придется париться по поводу различий в аргументах, будет достаточно лишь имени action-а, что делается простейшим t4-шаблоном.

Единственное НО — производительность. Выбрав путь MVC Futures (передача лямбда-выражения, использующего нужную функцию) мы теряем в производительности, т.к. это означает, что мы в рантайме анализируем свой код. Выбрав путь ссылок на имена action-методов мы можем сделать преобразование вызовов проверки UserCan компилятором в проверки типа IsAdmin, сохранив производительность в рантайме, но скорее всего потеряем возможность автоматического изменения всех ссылок при переименовании action-методов (так ли это важно, если у нас это редкость, да и на момент компиляции нас предупредят об изменениях?).

Естественно, UserCan не решит нам все проблемы, особенно когда появляются проверки на уровне записей, и, например, нужно проверять права пользователя не на часть пользовательского интерфейса, а его права на конкретную запись, конкретный объект. Но это уже совсем другая история.

Tags: , ,

Comments View Comments

Noncommercial Attribution license