«Что в этом сложного?» — видимо, подумали люди, не очень знакомые с техническими тонкостями, и обратились к нам за разработкой. Для нас же это поначалу напоминало анекдот: есть статичный макет, который совершенно неизвестно как должен меняться в зависимости от разных условий, и заказчик, который хочет увидеть новый сайт в работе меньше, чем через два месяца.
Как мы разбирались, что на самом деле нужно заказчику и какой должна быть админка, искали компромисс, чтобы уложиться в сроки, и реализовали новые фичи, расскажу под катом.
Исходные данные
The Bell — деловое медиа, которое начиналось с ежедневной e-mail рассылки. Сейчас это ещё и основной новостной сайт, и несколько спецпроектов с отдельными площадками.
Как вы поняли, сайт The Bell изначально был сделан на WordPress, что для стартапа вполне логично. WordPress — универсальная и простая CMS. И этим, по большому счёту, всё сказано. Она хороша для прототипирования и того, чтобы быстро стартануть; там можно реализовать всё, ну или почти всё. Но когда за несколько месяцев трафик вырос со 100 тысяч пользователей до миллиона, требовались большие усилия и кэши, чтобы WP и виртуалка, на которой он работал, не умирали. Поэтому сначала переехали на выделенный сервер и только спустя какое-то время занялись WordPress.
В подросшем продукте большее значение имеет то, сколько усилий потребуется для реализации стратегии развития и точно ли получится так же хорошо, как если делать с нуля под конкретную задачу. В случае «старого» The Bell каждая новая доработка делала реализацию всё более запутанной, громоздкой и непригодной для поддержки и рефакторинга.
Когда речь зашла о редизайне и полной переработке новостной ленты, стало очевидно, что проект перерос WordPress и пора разрабатывать специализированное решение. Новый макет с пятью новыми видами карточек, различными вариантами оформления материалов и возможностью управлять положением статьи в ленте на WP было бы не только сложно хорошо реализовать, но с этим потом было бы очень неудобно работать редакции, а поддержка и доработка для нас была бы полным кошмаром.
Для кастомной реализации мы выбрали связку Angular + Laravel, потому что оба этих фреймворка уже так или иначе были задействованы в отдельных модулях проекта. Для рассылок уже использовался модуль на Laravel, который отправлял письма через Mailchimp и собирал аналитику в нашей админке. И подпроект Bell.Club был ещё раньше сделан без участия WordPress на Laravel.
Что нужно сделать
Плиточную систему карточек материалов с возможностью выбирать оформление, ширину (на всю страницу, на половину, треть и четверть ширины), добавлять иллюстрации или фон и фиксировать позиции отдельных статей.
Для иллюстрации поместил в ленту статьи из нашего блога. The Bell пишут на острые социальные и политические темы, которые не хочется обсуждать в рамках данного поста.
А дальше мы вместе выясняли, что должно происходить со всеми остальными статьями: бесконечная ли будет лента, как она должна обновляться и куда будут попадать новые материалы, а куда уходить более старые.
Отдельно замечу, что заказчики — классные профессионалы в медиа, но среди них нет ни одного технического специалиста. Переложить задачу из картинок и разговоров в задачи для разработки нужно было нам самим. Работали в чистом виде по Agile и по ходу дела выясняли, что и зачем хочет клиент и что ему можно предложить по этому поводу.
На такого рода черновики мы ориентировались, проектируя админку.
Сроки. Ожидание vs реальность
Итак, мы подумали, что настало время отдавать техдолг, и настроились на большое переписывание. Мы же программисты — нас хлебом не корми, дай выбросить старый код и написать всё с нуля. Но получилось всё не совсем так.
Чтобы перевезти весь проект на новый стек, нужно было переписать всё, что связано с WordPress, а именно: фронтенд и бэкенд, админку и кучу всяких мелочей типа rss, метаданных, seo, которые в WordPress были реализованы плагинами. С учётом имеющихся ресурсов (в проекте было занято всего два разработчика) это заняло бы полгода. А заказчику новый дизайн нужен был к 1 апреля — на тот момент оставалось уже меньше двух месяцев.
Пришлось искать компромисс.
За что хвататься, чтобы всё успеть
В итоге решили разбить работы на несколько этапов и переезжать постепенно. Начали с фронтовой части и админки для управления лентой, а создание текстов писем и статей на первом этапе оставили в старой и привычной для редакции системе на WordPress. Конечно, это сделало работу сложнее, но позволило быстрее выкатить новую функциональность.
Бэкенд. Админка для размещения постов
У The Bell большая редакция, неудобное решение замедлит работу всего медиа. В первом собранном прототипе позицию фиксированного поста надо было просто указывать координатами вида: «Помести этот пост в третью строку на вторую позицию». Конечно, это был нежизнеспособный вариант, потому что редактору по сути требовалось самому помнить, как выглядит вся страница и что еще на ней зафиксировано.
Мы быстро поняли, что лучшим решением будет визуальный конструктор страницы. Такой, чтобы, примерно как на скриншоте выше, располагать статьи и виджеты, сразу видеть возможные варианты и результат. По сути, в конструкторе можно задать раскладку карточек на странице, которую мы называем темой (layout_theme). Тема — основная сущность, вместе со всеми зависимыми описывающая внешний вид новостной ленты.
Так как тема — это объект, к которому много обращений, её структура должна быть достаточно лаконичной, но при этом читаемой и понятной. У нас это набор горизонтальных объектов: линий или вложенных тем. Линия как объект определяет, сколько и какого размера блоков виджетов стоит в… в линии :) Например:
- 3 по 33,3%
- 33,3% + 66,6%
- 50%+50%
И прочие сочетания, кратные 33% и 25%.
Сами блоки виджетов бывают нескольких видов и описываются через набор полей:
- Новость — основной тип карточек, поля: цвет или бэкграунд подложки и, собственно, заголовок*.
- Цитата: цвет подложки, автор цитаты*, краткая информация об авторе и сама цитата*.
- Цифра дня: цвет подложки, цифра*, краткое описание*.
- Молния — карточка для важных и экстренных новостей — состоит только из заголовка*.
Поле имеет тип и указание на обязательность — * в списке выше. Также есть карточки, не связанные с постами, например, блоки подписки или сторонние посты.
Реализовать фиксирование любых постов внутри тем было легко за счет того, что линии — это одномерные структуры. Надо было лишь указать, на какой позиции в какой теме и линии пост зафиксирован.
Информация о закрепленных элементах хранится в json и выглядит примерно так.
{
"route_id": 1,
"theme_id": 1,
/* route_id - id пути в адресной строке и theme_id — id тем.
Они необходимы, потому что к одной теме может быть привязано несколько наборов закрепленных элементов. */
/* То есть например по пути / и по пути /tag/ тема одна и та же, но посты закреплены по-разному */
/* Список закрепленных элементов */
"items": [
{
/* Имя модели закрепленного элемента (тут может быть пост, форма подписки, рекламный блок или что угодно) */
"fixed_model_name": "Post",
/* ID айтема модели */
"fixed_model_id": 1,
/* ID линии. */
"line_id": 1,
/* Позиция в линии */
"position": 1,
/* Индикатор, повторяется ли это закрепление при повторных отображениях этой линии в бесконечной ленте */
"repeatable":0
},
...
]
}
В визуальном редакторе линии можно легко передвигать вверх-вниз и таким образом создавать новую тему.
Вот так это выглядит в админке на Angular:
В ней можно перетаскивать посты из списка всех постов и располагать их на макете. Естественно, можно попробовать разные варианты, прежде чем выбрать окончательный и применить его. Только после этого тема отобразится на клиенте, который получит структуру страницы со всеми вложенными элементами и их типами через API.
Преимущества нового бэкенда:
- Новая админка позволяет допускать меньше редакционных ошибок, связанных с человеческим фактором, потому что расположение постов удобно проверять в визуальном редакторе.
- Его быстрее дорабатывать и внедрять новые фичи, потому что мы хорошо знаем систему, которую сами и написали.
- Новый бэкенд стабильнее работает, то есть мы больше не теряем пользователей на простоях.
- Запросы теперь проще и работают быстрее, потому что идут к нашему серверу на Laravel и в специализированную БД, а не в универсальный WP. Скорость работы сайта для посетителей портала стала выше.
Публичная часть
Сделана на Angular и максимально переиспользует код из админки. На всех страницах с постами, кроме страниц типа «Команда», сделали бесконечную ленту, которая формируется за счёт повторения темы. Закреплённые посты показываются при прокрутке снова, если в админке для них задан параметр «repeatable».
Если из ленты перейти на детальную страницу поста, то там тоже будет тема, которая настраивается так же, как и все остальные темы, и также бесконечная. Например, сейчас первую линию занимает сам пост, дальше блок три по 33,3% и снова статья. И при этом, в зависимости от того, какая статья из бесконечной ленты сейчас на экране, меняется url. Кроме того, в текст поста, который приходит с бэкенда в виде HTML, можно встроить Angular-компоненты, например, форму подписки на рассылку.
Все темы на сайте The Bell свёрстаны на гридах.
Релиз и результаты переезда
За два месяца у нас, конечно, получилось то ещё чудовище Франкенштейна. Мы написали API для переезда на новый стек, но посты пока что создаются по-прежнему в админке на WP, синхронизируются с базой данных, и тогда уже в новой админке можно управлять их положением на странице.
Как бы то ни было, к оговоренному сроку фронтенд был готов и мы начали постепенно раскатывать его на пользователей, наращивая трафик. Это было нужно, чтобы отловить возможные баги, пока они не повлияли на большое число пользователей, и наш отдел эксплуатации легким движением команд в консоле настроил нам это.
Даже такой монстрик позволил, во-первых, за короткий срок решить задачу бизнеса, а во-вторых, существенно снизить нагрузку как на БД, так и на CPU. Если до переезда сайт мог упасть из-за крайне медленных запросов в таблицы WP, где все метаданнные (например, категории, тэги, картинки и т.д.) находятся в одной и той же таблице, а также в одной таблице хранятся посты и десятки (!) ревизий этих постов. То после переезда проблем с базой не было ни разу.
To be continued
Новый дизайн мы выкатили примерно полгода назад и теперь в режиме небольших доработок постепенно переносим все инструменты на новый движок и дописываем админку. Как это обычно бывает, продуктовые фичи отнимают почти всё время и они на виду, а внутренние доработки не всегда видны со стороны заказчика, но нужны для дальнейшей миграции и развития. Поэтому мы стараемся разгребать техдолг. В ближайших планах внедрить ssr и фиды на нашем бэкенде (сейчас это все ещё на стороне WP) и перевезти редактирование постов на новый редактор. А также довести до продуктового использования заложенную механику вложенных тем.
Послесловие
Закончить статью хочу нетехническими выводами о пользе гибкого подхода, в которой мы еще раз убедились на примере этого проекта:
- Если ваша самая оптимистичная оценка срока разработки в 3-5 больше, чем то, что нужно бизнесу, то это НЕ значит, что ничего не получится. Необходимо искать альтернативные варианты.
- Большой переезд — это не обязательно два года работы. Можно реализовать самое необходимое в новых модулях (или сервисах) на новом стеке и постепенно переносить старое и допиливать фичи. Это, может быть, не самое удобное и простое решение для разработчиков, но оно рабочее, способствует гибкой разработке и не заставляет пользователя резко отказываться от привычных инструментов.
- В условиях сжатых сроков большое значение имеет организация работы. Такие, казалось бы, очевидные моменты, как налаженная коммуникация, быстрое решение блокеров и слаженная работа кросс-функциональной команды могут быть решающими.
- Мы пишем код не для себя, а для того чтобы он решал бизнес-задачи. Лучше потратить время и разобраться в нуждах пользователя (для нас это не только посетители сайта The Bell, но и редакция медиа), чем написать идеальный код, которые делает что-то не то.
- Взять и сделать сразу всё идеально в реальном мире, к сожалению, невозможно. Вам всегда будет хотеться что-то переделать и улучшить. И это хорошо, потому что помогает не стоять на месте.
Мы в ITSumma довольно много работаем с медиа, накопили опыт и в разработке с нуля, и в поддержке и доработке проектов на разных стеках. Напишите в комментариях, если интересна эта тема, — постараемся поделиться собранными граблями и удачными решениями в новых постах. И не стесняйтесь задавать вопросы.
devlev
Жалко что о технических деталях реализации не сказано почти ни слова, а очень хотелось бы.
Очень большой Time to Interactive — на телефоне, после показа шапки, очень долго ничего не проихсодит. Я вижу секунд 5-10 просто шапку с логотипом и просто чистый лист. По ощущению, идет компиляция страницы для первоначального отображения. Причем нагрузка на трафик не сильная, а вот нагрузка на проц просто чудовищная. Такая же проблема хорошо заметна и на десктопе, если немного опустить скорость работы процессора.
Определенно стоит провести оптимизацию показа первого экрана. Мне кажется слишком много там сейчас выполняется фоновых действий, которые съедают ресурсы проца, откладывая первый показ.
По возможности отложить загрузку модулей, которые не нужны для первого показа. Например на главной не обязательно знать как рендерить конкретную новость, а в новости не обязательно знать как рендерить главную. Здесь лучше всего использовать модель загрузки lazy load module
Пред компиляции готовых HTML страниц нет — это конечно плохо.
Общий вывод:
Плиточный дизайн в стиле медузы конечно хорошо. Отсутствие пред компиляции страниц и очень тяжелые скрипты рендера приводят к большим задержкам первого показа. Сайт кажется очень тяжелым, но при этом ничего такого сверх тяжелого на нем я не вижу. Если выявить проблемы со скоростью рендера, то это, мне кажется, может существенно сократить время первого показа.
j30att Автор
Спасибо за уделенное время, работу над оптимизацией конечно же ведем, жаль что не такими темпами, как хотелось бы, но все будет и пререндер и снижение Time to Interactive до вменяемых значений.