Меня зовут Никита Неминущий, я ведущий инженер-программист финансового маркетплейса «Выберу.ру». В этой статьей я хотел бы рассказать, как на нашем сайте была реализована микроразметка и поделиться своим опытом ее доработки.
Пару слов о том, что такое микроразметка
Микроразметка сайта — это дополнительная (опциональная) разметка HTML-кода, которая помогает поисковым системам, таким как Google, Yandex, лучше понимать структуру и содержание веб-страниц. Она добавляет метаданные к контенту, чтобы поисковые системы могли более точно интерпретировать, что изображено на странице. Сама микроразметка не видна пользователю, но она значительно влияет на то, как сайт отображается в результатах поиска, так как поисковики включают данные из микроразметки в свою поисковую выдачу.
Другими словами, на полотне поисковой выдачи сайт с микроразметкой займёт больше места, чем сайт без нее, и вытеснит конкурентов. Также за счет выдачи ключевых частей контента страницы у такого сайта имеется больше шансов на то, чтобы захватить внимание пользователя и мотивировать его перейти по ссылке и открыть этот сайт.
Существуют два наиболее популярных словаря микроразметки и несколько их синтаксисов:
Schema.org — это стандарт, который разработан Google, Bing, Yahoo и Yandex. То есть это та микроразметка, которая используется поисковыми системами;
Open Graph — микроразметка, разработанная Facebook. Она используется для отображения информации в социальных сетях: определяет, как будет выглядеть пост: какое изображение, заголовок и описание будут показаны в случае, если вы поделитесь с кем-то ссылкой.
Мы сегодня поговорим о Schema.org.
Старое проблемное решение
На нашем портале прежде всего используется микроразметка из словаря Schema.org в двух вариантах синтаксиса: в меньшей степени “микроданные” и в большей “JSON-LD”.
Первый вариант менее удобный, так как данные микроразметки размазываются по HTML-разметке страницы, что засоряет её и усложняет поддержку такого кода для разработчиков.
Второй вариант представляет собой json, который вставляется в тег <script> в разделе <head> страницы. В итоге всё находится в одном месте, а значит, это легко найти, тяжело потерять и возможно, сделав раз, забыть.
Каждый объект json’а представляет собой краткое отображение представленных на странице сущностей. Например, если на странице представлен некий продукт, то для его описания существует соответствующий тип https://schema.org/Product. Все типы Schema.org включены в иерархию, а для их свойств четко определено, объекты какого типа они поддерживают.
"Ошибаться можно - врать нельзя" (с) Андрей Белоусов
Не будем греха таить и честно признаемся, что на нашем портале иногда встречаются спорные решения. И одним из таких решений была реализация микроразметки (создание json’а) путем склеивания строк.
Большими недостатками данного решения является следующее:
разработчик должен хорошо разбираться в правилах, установленных словарём микроразметки;
разработчик может легко ошибиться, размещая те типы данных и в таких местах, которые не предназначены для этого;
разработчик может легко сломать уже созданный код генерации микроразметки, потеряв где-либо скобочку или кавычку.
В 2010 году с российским с ракетой-носителем "Протон-М" произошёл инцидент: ракета разбилась из-за неверно установленного гироскопа. Ракета должна была вывести на орбиту три спутника системы ГЛОНАСС, но после старта ракета отклонилась от курса, развернулась на 180 градусов и в итоге упала в Тихий океан неподалеку от Гавайских островов.
Гироскоп, использовавшийся для управления ориентацией ракеты, был вставлен вверх ногами, что привело к тому, что система управления, полагая, что ракета со всей дури несется вниз, сделала всё, чтобы исправить её курс и направить на путь истинный. А всё из-за того, что инженеры, собиравшие ракету, испытывали трудность в размещении гироскопа на своей позиции и в итоге, воспользовавшись напильником и подточив защиту у крепления, они таки смогли его туда воткнуть.
Так вот, продолжать этот путь не хотелось и чтобы случайно не впихнуть “невпихуемое”, и был произведен поиск альтернатив. Альтернатива была найдена достаточно быстро, и из доступного в нашем стеке технологий dotNET ей оказался nuget пакет Schema.NET, который мы и решили задействовать на нашем ресурсе.
Работа строго по словарю, или как не получить ложкой в глаз
Nuget пакет Schema.NET поддерживает все основные типы и свойства словаря Schema.org, и предоставляет возможность создания микроразметки путем заполнения данных в подготовленных к сериализации моделях. Все эти модели для nuget пакета Schema.NET генерируются автоматически по заданным правилам, которые строго соответствуют словарю, и описанным в этом многостраничном документе.
То есть чтобы разработчику получить подобную JSON-LD микроразметку:
{
"@context":"https://schema.org",
"@type":"WebSite",
"alternateName":"An Alternative Name",
"name":"Your Site Name",
"url":"https://example.com"
}
Ему достаточно написать следующий код:
WebSite website = new()
{
AlternateName = "An Alternative Name",
Name = "Your Site Name",
Url = new Uri("https://example.com")
};
string jsonLd = website.ToString();
Благодаря тому, что каждому полю задан свой тип, разработчику тяжелее ошибиться, “попав ложкой себе в глаз”. Но ошибиться всё же можно, так как некоторые свойства многотипные, то есть могут содержать в себе более одного варианта типа данных. А так как C# строго типизированный язык, то реализация этой возможности имеет определенные ограничения. Чтобы их обойти, Schema.NET реализует вспомогательные типы, такие как структура Values<T1, T2>.
Вот так, например, выглядит свойство Brand в типе Product:
[JsonPropertyName("brand")]
[JsonPropertyOrder(110)]
[JsonConverter(typeof(ValuesJsonConverter))]
public Values<IBrand, IOrganization> Brand { get; set; }
Из кода видно, что свойство может принимать все модели, реализующие либо интерфейс IBrand, либо интерфейс IOrganization. Этот факт, конечно, является документацией сам по себе, но дабы сделать заполнение моделей удобным, а код наглядным: структура Values<T1, T2> реализует множество вариантов неявных приведений типов.
Одно такое неявное приведение типа выглядит таким образом:
public static implicit operator Values<T1, T2>(object[] array) => new(array);
Это позволяет вонзить в него произвольный массив и с ходу не заметить, что” бутерброд” то” без масла". На этапе выполнения никакой ошибки не будет, просто в итоговом json’е свойство окажется незаполненным.
Еще одним недочетом Schema.NET является тот факт, что все содержащиеся в нем типы данных расположены в одном и том же пространстве имен. Из-за этого, к примеру, в Schema.NET напрочь отсутствует тип PaymentCard как финансовый продукт, зато есть PaymentCard как способ оплаты. И если посмотреть на описание этого типа https://schema.org/PaymentCard в словаре, то можно заметить, что их два с одним и тем же именем, но от разных наследников.
Благо в Schema.NET все типы данных не являются закрытыми от наследования и по примеру можно создать нужный вам тип. А в остальном, прекрасная маркиза, всё хорошо, всё хорошо…
Руки в ноги — подводим итоги
Использование nuget пакета Schema.NET позволило нам:
унифицировать механизм добавления микроразметки к страницам сайта;
ускорить добавление этой самой микроразметки;
снизить порог вхождения разработчиков в данную технологию;
повысить отказоустойчивость кода.