Пролог
Вряд ли эта статья войдёт в чьё-то избранное, так как статьёй как таковой и не является. Здесь нет никакого сборника мудростей для новичков. Здесь нет ни строчки кода. Здесь нет картинок для привлечения внимания. Скорее, этот пост — это вопросы и мысли вслух простого программиста аутсорсинговой компании. Потому и будет чем-то напоминать порезанный и склееный воедино диалог (ну, в данном случае, скорее, монолог) из курилки в офисе IT компании. Вероятно, на многие вопросы мне смогут ответить те разработчики, которые очень хорошо знакомы с .NET CMS Orchard и Umbraco. Хотелось бы на всякий случай воззвать к вашей интеллигентности — не устраивайте здесь священные войны, пожалуйста. Вы ведь уже давно сами поняли, что плюсы и минусы есть везде и, более того, при существовании двух популярных решений на одну проблему, их отношение приблизительно равно единице. Также, хотелось бы попросить прощения за получившееся полотенце.
Как для одного проекта мы делали свою CMS
В 2010 году я и мой напарник пошли на проект к клиенту, который в силу своих обязательств (мы детали не узнавали), не мог использовать сторонние компоненты. В виду того, что сама Microsoft внедряет в свои продукты сторонние открытые компоненты, клиент уточнил, что использовать предоставляемое в продуктах Microsoft — можно. У клиента был свой IT отдел, где был проведён предварительный анализ и даже начата была некоторая работа. Мы подключились почти в самом начале цикла. Их IT отдел проделал очень неплохую работу по базе, используя свои предыдущие наработки. Этот шаг был оправдан, так как новая система должна была быть тесно интегрирована с их старой. А старая система — это, по сути, база. Фронтенд и DAL были полностью стёрты и переписаны. База в итоге была поолностью синтегрирована со старым продуктом. В течение всего срока разработки сменилось несколько типов используемых технологий и далее — несколько версий в итоге утвердившихся технологий. Работы было много, но как и все уважающие себя программисты, мы работали на «заебись», а не на «отъебись». Каждый день думали о том, как улучшить модульность, как улучшить процесс сборки. Потихоньку ввели и Agile практику, и практику прототипирования. Некоторым это может показаться смешным. Но у кого были сложные заказчики с закостенелой системой — те меня поймут. Любое нововведение принимается если не в штыки, то как минимум проходит через фильтр агрессивной критики. Возвращаясь к нашему продукту, мы предоставили много, как нам казалось, новшеств. Использовали ортогональную идеологию, всё в проекте было виджетом. Всё настраивалось через базу. Виджеты сами были плагином (нет, не MEF1, обычный IoC контейнер Unity2 из EntLib3). Дальше и AOP начали использовать. Всё делалось без оглядки на существующие CMS. Конечно, глупо было не засматриваться на существующие решения. Но в нашем контексте всё было логично. Изначально продукт как CMS и не фигурировал. Это клиент плавно добавлял деталей к требованиям. Как всегда. Мы, конечно, готовы были к этому. Так всегда происходит, потому проблем с финансированием или переоценкой бюджета не было. Я лишь уточняю, что мы начали превращать продукт в CMS случайно. Благодаря пересмотру требований, ретроспективе событий и попытке увидеть продукт с точки зрения клиента, чтоб предвидеть его пожелания. Обычная практика DRY, введённый Agile4 процесс, ортогональность, попытка всё автоматизировать и заставить настраиваться через базу или файлы конфигурации, хорошая реализация сборочного цеха на TFS, своя система локализации, свой движок тем, контроль производительности, а также постоянный рефакторинг (а на деле — переписывание иногда самого ядра системы на очередном витке понимания клиента) и привели сами собой к продукту, взглянув на который любой программист спросил бы: «а вы тут что, CMS свою пишете?». На что получил бы тогда наш полный непонимания взгляд, так как мы забыли повесить ярлык на то, что мы делаем. С вашего позволения, я сверну эту историю до простого окончания — всё получилось. Мне не стыдно за свою работу, у меня был прекрасный напарник, с которым мы регулярно спорили. Продукт готов к использованию и лишь благодаря неторопливости клиента у наших разработчиков (коих уже теперь 5, в то время как у клиента успел поменяться состав руководителей и даже ядро их IT отдела) есть ещё время для вылизывания продукта до недостижимого совершенства. Таким образом, несмотря на нашу изоляцию от мира .NET CMS, мы создали свою. После моего ухода из проекта я решил взглянуть на варианты, которые мы игнорировали. На слуху в нашем офисе были Umbraco и Orchard. Я решил мельком взглянуть на их код, зная наперёд, что эти продукты просто обязаны быть хорошими. Потому при просмотре их архитектурных решений мне просто хотелось узнать, как ещё мы могли бы улучшить наш собственный продукт. Собственно, вот здесь я бы хотел узнать мнение людей, которые продолжительно следят за этими CMS.
«Orchard» и «Umbraco 5»
Обе CMS используют ядро, на которое могут положиться любые модули. Кстати говоря, в обеих командах используется JetBrains R#5. Это приятно сказалось на представлении кода обеих CMS. Также, обе CMS используют ORM NHibernate6 и IoC Autofac7. Хотелось бы заострить внимание сперва на два этих факта ради интереса. Начнём с последнего.
IoC и расширяемость вообще
В Umbraco попытались абстрагироваться от IoC, создав набор интерфейсов-оболочек. Таким образом, разработчик волен использовать любой IoC—контейнер. Однако при попытке это сделать (Unity вместо Autofac, так как в нашем проекте у нас другого выбора и не было) я заметил забавную вещь. В Umbraco просто скопировали модель интерфейсов Autofac. Т.е. фактически реализуя обвязку над Unity, эта обвязка будет иметь вид или ощущаться как Autofac. Справедливости ради стоит заметить, что, несмотря на забавность данного факта, сделать обвязку получилось. Ну, как получилось — оно компилируется и тесты проходит. Просто ради эксперимента попытался. Я вижу тут одно вероятное объяснение подобного подхода в Umbraco, хотя их, несомненно, больше. Правды я не знаю. Моё для себя объяснение состоит в том, что проектировалась CMS из рассчёта именно на IoC Autofac. И затем разработчики решили абстрагироваться от конкретного контейнера, но без ущерба разработке, так как уже был написан код и разработчики уже привыкли к синтаксису. Потому так забавно выходит переход на использование другого контейнера. Можно было бы, конечно, глянуть историю изменений CMS чтоб убедиться или, напротив, отказаться от своего объяснения как фактически неверного, но времени у меня на это не было. Если есть кто, кто следит за разработкой этой CMS, хотелось бы услышать об этом более подробно. В любом случае, спасибо разработчикам за существование возможности замены IoC. Иногда разработчикам не хочется использовать в своём проекте несколько разных библиотек, решающих одну задачу. В Umbraco также используется MEF, чего, к моему удивлению, не удалось обнаружить в Orchard. Подход к созданию модулей в Umbraco, однако, как мне показалось, достаточно ортодоксален. Их командой было написано несколько шаблонов со своим типом проекта. Стоит заметить, что этот потрясающий объём работы был проделан ради небольшого лоска. Т.е. вы в студии видите фирменную иконку на модуле-проекте Umbraco и имеете по правому щелчку мышки на нём или на каком-либо элементе какой-то уникальный, разработанный для данного типа проекта или элемента дополнительный набор действий. С вероятными своими визуальными помощниками и прочим… Ещё раз повторюсь, это огромное количество работы ради небольшого лоска. Однако, стоит заметить, благодаря этому Umbraco прекрасно «чувствуется» в студии. Фактической же пользы от этого мало и модернистский подход Orchard при разработке модулей, где используется столь знакомый многим scaffolding8 и манифесты в простом текстовом формате, в этом смысле мне импонирует больше. Как уже было сказано, Orchard также, как и Umbraco, использует Autofac в качестве IoC-контейнера. Уже сам только этот факт вызвал во мне вопрос. Кажется, Orchard возник в недрах Microsoft, когда готовился очередной MIX9. При этом задумывался Orchard как «идеологически чистая» CMS, что бы под этим ни подразумевалось. Что остановило разработчиков от использования Unity, который родился, как и Orchard, в Microsoft? Он также решает вопросы контроля зависимостей. Кроме того, разработчики не могли быть не в курсе, что MEF для их системы окажется отличным решением. Особенно в свете тенденций в MEF 2, которые сделали очевидное развитие реальностью. Использование технологий от Microsoft смогло бы улучшить их (Unity, классы в неймспейсе System.ComponentModel.Composition.Web.Mvc…). Коммуникации между разными командами, но в одной компании ведь всё равно должны проходить интенсивнее, чем между независимыми разработчиками библиотеки и разработчиками другой компании. Так мало того, Orchard использует Autofac в самом ядре. Т.е. связанность с данным контейнером куда сильнее, чем в Umbraco. Неужели с коммуникациями в Microsoft всё на столько плохо? Очень бы хотелось услышать хоть какие-то комментарии по данному поводу. С точки зрения использования системы это не мешает никому, но простой интерес покоя мне всё равно не даёт.
NHibernate ORM и уровень данных
Я тут лишь один вопрос задам, так как меня не очень интересовал данный вопрос. Тем не менее. Почему эта ORM, а не EF? Ну, то есть я конечно понимаю, что NHibernate давно вызрел, в то время как EF только подбирается к нормальному решению миграции данных. Но есть ли планы по переходу? NHibernate в Orchard интегрирован так же плотно в ядро, как и IoC. В то время как в Umbraco позаботились об ортогональности персистентного механизма. В Umbraco использование Umbraco.Framework.Persistence.NHibernate абсолютно опционально. Что касается уровня данных вообще, то в обеих CMS он на высочайшем уровне. У обеих свои плюсы. Umbraco может похвастаться отличной ортогональностью модулей и концепции ульев (Hive), являющихся, по-сути, абстрактными провайдерами данных. Я слышал массу негативных отзывов об Umbraco предыдущих версий (по очевидным причинам, на живых проектах никто не использовал не вышедшую даже в beta-стадию пятую версию этой CMS), когда дело касалось кеширования и вообще работы с данными. Что-то там было связано с XSLT, XML, отжираемой памятью, слабой производительностью… Я смотрю на пятую версию этой CMS, ничего не зная о предыдущих её версиях. И вижу, что тех проблем, о которых я был столь наслышан от сотрудников в этой версии просто нет. Может быть, в предыдущих версиях ортогональность была куда хуже или сотрудники не знали чего-то — мне этого не ведомо и даже не интересно сейчас. Orchard же хвастается своей системой типов контента, которая, по их заявлениям, является даже более гибкой, чем система типов CLR, на которой она базируется, имея ввиду динамическую композиции типов.
Что очень приятно зацепило в «Orchard» и «Umbraco 5»
В Umbraco реализован модуль локализации10, от которого лопнул мой
Что лично мне стало понятно
Если есть возможность, то лучше выучить одну какую-то хорошую CMS. На данный момент есть из чего выбрать. Все они используют ортогональность и стараются её максимизировать. То есть вы в любом случае будете в выигрыше (если речь не идёт о тривиальной статической страничке) и сможете завершить свой проект с меньшим количеством неожиданностей и сможете его завершить куда быстрее, чем без использования CMS. Я недоумеваю, с какими ещё непреодолимыми или очень неприятными неожиданностями разработчики могли сталкиваться, работая с этими системами (ещё раз хочу напомнить, я рассматривал только «Orchard» v.1.3 и «Umbraco» v.5). Код перед носом и он гораздо чище и качественнее с архитектурной точки зрения, чем большая часть всего того, что разработчики напишут без CMS. Я для своего следующего проекта выбрал Orchard, но лишь из-за своих личных предпочтений. Umbraco 5, после просмотра кода этой CMS, оказалась ничуть не хуже Orchard. А кое-где качество исполнения на голову выше. Однако меня подкупила, как я уже говорил, кажущаяся простота и ощущение «лёгкости» при работе с Orchard. Как вы уже видите, у меня остались некоторые вопросы и мне было бы дико интересно узнать на них ответы, если таковые у кого-то имеются. Спасибо, если дочитали это полотенце до конца.
MEF ↩
Unity ↩
EntLib ↩
Agile ↩
ReSharper ↩
NHibernate ↩
Autofac ↩
Scaffold ↩
Microsoft MIX events ↩
“Forget about resource strings” ↩
“How Orchard works” ↩
Writing a new Theme ↩
Making a Web Site Recipe ↩