Каковы ваши лучшие практики при использовании веб-фреймворка на основе MVC? - PullRequest
1 голос
/ 09 апреля 2011

Несколько общих вопросов для тех, кто хорошо разбирается в разработке веб-приложений.

Вопрос 1:

Как избежать проблемы "переноса зависимости"? Из того, что я понимаю, первая точка поиска объекта должна происходить в методе действия вашего контроллера. Оттуда вы можете использовать различные модели, классы, сервисы и компоненты, которые могут требовать определенных объектов.

Как избежать необходимости передавать объект другому только потому, что объект, который он использует, требует этого? Я бы не хотел снова заходить в базу данных / кеш для получения данных, но я также не хочу создавать функции, которые требуют массу параметров. Должно ли действие контроллера быть тем местом, где вы создаете каждый объект, который вам в конечном итоге понадобится для запроса?

Вопрос 2:

Какие данные вы храните в сеансе? Насколько я понимаю, вы, как правило, должны хранить только такие вещи, как идентификатор пользователя, адрес электронной почты, имя и права доступа.

Что если у вас есть данные, которые необходимо анализировать для каждого запроса, когда пользователь входит в систему? Стоит ли хранить весь пользовательский объект в кэше по сравнению с сеансом?

Вопрос 3:

Размещаете ли вы методы извлечения данных в самой модели или в отдельном объекте, который получает данные и возвращает модель? Каковы преимущества этого подхода?

Вопрос 4:

Если ваш сайт управляется идентификатором пользователя, как вы тестируете свою кодовую базу? Поэтому все ваши методы извлечения данных должны находиться в централизованном месте, чтобы вы могли переопределить их в своих модульных тестах?

Вопрос 5:

Вообще говоря, тестируете ли вы свои контроллеры? Я слышал, многие говорят, что это трудная и даже плохая практика. Что вы думаете об этом? Что именно вы тестируете в своих контроллерах?

Любые другие кусочки информации, которыми вы хотели бы поделиться относительно лучших практик, приветствуются! Я всегда готов узнать больше.

Ответы [ 2 ]

4 голосов
/ 09 апреля 2011
  • Как избежать проблемы «переноса зависимости»?

Хороший объектно-ориентированный дизайн BaseController SuperClass может справиться с большим количеством тяжелой работы по созданию экземпляров часто используемых объектов и т. Д. Использование составных типов для обмена данными между вызовами является весьма распространенной практикой. Например. Создание некоторого объекта контекста, уникального для вашего приложения, в контроллере для обмена информацией между процессами - не страшная идея.

  • Какие данные вы храните в сеансе?

Столько всего, что возможно по-человечески.

Если есть какая-то интенсивная операция с данными, требующая много обработки для обработки, и это требуется довольно часто приложением, это подходящий кандидат для хранения сеанса. И да, хранение информации, такой как идентификатор пользователя и другая информация персонализации, не является плохой практикой для состояния сеанса. Как правило, использование файлов cookie является предпочтительным способом персонализации. Всегда помните, что никогда, никогда не доверяйте содержимому файлов cookie, например, перед тем, как доверять этому, проверьте правильность прочитанного.

  • Размещаете ли вы методы извлечения данных в самой модели или в отдельном объекте, который получает данные и возвращает модель?

Я предпочитаю использовать шаблон Repository для своих моделей. Сама модель обычно содержит простые проверки бизнес-правил и т. Д., В то время как репозиторий обращается к бизнес-объекту для результатов и преобразований / манипуляций. На рынке существует множество паттернов и инструментов ORM, и эта тема обсуждается очень часто, поэтому иногда приходится просто знакомиться с инструментами и т. Д. *

  • В чем преимущества этого подхода?

Преимущество, которое я вижу с шаблоном репозитория, состоит в том, что чем тупее ваши модели, тем легче их модифицировать. Если они являются представителями бизнес-объекта (например, веб-службы или таблицы данных), изменения в этих базовых объектах достаточно абстрагированы от логики представления, которая является моим MVC-приложением. Если я реализую всю логику загрузки модели в самой модели, я как бы нарушаю шаблон разделения интересов. Опять же, это все очень субъективно.

  • Если ваш сайт управляется идентификатором пользователя, как вы проводите модульное тестирование своей кодовой базы?

Настоятельно рекомендуется использовать Dependency Injection, когда это возможно, в коде. Некоторые контейнеры IoC позаботились об этом достаточно эффективно и, поняв это, значительно улучшат вашу общую архитектуру и дизайн. При этом сам пользовательский контекст должен быть реализован через некоторую форму известного интерфейса, который затем может быть «смоделирован» в вашем приложении. Затем в своем тестовом комплекте вы можете смоделировать любого пользователя, которого хотите, и все зависимые объекты не будут знать разницы, потому что они будут просто смотреть на интерфейс.

  • Вообще говоря, вы тестируете свои контроллеры?

Абсолютно. Поскольку ожидается, что контроллеры будут возвращать известные типы контента, с надлежащими инструментами тестирования мы можем использовать методы, чтобы высмеивать информацию HttpContext, вызывать метод действия и просматривать результаты, чтобы убедиться, что они соответствуют нашим ожиданиям. Иногда это приводит к поиску только кодов состояния HTTP, когда результатом является какой-то массивный HTML-документ, но в случае ответа JSON мы можем легко увидеть, что метод действия возвращает всю информацию сценария, как и ожидалось

  • Что именно вы тестируете в своих контроллерах?

Любые и все публично объявленные члены вашего контроллера должны быть тщательно протестированы.

Длинный вопрос, более длинный ответ. Надеюсь, что это кому-нибудь поможет, и, пожалуйста, просто примите это как мое собственное мнение. Многие из этих вопросов - религиозные дебаты, и вы всегда в безопасности, просто практикуя надлежащий объектно-ориентированный дизайн, SOLID, программирование интерфейса, DRY и т. Д. *

3 голосов
/ 09 апреля 2011

Что касается взрыва зависимостей, книга Внедрение зависимостей в .NET (что превосходно) объясняет, что слишком много зависимостей показывает, что ваш контроллер принимает на себя слишком большую ответственность, то есть нарушает принцип единственной ответственности.Часть этой ответственности должна быть разделена за агрегатами, которые выполняют несколько операций.

По сути, ваш контроллер должен быть тупой .Если ему нужно столько зависимостей, чтобы выполнять свою работу, он делает слишком много!Он должен просто принимать пользовательский ввод (например, URL, строки запроса или данные POST) и передавать эти данные в соответствующем формате на уровень службы.

Пример, взятый из книги

Начнем с OrderService с зависимостей от OrderRepository, IMessageService, IBillingSystem, IInventoryManagement и ILocationService.Это не контроллер, но применяется тот же принцип.

Мы замечаем, что ILocationService и IInventoryManagement являются действительно деталями реализации алгоритма выполнения заказа (используйте службу определения местоположения, чтобы найти ближайший склад, затем управляйтеего инвентарь).Поэтому мы абстрагируем их в IOrderFulfillment и конкретную реализацию LocationOrderFulfillment, в которой используются IInventoryManagement и ILocationService.Это круто, потому что мы скрыли некоторые детали от нашего OrderService и, кроме того, выявили важную концепцию предметной области: выполнение заказа.Мы могли бы реализовать эту концепцию домена без привязки к местоположению без изменения OrderService, поскольку это зависит только от интерфейса.

Далее мы заметим, что IMessageService, IBillingSystem,и наши новые IOrderFulfillment абстракции действительно используются одинаково: они уведомляются о заказе.Таким образом, мы создаем INotificationService и делаем MessageNotification конкретной реализацией INotificationService и IMessageService.Аналогично для BillingNotification и OrderFulfillmentNotification.

Теперь вот хитрость: мы создаем новый CompositeNotificationService, который наследуется от INotificationService и делегирует различные "дочерние" INotificationService экземпляры.Конкретный экземпляр, который мы используем для решения нашей первоначальной проблемы, будет делегировать, в частности, MessageNotification, BillingNotification и OrderFulfillmentNotification.Но если мы хотим уведомить больше систем, нам не нужно редактировать наш контроллер: нам просто нужно реализовать наш конкретный CompositeNotificationService по-другому.

Наш OrderService теперь зависит только от OrderRepository и INotificationService, что гораздо разумнее!У него два параметра конструктора вместо 5, и , что наиболее важно , он почти не несет ответственности за выяснение того, что делать.

...