IT-инфраструктура для бизнеса и творчества
Разработка
ITSumma

Как мы сделали новый сайт для The Bell за два месяца

Давным-давно в далекой-далекой галактике появился проект The Bell, построенный на WordPress. Постепенно проект рос и развивался, добавлялись всевозможные галочки и тоглеры, накручивались фичи.

Технический долг копился и тащил The Bell на тёмную сторону, а новые хотелки уже выходили за рамки возможностей CMS и превращали проект в колесо с костыликами вместо спиц. И тут редакция задумала обновить сайт и сделать редизайн новостной ленты.

«Что в этом сложного?» — видимо, подумали люди, не очень знакомые с техническими тонкостями, и обратились к нам за разработкой. Для нас же это поначалу напоминало анекдот: есть статичный макет, который совершенно неизвестно как должен меняться в зависимости от разных условий, и заказчик, который хочет увидеть новый сайт в работе меньше, чем через два месяца.

Рассказываем, как мы разбирались, что на самом деле нужно редакции The Bell, искали компромисс, чтобы уложиться в сроки, разрабатывали новую админку и реализовывали новые фичи.

Исходные данные

The Bell — деловое медиа, которое начиналось с ежедневной e-mail рассылки. Сейчас это ещё и основной новостной сайт, и несколько спецпроектов с отдельными площадками. Как вы поняли, сайт The Bell изначально был сделан на WordPress, что для стартапа вполне логично.

WordPress — универсальная и простая CMS. И этим, по большому счёту, всё сказано. Она хороша для прототипирования и того, чтобы быстро стартануть; там можно реализовать всё, ну или почти всё.

Но когда за несколько месяцев трафик вырос со 100 тысяч пользователей до миллиона, требовались большие усилия и кэши, чтобы WP и виртуалка, на которой он работал, не умирали. Поэтому сначала переехали на выделенный сервер и только спустя какое-то время занялись WordPress.

В подросшем продукте большее значение имеет то, сколько усилий потребуется для реализации стратегии развития и точно ли получится так же хорошо, как если делать с нуля под конкретную задачу. В случае «старого» The Bell каждая новая доработка делала реализацию всё более запутанной, громоздкой и непригодной для поддержки и рефакторинга.

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

Для кастомной реализации мы выбрали связку Angular + Laravel, потому что оба этих фреймворка уже так или иначе были задействованы в отдельных модулях проекта. Для рассылок уже использовался модуль на Laravel, который отправлял письма через Mailchimp и собирал аналитику в нашей админке. И подпроект Bell.Club был ещё раньше сделан без участия WordPress на Laravel.

Что нужно сделать

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

Для иллюстрации поместили в ленту статьи из нашего блога.

А дальше мы вместе выясняли, что должно происходить со всеми остальными статьями: бесконечная ли будет лента, как она должна обновляться и куда будут попадать новые материалы, а куда уходить более старые.

Отдельно замечу, что заказчики — классные профессионалы в медиа, но среди них нет ни одного технического специалиста. Переложить задачу из картинок и разговоров в задачи для разработки нужно было нам самим. Работали в чистом виде по Agile и по ходу дела выясняли, что и зачем хочет клиент и что ему можно предложить по этому поводу.

На такого рода черновики мы ориентировались, проектируя админку.

Сроки. Ожидание vs реальность

Итак, мы подумали, что настало время отдавать техдолг, и настроились на большое переписывание. Мы же программисты — нас хлебом не корми, дай выбросить старый код и написать всё с нуля. Но получилось всё не совсем так.

Чтобы перевезти весь проект на новый стек, нужно было переписать всё, что связано с WordPress, а именно: фронтенд и бэкенд, админку и кучу всяких мелочей типа rss, метаданных, SEO, которые в WordPress были реализованы плагинами. С учётом имеющихся ресурсов (в проекте было занято всего два разработчика) это заняло бы полгода. А заказчику новый дизайн нужен был к 1 апреля — на тот момент оставалось уже меньше двух месяцев.

Пришлось искать компромисс.

За что хвататься, чтобы всё успеть

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

Бэкенд. Админка для размещения постов

У The Bell большая редакция, неудобное решение замедлит работу всего медиа. В первом собранном прототипе позицию фиксированного поста надо было просто указывать координатами вида: «Помести этот пост в третью строку на вторую позицию». Конечно, это был нежизнеспособный вариант, потому что редактору по сути требовалось самому помнить, как выглядит вся страница и что еще на ней зафиксировано.

Мы быстро поняли, что лучшим решением будет визуальный конструктор страницы. Такой, чтобы, примерно как на скриншоте выше, располагать статьи и виджеты, сразу видеть возможные варианты и результат. По сути, в конструкторе можно задать раскладку карточек на странице, которую мы называем темой (layout_theme). Тема — основная сущность, вместе со всеми зависимыми описывающая внешний вид новостной ленты.

Так как тема — это объект, к которому много обращений, её структура должна быть достаточно лаконичной, но при этом читаемой и понятной. У нас это набор горизонтальных объектов: линий или вложенных тем. Линия как объект определяет, сколько и какого размера блоков виджетов стоит в… в линии :) Например:

3 по 33,3%
33,3% + 66,6%
50%+50%

И прочие сочетания, кратные 33% и 25%. Сами блоки виджетов бывают нескольких видов и описываются через набор полей:

  • Новость — основной тип карточек, поля: цвет или бэкграунд подложки и, собственно, заголовок*.
  • Цитата: цвет подложки, автор цитаты*, краткая информация об авторе и сама цитата*.
  • Цифра дня: цвет подложки, цифра*, краткое описание*.
  • Молния — карточка для важных и экстренных новостей — состоит только из заголовка*.

Поле имеет тип и указание на обязательность — * в списке выше. Также есть карточки, не связанные с постами, например, блоки подписки или сторонние посты.

Реализовать фиксирование любых постов внутри тем было легко за счет того, что линии — это одномерные структуры. Надо было лишь указать, на какой позиции в какой теме и линии пост зафиксирован.

Информация о закрепленных элементах хранится в json и выглядит примерно так:

В визуальном редакторе линии можно легко передвигать вверх-вниз и таким образом создавать новую тему.

Вот так это выглядит в админке на 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 довольно много работаем с медиа, накопили опыт и в разработке с нуля, и в поддержке и доработке проектов на разных стеках. Напишите в комментариях, если интересна эта тема, — постараемся поделиться собранными граблями и удачными решениями в новых постах. И не стесняйтесь задавать вопросы.

(function () { let cdnUrl = `https://specialsf378ef5-a.akamaihd.net/SelectelBranding/images/` let previousArticleNumber = null let currentArticleNumber = 0 let platform = 'Desktop' let articles = [ { name: 'camera', url: `${cdnUrl}CameraCat`, text: 'умную камеру для\u00A0наблюдения за\u00A0котиками', link: 'https://vc.ru/selectel/306690', num: 3 }, { name: 'chill', url: `${cdnUrl}ChillCat`, text: 'трекер, который подскажет, когда пора отдохнуть', link: 'https://vc.ru/promo/288561-eye-tracker', num: 1 }, { name: 'cloud', url: `${cdnUrl}CloudCat`, text: 'котика: даёшь ему «пять», а\u00A0он делает бэкап в облако', link: 'https://vc.ru/dev/294799-maneki-neko', num: 2 } ] let buttonCycle = document.querySelector('.button--cycle') let buttonChoose = document.querySelector('.button--choose') let buttonMobile = document.querySelector('.button--mobile') let textField = document.querySelector('.selectel-footer-subtitle') let imageAgent = document.querySelector('.image--agent') let banner = document.querySelector('.selectel-footer') buttonCycle.addEventListener('click', cycleClick) buttonChoose.addEventListener('click', () => sendEvent(`Promo ${articles[currentArticleNumber].num} Left`, 'Click')) buttonMobile.addEventListener('click', () => sendEvent(`Promo ${articles[currentArticleNumber].num} Left`, 'Click')) let media = window.matchMedia("(max-width: 570px)") media.addEventListener('change', matchMedia) function matchMedia() { if (media.matches) { platform = 'Mobile' } else { platform = 'Desktop' } update() } matchMedia() function cycleClick(event) { sendEvent(`Promo ${articles[currentArticleNumber].num} Right`, 'Click') if (event) { event.preventDefault() event.stopPropagation() } window.open('https://vc.ru/tag/selectelDIY', '_blank') //cycle(event) } function cycle(event) { // incrementArticleNumber() textField.innerHTML = generatedText() imageAgent.src = articles[currentArticleNumber].url + platform + '.svg?3' imageAgent.setAttribute("class", "") imageAgent.classList.add('image--agent', articles[currentArticleNumber].name) banner.href = articles[currentArticleNumber].link } function update() { banner.href = articles[currentArticleNumber].link imageAgent.src = articles[currentArticleNumber].url + platform + '.svg' textField.innerHTML = generatedText() } function incrementArticleNumber() { previousArticleNumber = currentArticleNumber if (currentArticleNumber >= articles.length - 1) { currentArticleNumber = 0 } else { currentArticleNumber++ } } const sendEvent = (label, action = 'Click') => { const value = `SelectelDIY — loc: Footer — ${label} — ${action}`; if (window.dataLayer !== undefined) { window.dataLayer.push({ event: 'data_event', data_description: value, }); } }; function generatedText() { let defaultText if (platform === 'Desktop') { defaultText = `Мы тут собрали %text%. Хотите научим?` } else { defaultText = `Мы тут собрали %text%.` } return defaultText.replace('%text%', articles[currentArticleNumber].text) } function getRandom(min, max) { min = Math.ceil(min) max = Math.floor(max) return Math.floor(Math.random() * (max - min + 1)) + min } (function create() { currentArticleNumber = getRandom(0, articles.length - 1) cycle() let page = document.querySelector('.page--entry') if (page) { function insertAfter() { let parents = page.querySelectorAll('[data-id="7"]') let referenceNode = parents[0] referenceNode.parentNode.insertBefore(banner, referenceNode.nextSibling); loaded() } setTimeout(() => insertAfter(), 0) } }()) function loaded() { banner.classList.add('loaded') } loadImages([ `${cdnUrl}CameraCatDesktop.svg`, `${cdnUrl}ChillCatDesktop.svg`, `${cdnUrl}CloudCatDesktop.svg`, `${cdnUrl}CameraCatMobile.svg`, `${cdnUrl}ChillCatMobile.svg`, `${cdnUrl}CloudCatMobile.svg?3`, ]) function loadImages(urls) { return Promise.all(urls.map(function (url) { return new Promise(function (resolve) { var img = document.createElement('img'); img.onload = resolve; img.onerror = resolve; img.src = url; }); })); } }())
0
6 комментариев
Популярные
По порядку
Написать комментарий...

хорошо, что вы существуете, спасибо вам
Благодаря таким компаниям заказчики понимают геморойность дел и привыкают платить дольше. Обязательно перепишите еще потом админку с вордпресса на ангуляр.
А потом раз в год переписывайте ангуляр на новую версию ангуляра. Через три года все перепишите на svelte, и так по кругу.
А я пойду пока настрою балансировку и master-slave репликацию в БД.

5

Чисто из любопытства. Сколько вам за "это" заплатили, хотя счас будет это коммерческая тайна и что это за вопросики.
Почему не использовали имеющиеся CMS? 
Какие фичи не позволили этого сделать?
Про перенос бд с вордпресса, вопросов нет.

3

Нет ничего постыдного писать / переписывать и зарабатывать свои рублики. Люблю повторять фразу, что все фреймворки служат 2м целям, делать из проекта на миллиард, проект на миллион, и из проекта за сто баксов — проект на пару миллионов. Пользуетесь тем что эффективнее сэкономит ваше время и деньги.

1

Ghost делает все это гораздо лучше и из коробки. Работает blazing fast. Велосипед уже изобретен.
Не благодарите.

0

Не могу не отметить, что формулировка "Ghost делает все это гораздо лучше" уместна только тогда, когда вы опробовали оба решения.

0

Кастомные темплейты и типы контента, отличный визуальный редактор с упором на большую редакцию, amp страницы, отличная скорость работы, масштабируемость, api если хочется свой фронт навелосипедить, из коробки seo и многое другое. Что-то не учел? По сути всё ,что надо было сделать - темплейт. В статье прямыми словами - у заказчика ни одного технаря, который бы отвадил делать самострой, а разработчики - любители писать с нуля, что хлебом не корми. А теперь это поделие - мертвый груз или воронка для сжигания денег. Не каждая редакция обладает ресурсами для развития собственного решения. ИМХО.

0
Читать все 6 комментариев
Лайфхак в подборе: как ATS-системы помогают экономить время и бюджет рекрутеров

Процесс рекрутинга существенно не отличается от компании к компании. Есть несколько типичных шагов, которые проходит рекрутер: размещение вакансии на джоб-бордах, поиск соискателей по базам, согласование кандидатов с заказчиками, собеседование, выдача и проверка тестового задания, проверка кандидата службой безопасности.

Путин поручил разработать вариант налогового вычета для частных инвесторов при долгосрочных вложениях в российские акции Статьи редакции

Фондовый рынок должен не только финансировать инвестиционные проекты, но и приносить доход гражданам, считает президент.

Мвидео, облажались. Дважды

1. Мультиварка

Это Элви Рэй Смит: он мечтал создать анимационный фильм на компьютере, соосновал Pixar, но ушёл из компании из-за Джобса Статьи редакции

Смит создал альфа-канал, который используется в Photoshop и других редакторах, работал в Xerox и LucasFilm и убеждал всех, что за компьютерной графикой будущее, однако всерьез его никто не воспринимал – кроме Стива Джобса.

Минэкономразвития РФ приняло предложения РСПП по совершенствованию рынка интеллектуальной собственности

На актуализации плана дорожной карты ТДК (трансформация делового климата) «Интеллектуальная собственность» в соответствии с пожеланиями бизнес-сообщества настоял первый заместитель председателя правительства Андрей Белоусов.

«Мегафон» заблокировал 36 тыс. ₽ на 2 недели по ФЗ № 115

Являюсь абонентом Мегафона второй десяток лет. Несколько лет назад завёл себе карту Мегафон-банка. Очень нравилось, и рекомендовал всем, так как:

На сайтах с эквайрингом от ПСБ появился Yandex Pay

Покупатели с аккаунтом «Яндекса» смогут оплачивать покупки, не вводя данные карты.

Мвидео отказал в замене товара ненадлежащего качества. Битый телевизор

14.11.2021 доставка магазина Мвидео привезла мне домой телевизор LG. При приёме телевизора от доставщиков никаких недостатков не обнаружили ( или не заметили, потому что телевизор был весь запотевший). Включать для проверки тоже не стали из-за запотевания. В тот же вечер через несколько часов телевизор повесили и попытались включить, он не…

Kornia - Python библиотека для обработки изображений в задачах CV

В этой статье я хотел бы познакомить читателей с библиотекой для ЯП python — Kornia, имеющей богатый функционал в области computer vision. Библиотека написана с использованием pytorch, в ее основе лежат готовые решения, такие как torchvision, PIL, skimage, tf.image, OpenCV. В Kornia реализована возможность выполнения вычислений не только с…

null