Многие скажут, что сравнивать теплое с мягким глупо. Все верно, сравнивать CMS и фреймворк некорректно, так как это инструменты из разных областей.
Но я все-таки сравню WordPress CMS и фреймворк Laravel. И вот почему:
Как я уже сказал, WordPress — это CMS, а Laravel — фреймворк (framework). CMS ориентирована на обычного пользователя (контент-менеджера, редактора, администратора сайта), фреймворк на программиста. Вытекающие различия мы обсудим ниже.
Обе системы Open source, то есть системы с открытым исходным кодом. Это означает, что любой разработчик (даже вы и я) может сделать форк (ответвление) и изменить код под себя. Также можно предложить изменение в основной продукт (с помощью pull request). Обе системы полностью бесплатны.
Обе системы написаны на языке PHP. Язык PHP с большим отрывом лидирует среди языков программирования для веба (80% сайтов), существует с 1995 года. На PHP написаны такие проекты, как Facebook, VK и Badoo.
Давайте приведу несколько интересных цифр.
Является мировым лидером среди CMS. Существует давно, поддерживается создателями. Популярность, судя по трендам Google, медленно снижается, но все равно остается недосягаемой для конкурентов.
Главный разработчик: Мэтт Мюлленвег
Первый релиз: 2003 г
“Живых” сайтов на платформе: 26M
Звезды на GitHub: 12K
Сравнение с конкурентами по поисковым запросам Google:
Топ 10 стран:
Laravel — относительно молодой PHP-фреймворк, стремительно набирающий очки. Быстро обогнал другие PHP-фреймворки, в 2018 г по популярности среди разработчиков обогнал остальные серверные фреймворки (не только PHP).
Главный разработчик: Taylor Otwell
Первый релиз: 2011 г
“Живых” сайтов на платформе: 130K
Звезды на Github: 46K
Сравнение с конкурентами по поисковым запросам Google:
Топ 10 стран:
Прежде чем мы углубимся в кроличью нору, я дам вам важнейшую установку в любой области программирования. Возможно, это самая ценная мысль в этой статье.
Разработка — ничто. Поддержка — все.
Выпустить начальную версию продукта на рынок (MVP) очень легко, если хоть немного знаешь, чего хочешь. Сдохнет ваш проект (если сдохнет) в следующие 2-3 года поддержки и развития. Расходы в этот период составят 9/10 стоимости проекта и, что самое важное, вся прибыльная функциональность проекта также будет создаваться в этот период, так как заранее не известно, что нужно будет потребителю.
Итак, мы познакомились с нашими подопытными, давайте начинать резать.
Расчехлим инструменты. Скажу пару слов, о том, как мы будем называть вещи.
API (Application Programming Interface) это возможность для двух систем разговаривать: обмениваться данными, отдавать друг другу команды и тд. В статье, в зависимости от контекста, я буду использовать API в двух смыслах:
Фича — полезная для пользователя законченная функциональность проекта. Возможность оплаты, вывод текущего времени. Что-то полезное, что можно закодить.
Админка — панель администрирования.
Продакшен, прод, боевой — сайт или сервер, открытый для реальных посетителей
Ё — букву Ё я не использую из-за особенности раскладки клавиатуры.
Сейчас будет немного больно сложно!
Если вы не программист, техлид или интересующийся разработкой человек, то переходите сразу к выводам.
Я начну с базы потому что:
Давайте представим, что мы разрабатываем небольшой образовательный проект. Допустим, в нашей онлайн-школе есть студенты, курсы, тесты и попытки студентов пройти тесты, некоторые даже успешные.
Как вы думаете, с каким вариантом разработчик быстрее разберется, быстрее найдет нужные данные?
Хотя, это не главный вывод. Все дело, конечно, в производительности (скорости работы) вашего проекта.
CMS не позволяет проектировать БД, в отличии от фреймворка. От гибкости базы данных напрямую зависит ее производительность.
Как вы видели выше, WordPress по историческим причинам хранит 99% данных в двух-трех таблицах. Можете представить себе, какой объем ресурсов нужен, чтобы собрать самый крошечный кусочек связанных данных из большой базы?
Например, мы хотим предложить дополнительный урок студентам, уже проходившим одну из тем. Для этого давайте найдем телефоны всех студентов, которые пытались пройти тесты по определенному курсу.
Это была достаточно простая операция, но из-за структуры БД количество обращений в WordPress оказалось вдвое больше.
Вы знаете, почему большинство SQL БД еще часто называют реляционными?
Потому что таблицы в них связаны друг с другом, то есть связаны данные. И именно в этом преимущество таких баз.
Дело в том, что только фреймворки за счет гибкости базы по настоящему используют возможности БД. Во фреймворках, в том числе в Laravel, вы сами с нуля проектируете базу и можете распределить данные и их связи самым оптимальным способом, можете создавать индексы, триггеры и тд. Оптимизация БД на уровне БД не только звучит лучше, чем оптимизация кода, но и гораздо более эффективна.
ORM — это такой кусок кода, который берет данные из базы и создает для них объектную модель, а затем обеспечивает связь этой модели с базой. С такой моделью может работать ваш код. Вы можете программно менять объектную модель и сохранять ее обратно в базу. Это очень удобный подход для работы с данными, позволяющий писать чистый и понятный код.
Получается, что в ORM каждый класс соответствует таблице, а объект (реализация класса) соответствует строке. Посмотрите на картинку, и вы все поймете.
В WordPress ORM нет. Есть десяток методов получения данных из базы, некоторые даже создают объекты (например, WP_Post
), но это все настолько же далеко от ORM, как селедка от Плутона.
В Laravel есть решение Eloquent, реализующее ORM по принципу Active Record. Оно написано автором фреймворка Taylor Otwell, и уже давно используется не только в Laravel, но и в других приложениях на PHP, например, есть библиотека для того же WordPress и для фреймворка Slim. Есть даже имплементации в других языках, например, Adonis JS для Node.JS. Я знаю пример команды разработки крупного банка в Америке, которая просто берет Eloquent, если нужно привязаться к какой-либо SQL базе данных.
Многие считают, что популярность фреймворка для начинающих разработчиков обусловлена именно удобством Eloquent. В качестве примера приведу все тот же пример с онлайн-школой, где мы получали телефонами усердных студентов, делавших попытки пройти тест по курсу “Протирка слонов”
$phones = Course::whereTitle("Протирка слонов") ->tests() ->testing_tries() ->users() ->pluck("phone") ->get();
Я не буду приводить аналогичный код в WordPress, так как он займет слишком много места.
Миграции — это очень полезная штуковина, которая помогает разработчиками хранить структуру базы данных в коде. Зачем это нужно? — Спросите вы.
Допустим, у вас локально на компьютере развернут сайт. Вы создаете в нем новую таблицу данных cats, пишете для нее код. Код вы отправите на “боевой” сайт через Git (если вы не умеете работать с Git, рекомендую записаться на мой курс Go Git). А как быть с таблицей cats?
Правильно, вы создадите для этой таблицы файл-миграцию, который описывает структуру этой таблицы. Затем, например, на “боевой” площадке вы создадите из этой миграции таблицу в БД. Таким образом, структура вашей БД хранится в файлах, в коммитах, поэтому вы можете с легкостью ей управлять.
В Laravel миграции реализованы стандартно для многих фреймворков. В этом нет технического прорыва. Все просто работает.
В WP миграций нет.
И это одна из причин, почему мы чуть не сбежали с движка несколько лет назад. Переносить изменения структуры БД между площадками (локальный компьютер, тестовые и продакшен сервера) руками было очень больно, тяжело и опасно. Но вдруг все изменилось.
В какой-то момент, я нашел решение под названием ACF Local JSON. Это фича плагина ACF. ACF реализует дополнительные свойства для разных сущностей WordPress. Это не миграции, но решается та же проблема. Если в двух словах, то ACF LJ позволяет для свойств какой-либо сущности создать файл, в котором хранится эта структура. В отличие от миграций, ACF LJ не нужно применять на боевой площадке, они работают прямо из файлов. Интересный подход, иногда очень удобный, но ограниченность применения (ACF LJ работает только для полей ACF) и проблемы с “раздвоением” (ACF LJ могут храниться как в базе, так и в файлах) надоедали.
В целом, я бы дал обеим системам по одному баллу в этой части. Хотя и странно, что разработчики WordPress должны отдельно покупать плагин ACF для таких базовых задач.
Это не бог весть какая проблема, но я хоть убей не понимаю, зачем в WordPress в базе данных во многих местах захардкожен (жестко прописан) домен. При переносе базы нужно всегда делать поиск с заменой, для автоматизации которого (и других задач с базами данных) мне пришлось написать BDSM. По названию скрипта можно понять, насколько эта проблема раздражает.
А теперь давайте перейдем к действительно интересным вещам. Давайте поговорим о коде.
MVC — старая, но актуальная по сей день логика создания систем для взаимодействия с пользователем. MVC используется почти везде с 1978 года. Расшифровывается как Model-View-Controller.
Предлагаю вернуться к примеру с онлайн-школой с курсами и тестами. Я попробовал очень примерно накидать структуру кода такого приложения на WordPress и Laravel.
Как видите, вся логика варианта WordPress лежит либо в functions.php, либо прямо в шаблонах страниц, что противоречит логике MVC (об этом чуть ниже). В принципе, ничего плохого, пока на вашем сайте десяток информационных страниц и форма обратной связи.
В варианте Laravel нам заранее установлена логика MVС, основные принципы ООП и кое-где логика авторов фреймворка. Причем все это идет как требования, мы не можем от нее отступить.
В программировании стандартизация — благо, потому что любому Laravel-разработчику ясно, где описано получение названия теста (Test@getTitle()
), а где логика удаления курса (CourseController@destroy
).
К слову о логике Taylor Otwell. Его логика отличается лаконичностью и близостью к разговорной речи. Многие конструкции в ядре можно буквально читать как обычный текст (на английском). Например, проверка, может ли юзер редактировать данный пост:
if ($user->can("update", $post)) { // some code }
Роутер (маршрутизатор) в данной статье это не та коробочка с лампочками, проводами и рогами, что стоит у вас на шкафу. Роутер в веб-проекте это механизм, который сопоставляет отдельные адреса страниц (урлы) с отдельными кусками функциональности (методами контроллера).
Роутинг это маршрутная карта вашего проекта.
Принцип роутера в Laravel позаимствован Тейлором из фреймворка Синатра (о котором, похоже, никто кроме Тейлора и не слышал). Я считаю, что это лучший пример подхода KISS (Keep It Silly Simple, в переводе “до идиотизма просто”).
Все рауты (маршруты, урлы) для веб-интерфейса описаны в файле routes/web.php.
Route::get("/courses/", "CourseController@index");
Это пример, в котором мы просто на странице /courses/ выводим список курсов методом index()
класса CourseController
.
или вот посложнее
Route::prefix("/tests/")->middleware("auth")->group( function(){ Route::get("/", "TestController@index"); Route::get("/{test}", "TestController@show"); }; );
В этом примере мы обрабатываем урлы вида /tests/ и /tests/name-of-the-test. Также мы разрешаем просмотр тестов только авторизованным юзерам. И, наконец, мы передаем ключ теста (конструкция {test}
) в метод show()
класса TestController
с помощью Implicit Route Model Binding, это еще одна удобная фича Laravel.
Кстати, в Laravel можно вывести список всех роутов прямо в консоль с подробным описанием.
Роутинг в WordPress это серьезная головная боль для разработчика. Самый часто используемый способ создать новый урл — создать страницу, а на нее навесить шаблон, в который запихнуть всю логику.
Во-первых, мы очень долго думали, как в WordPress переносить такие урлы (страницы) между площадками, но так и не придумали абсолютно ничего. Так и делаем руками.
Во-вторых, этот принцип резко противоречит MVС, и не позволяет развивать проект.
Есть в нашей отрасли такое понятие как Dependency Hell (ад зависимостей). Сейчас мы постараемся понять, почему оно не называется Dependency Cocktail Party или Dependency Weekend On Islands.
Многие части фреймворка или CMS зачастую нуждаются в других частях.
Например, класс RegisterController
, отвечающий за регистрацию пользователей использует класс HashManager
для хэширования паролей и класс Validator
для проверки введенных пользователем данных. Эти два класса, в свою очередь, используют другие и так далее.
Ваш сайт выдаст ошибку, если не подтянется хотя бы одна из зависимостей. Другой серьезной проблемой будет подтягивание лишней функциональности для какого-либо действия. Давайте посмотрим на наших испытуемых в этом контексте.
Следующий абзац, вероятно, самый сложный в статье. Ничего страшного, если вы его пролистнете. Я просто должен был упомянуть эти решения.
Наверное, топовая киллер-фича Laravel, выделяющая его среди других фреймворков — это мощный механизм разрешения зависимостей и гибкое управление ими. В основе фремворка лежат Service Container и Service Providers, возможности которых я до сих пор открываю для себя. Также в Laravel мне нравится реализация Implicit Binding для передачи данных, например, в раутах (пример выше). Разумеется, как и остальные современные PHP-фреймворки, Laravel использует неймспейсы (namespaces) для удобного разграничения областей видимости и импорта классов, а также автоподгрузку PSR-4 (настроено из коробки с помощью Composer).
В WordPress нет никаких механизмов для разрешения зависимостей. Из коробки нет Composer (о нем ниже) и нигде не используются неймспейсы. Все обстоит несколько проще.
В WordPress есть глобальные переменные. Причем используются очень активно. Но, честное слово, лучше бы их не было. Существование глобальных переменных неудобно и опасно, так как глобальную переменную можно случайно (специально?) переопределить в любом месте (установленном плагине, теме) и изменить логику работы системы. Но есть и другая проблема.
У фехтовальщиков есть выражение: хороший замах нужен везде, кроме фехтования. В программировании все точно также. Любая лишняя мощность угрожает производительности и качеству вашего проекта.
WordPress при каждом обновлении страницы подгружает всю свою функциональность. То есть, когда я хочу выполнить какой-то небольшой кусочек кода, и мне нужно чуть-чуть Вордпресса (получить имя текущего юзера) я оказываюсь перед выбором: подключить все или не подключать ничего. Я выбираю все и, в итоге, получаю солидный оверхед (лишнюю нагрузку).
Оба наших соперника имеют возможность расширения функциональности. Это хорошо, но в сторонних решениях проблема в том, что они сторонние. Их поведение и зависимости нужно контролировать. Давайте разбираться.
Выше я уже упоминал Composer. Это пакетный менеджер для PHP-библиотек. Он проверен временем (с 2012 года) и, фактически, не имеет аналогов. Если вы разрабатываете проект на PHP, то без Composer вам придется открывать велосипедный завод.
Laravel является пакетом Composer. По сути, Composer, а вовсе не Laravel является основой проекта. Получается, фреймворк — это не центр вашей вселенной, а всего лишь одна из планет. А звезда — пакетный менеджер Composer. Если бы Галилей был программистом …
Composer умеет устанавливать пакеты не только для Laravel, но и для любого другого PHP приложения. Учитывая, что структура БД не завязана на фреймворке и, как мы только что узнали, сам фреймворк является пакетом, то у нас появляется абсолютно новая степень свободы.
Мы можем безболезненно сменить фреймворк. Вдумайтесь. Как вам такая степень гибкости?
Выбирать мы сможем в рамках языка PHP, конечно, но выбор все равно огромен. Как я уже упоминал, 80% всех сайтов в мире работают на PHP. Я легко верю этой статистике, в России цифра должна быть больше 90%.
В WordPress из коробки нет никакой подготовки к использованию Composer, однако поставить все-таки можно. Мы ставим почти на все проекты.
Из коробки в WordPress есть менеджер плагинов. Я не уверен, можно ли назвать установку плагинов в админке WordPress пакетным менеджером, но если так, то в нем нет ни зависимостей, ни фиксации состояний, ни автоподгрузки через неймспейсы. Все новые плагины нужно добавлять в коммиты (сотни, тысячи файлов). Написаны плагины по-разному и пользоваться ими в своем коде можно только через хуки, о которых речь пойдет в следующем различии.
Разумеется, менеджер плагинов WordPress может устанавливать плагины только для WordPress.
При этом, надо отдать должное менеджеру плагинов в WordPress. Он имеет приятный, продуманный интерфейс и позволяет ставить плагины быстро, интуитивно и без каких-либо технических знаний. Composer же работает только через консольный интерфейс (терминал, CLI). Количество WordPress-плагинов сравнимо с количеством Composer-пакетов.
Во второй части мы обсудим:
Перейти ко второй части статьи