![Картинка сгенерирована с помощью ChatGPT](https://habrastorage.org/getpro/habr/upload_files/63c/715/c9e/63c715c9ed02ab9710c50e5934b0117e.png)
Переезд большого сервиса с Perl на Golang едва ли кому‑то покажется простой задачей. А теперь представьте, что это главная страница Яндекса, на которую ежедневно заходят миллионы пользователей. И что продукт постоянно дорабатывается, а значит, нельзя взять и остановить разработку на пару лет переезда. Представили? Сложно? А вот, оказывается, всё возможно.
Привет, Хабр! Меня зовут Вячеслав Круглов. Я руковожу одной из команд разработки бэкенда главной страницы Яндекса. Расскажу, как мы переписывали бэкенд с Perl на Go, поделюсь интересными подробностями переезда, а также сравню компоненты и продуктовые блоки. Эта статья — расшифровка моего доклада на GolangConf 2024. Посмотреть запись выступления вы можете на Ютубе.
Перед началом хочу сделать важную ремарку. Над переездом Главной страницы трудилось множество людей. Выражаю огромную благодарность всем, благодаря кому появилась эта статья.
Зачем нам понадобилось менять язык
Главную страницу ya.ru видели многие, но это далеко не единственное, чем мы занимаемся. В техническом смысле это отдельный сервис, который работает в разных странах и обслуживает множество доменов. А помимо веб‑страниц бэкенд обслуживает разнообразные приложения под iOS и Android, NTP (New Tab Page) в разных браузерах, и еще несколько десятков вспомогательных ручек: для установки cookies, сохранения настроек, получения конфигов, и так далее.
Короче говоря, бэкенд у нас очень большой.
Мы, как сервис, родились примерно 25 лет назад. И тогда Go ещё не было даже в зачатке. Поэтому писали на технологии, которая хорошо подходила под те задачи в то время — Perl. До переезда на Go в нашем сервисе на Perl было примерно 1 миллион строк кода и десятки тысяч RPS.
Давайте заглянем под капот нашей системы на примере главной страницы Яндекса в России ya.ru. На странице есть данные, которые мы называем продуктовыми блоками. Это данные из внешних сервисов: погода, котировки валют, и многое другое. Набор этих данных может отличаться в зависимости от домена, страны или региона.
![Продуктовые блоки на странице ya.ru Продуктовые блоки на странице ya.ru](https://habrastorage.org/getpro/habr/upload_files/8e0/73e/851/8e073e851579585061291edc094941b6.png)
Упрощенно флоу обработки запроса главной страницей выглядит так: мы получаем запрос пользователя, делаем подзапросы в источники — другие сервисы Яндекса —, получаем их ответы, обрабатываем и отдаём верстке. Всё быстро, надёжно, отказоустойчиво.
И Perl был для этого хорош, пока не появились проблемы:
Трудности найма: язык старый и людей, которые его знают или учат, мало.
Язык почти не развивается: на Perl не пишут новых библиотек или инструментов.
Много legacy, сложно поддерживать: за всё время существования сервиса накопилось много legacy кода, который тяжело поддерживать.
Сложный синтаксис, отсутствие типизации: это тоже доставляет неудобства. Например, люди, пишущие на Go, с трудом смогут понять, что на иллюстрации ниже написано в сигнатуре функции:
sub respond ($;$$@) {
my ($req, $headers, %args) = @_[0, 2 .. $#_];
return undef unless ref $_[1]
}
Или ещё один пример, на котором кроме слова stack
тоже мало что можно разобрать:
@$$out = map { _push_to_stack($stack, \$_, \(my $o = {}), \$s); $o } @$$in;
А вот еще один пример реального кода из нашего проекта. Конечно, он не весь такой. Но для подобных участков мой коллега придумал забавное определение: стиль кода «кошка прошлась по клавиатуре»:
($template =~ m, $,o) ||
($parts[$i] =~ m,^ ,o) ||
(($template =~ m,<[^<>]+$,o) &&
($parts[$i] =~ m,^>,o)) ||
(($template =~ m,%\]$,o) &&
($parts[$i] =~ m,^\[%,o))
Эти причины и привели к тому, что мы решили: Perl нам больше не подходит, и начали выбирать новый язык.
Как выбирали новый язык
Для начала мы составили список требований к новому языку:
популярный;
подходит для высокой нагрузки;
поддерживается внутри Яндекса, чтобы интегрироваться с системами сборки;
наличие хотя бы минимальной экспертизы в команде, чтобы прямо сейчас начать что‑то делать без найма дополнительных людей;
желательна статическая типизация, потому что её отсутствие часто мешает.
Изначально был выбран С++. Но когда начали переписывать главную страницу, оказалось, что разрабатывать на этом языке быстро не получается. Нового кода на Perl в единицу времени появлялось больше, чем мы переписывалось на «плюсы». График не сходился, эксперимент признали неудачным, и мы добавили новое требование:
Простота разработки, чтобы можно было быстро писать код.
«Плюсы» по этому критерию не подходили, и уже в следующей итерации мы выбрали Go.
Начали переезд
Для примера покажу процесс переезда на Go ручки бэкенда, которая обрабатывает запросы за веб‑страницей. В других ручках (для мобильных приложений, NTP, и пр.) процесс будет отличаться в деталях, но в общем останется таким же.
До начала переезда у бэкенда была примерно следующая схема: запрос приходит из балансера, попадает в Nginx, и далее в сервис, объединяющий бэкенд и серверную верстку (Perl+Front). Внутри этого сервиса Perl готовит json с данными и передаёт их в вёрстку, которая отвечает на запрос в формате HTML.
![Упрощенная схема бэкенда до начала переезда на Go Упрощенная схема бэкенда до начала переезда на Go](https://habrastorage.org/getpro/habr/upload_files/bb4/9ce/e75/bb49cee7578b8dfe3f03ca365b4953a8.png)
Важно отметить: основная сложность в нашей системе — это быстро сделать подзапросы в множество внешних по отношению к нам сервисов. Для этого в Perl была реализована крутая транспортная система.
Прежде, чем переписывать это всё на Go, мы задумались, стоит ли нам переписывать транспортную систему. Решили посмотреть, какие уже есть готовые инструменты. Оказалось, что в Яндексе есть готовый транспорт AppHost. К тому же, часть внешних источников, к которым мы обращаемся, уже находились под ним. И, самое важное, его можно добавить как обвязку, оставив Perl.
Внедрили AppHost
![](https://habrastorage.org/getpro/habr/upload_files/68e/2f8/ee7/68e2f8ee7ef3248c6e52a47dbd0267f5.png)
AppHost — это система управления сетевыми запросами. Расскажу в общих словах, как он работает. Более подробно можно прочитать в другой статье.
Балансер делает запрос в AppHost. AppHost роутит его между разными сервисами, основываясь на описании в виде графа.
Граф описывается в json в виде узлов и связей между ними.
Каждый узел — это связка бэкенд + путь запроса в нём.
Ребро между узлами — это зависимость. То есть, какому узлу какие данные из каких других узлов нужны, чтобы запуститься.
Например, представим себе простой граф и опишем каждый узел:
![Описание узлов в графе AppHost Описание узлов в графе AppHost](https://habrastorage.org/getpro/habr/upload_files/11f/dea/8a4/11fdea8a47f1cc3799ab6e88299f374b.png)
У каждого узла есть описание зависимостей: они описывают, какие данные этому узлу нужны от каких других узлов. Это и есть ребра графа.
![Описание ребер в графе AppHost Описание ребер в графе AppHost](https://habrastorage.org/getpro/habr/upload_files/1c2/b80/c7f/1c2b80c7f6c21bae86d96ea3d892ff3f.png)
AppHost работает по сетевой схеме «звезда». То есть, он делает запросы в каждый узел по очереди в соответствии с описанием графа на json. В конце мы описываем, какие данные нужны, чтобы отдать ответ пользователю.
![](https://habrastorage.org/getpro/habr/upload_files/ed6/e68/363/ed6e6836358b991406a0c5222ce61add.png)
Нам понравилось, как это всё выглядит и работает, поэтому мы решили внедрить AppHost.
Таким образом, после внедрения AppHost у нас появился первый самый простой граф, который функционально почти не отличается от первоначальной схемы. Он состоял из одной вершины — сервиса Perl+Front — и 0 ребер.
![Первый простейший граф для AppHost Первый простейший граф для AppHost](https://habrastorage.org/getpro/habr/upload_files/13b/734/62a/13b73462abd3f739fb24f534a50252f9.png)
Далее мы разделили Perl и фронтенд на два узла, которые теперь общаются между собой по сети. Perl пересылает json для вёрстки во фронт.
![Граф с разделением Perl и Front на два узла Граф с разделением Perl и Front на два узла](https://habrastorage.org/getpro/habr/upload_files/fd9/bc9/2cd/fd9bc92cd37692756ee37fbec82f28b5.png)
Следующим шагом мы написали первый маленький узел на Go. Он делает подготовительную работу перед отправкой запросов в Perl — удаление лишних заголовков или чистку cookies.
![](https://habrastorage.org/getpro/habr/upload_files/9c3/3df/e1c/9c33dfe1cf6001cb8b23677f323f9be4.png)
Что делать с Perl?
Теперь вокруг Perl у нас AppHost, и дальше нужно было переписать логику самого сервиса. С этим была очевидная проблема: чтобы переписать сервис с Perl на Go, он не должен изменяться во время переписывания.
В идеальном мире хотелось бы оставить продуктовую разработку целиком, переписать все, а потом переключить. Но так, к сожалению, не бывает. Мы не можем себе позволить на год или два остановить продуктовое развитие сервиса. Переписывать его нужно по частям, учитывая всё, что будет меняться по дороге.
Моя любимая аналогия на эту тему звучит так: переписывать большой сервис на другой язык — все равно, что перебирать двигатель Боинга прямо в полете.
В результате мы придумали и внедрили такое решение:
Разделили бэкенд на «продукт» и «платформу».
Платформа — это часть, которая реализует базовые компоненты, нужные для работы продуктовых блоков. Например, геолокация пользователя, язык, данные об устройстве.
Продукт — это часть, реализующая сами продуктовые блоки, в которых содержатся данные для ответа пользователю.
Сначала мы переписали платформу, проведя аналогию с рельсами, а потом переписали продуктовые блоки, которые как поезд поедут по этим рельсам.
Продуктовые блоки
На странице ya.ru есть полоса с данными о погоде и котировках. Это и есть пример продуктовых блоков.
![Пример продуктовых блоков на странице ya.ru Пример продуктовых блоков на странице ya.ru](https://habrastorage.org/getpro/habr/upload_files/e47/e70/19a/e47e7019ab312836035482f28253d568.png)
Попробуем представить фрагмент графа для AppHost, который будет работать с продуктовыми источниками. В нём есть узел, который делает запросы в источники (SETUP), и узел, который обрабатывает ответы из этих источников и передаёт их во фронтенд (PROCESS).
![Фрагмент графа с продуктовыми блоками Фрагмент графа с продуктовыми блоками](https://habrastorage.org/getpro/habr/upload_files/164/81c/cb2/16481ccb2637362a0d2905401dfb26a3.png)
Продуктовые блоки с точки зрения бэкенда:
В Perl — объекты внутри json. Каждый продуктовый блок — это отдельный объект в ответе бэкенда.
В Go — protobuf. Каждый продуктовый блок — это отдельное сообщение в protobuf.
Переходя на Go, мы решили использовать protobuf вместо json. Во‑первых, protobuf легче по объему данных. Во‑вторых, он позволяет фиксировать контракт между бэкендом и фронтендом. И в‑третьих, protobuf — это ещё и нативный формат для AppHost.
Go очень способствовал решению перейти на protobuf, потому что предоставляет удобные инструменты для работы с ним, а в Perl этот формат поддерживался очень ограниченно. Например, очень пригодился protoc, который позволяет генерировать структуры на Go из proto‑описания.
Базовые компоненты
Базовые компоненты редко изменяются и нужны для всех продуктовых блоков. Например, геолокация нужна для запросов про погоду и пробки. АБ‑флаги, опции требуются вообще для всех продуктовых блоков. Поэтому базовые компоненты должны вычисляться в самом начале.
Многие базовые компоненты уже были алгоритмически реализованы в Яндексе. Например, вычисление геолокация уже было сделано в виде библиотеки на «плюсах». Чтобы это не переписывать на Go, мы решили подключить их в свой проект с помощью CGO. А чтобы сделать это ещё проще, использовали SWIG. Этот инструмент позволяет описать класс, который хотим сбиндить в Go, и биндинги генерируются автоматически.
Вернёмся к графу и поставим узел, который вычисляет базовые компоненты (INIT). Так базовые компоненты будут передаваться в продукт (участок графа обведен красным), и у нас получится почти готовый граф — целевое состояние, в которое мы хотим прийти после переезда.
![](https://habrastorage.org/getpro/habr/upload_files/efb/ef3/338/efbef3338840afd2bde8215336cb2eab.png)
Но у нас всё еще есть Perl. Мы оставили два бэкенда — Perl и новую схему с Go — и собрали новый граф такого вида. В нем бэкенды на двух языках работают параллельно:
![Промежуточный граф с параллельной работой двух бэкендов Промежуточный граф с параллельной работой двух бэкендов](https://habrastorage.org/getpro/habr/upload_files/4af/242/e13/4af242e139730fd41bf452f557207e01.png)
Мы также научили фронтенд принимать данные из двух бэкендов сразу. Если какой‑то продуктовый блок приходит из Go, фронтенд берёт его оттуда. Если в Go его нет, то берёт из Perl. Такая схема позволила сделать плавный переезд и переносить по одному блоку с одного языка на другой.
Тестирование базовых компонент
К базовым компонентам предъявляются высокие требования по отсутствию багов. От них зависят вообще все продуктовые блоки. Например, если мы ошибемся при вычислении языка, то пользователь получит что‑то такого рода:
![](https://habrastorage.org/getpro/habr/upload_files/b59/5c3/894/b595c38944123ec9fbc324a73691c66d.png)
А если ошибёмся в геолокации, то получим массу пользовательских жалоб.
Go, как язык, способствует покрытию компонентов тестами благодаря своим особенностям:
великолепный фреймворк для юнит‑тестов, которого в Perl не было;
генерация тестовых функций средствами IDE;
легко измерять покрытие;
генерация моков для интерфейсов.
Лирическое отступление про генерацию моков
Мы выбрали подход, в котором функции в качестве аргументов принимают приватные интерфейсы. Чтобы такие функции тестировать, нам нужен инструмент, который будет генерировать моки для этих интерфейсов. Посмотрим на пример: есть функция вычисления языка, которая зависит от значения в cookies, и описание интерфейса с методом, возвращающим их.
type cookiesGetter interface {
GetCookies() models.Cookies
}
func GetLocale(cookies cookiesGetter) models.Locale {
...
}
Чтобы протестировать эту функцию, нужно сгенерировать mock для интерфейса cookiesGetter. В первой итерации мы использовали для этого утилиту mockery, но впоследствии перешли на gomock.
func Test_GetLocale(t *testing.T) {
// mockery
mockCookiesGetter.On("GetCookies").Return(...)
// gomock
mockCookiesGetter.EXPECT().GetCookies().Return(...)
}
Разница в том, что в mockery название метода передаётся строковым литералом, а в gomock — просто как вызов метода. Второй подход намного лучше и удобнее, потому что лучше ловить ошибки на этапе компиляции, чем на этапе прогона тестов (это было справедливо на момент начала переезда с Perl на Go несколько лет назад; сейчас в mockery также можно использовать простой вызов метода).
Помимо этого, gomock нативно поддерживается в яндексовой системе сборки, а mockery — нет.
Но тестов оказалось недостаточно. К сожалению, в Perl не всё было покрыто юнит‑тестами, а придумать тест‑кейсы для компонент, написанных годы назад, не получалось.
Сравнение компонентов
Мы решили не ловить баги с помощью пользователей или тестировщиков. Ведь у нас два параллельно работающих бэкенда. В real‑time берём и сравниваем базовые компоненты из Go и базовые компоненты из Perl. Для этого решили написать новый узел COMPARE.
![](https://habrastorage.org/getpro/habr/upload_files/c50/b85/150/c50b851509766963fc49fd48bcb9bad3.png)
Этот узел берет json из Perl, protobuf из Go и сравнивает прямо на лету на каждом запросе. Затем разница записывается в лог. Анализируя этот лог, мы понимали, что и в каких компонентах на Go нужно исправить.
Этот подход сильно ускорил разработку, но хотелось ускориться ещё сильнее. Базовые компоненты были всё ещё в работе, разница по ним оставалась, но продуктовые блоки на Go хотелось переносить уже прямо сейчас, не дожидаясь, что базовые компоненты будут готовы на 100%.
Мы нашли решение: превратили узел COMPARE в SELECTOR, который не только сравнивает компоненты, но и выбирает верный вариант. В результате SELECTOR принимает базовые компоненты из Go и Perl, сравнивает, и если они отличаются, то в protobuf Go подставляет значение из json, который пришёл из Perl.
![](https://habrastorage.org/getpro/habr/upload_files/1f4/b87/25e/1f4b8725e9e2b9afd21d92f85d344a31.png)
Идея прикольная, и получилось здорово, но у этого подхода тоже есть проблема — линейное выполнение: сначала Perl, потом Go. Переход от параллельного к последовательному выполнению слегка замедлило время ответа сервиса.
Тогда мы решили добавить второй узел Perl только для базовых компонентов:
![](https://habrastorage.org/getpro/habr/upload_files/8c6/192/755/8c6192755f4fe2023bfab0b94b7dc1bc.png)
Мы разделили Perl на «полторы» части. Главный бэкенд на Perl оставили работать по‑прежнему параллельно с Go, в нем вычисляя все продуктовые блоки. Однако мы добавили другой узел на Perl, не такой большой и тяжелый, который вычислял только базовые компоненты.
Однако, получилось не очень. К сожалению, попытка упростить бэкенд на Perl привела к тому, что базовые компоненты в новом узле стали вычисляться неправильно. Вместо того, чтобы чинить баги, посаженные в Perl, мы решили просто временно откатиться к предыдущей схеме, в которой бэкенды работают последовательно.
Затем мы написали ещё одну сравнивалку, на этот раз для самих продуктовых блоков, уже без отдельного узла, и чуть‑чуть умнее. На схеме ниже она работает в узле PROCESS.
![](https://habrastorage.org/getpro/habr/upload_files/541/40e/f5d/54140ef5d84fe8a3b349715d821c72af.png)
У нас есть довольно развесистое описание продуктовых блоков в protobuf, в каждом из которых множество полей. Писать функции для сравнения блоков вручную было неудобно — занимает слишком много времени. Поэтому, как обычно, отдали это на откуп кодогенерации. Опять же, Go отлично этому способствует: простая утилита для кодогенерации на основании protobuf генерирует функции сравнения с соответствующим кусочком json из Perl.
Отключили Perl
Мы перенесли продуктовые блоки из Perl в Go. Далее для каждого базового компонента и продуктового блока завели АБ‑флаг, по АБ‑флагу выключили процессинг в Perl и включили в Go. Получилось не работать вслепую, а проводить АБ‑эксперименты, принимая решения по критерию неухудшения метрик.
Финальным экспериментом мы отключили Perl и убрали его из конфига графа. Финальный граф стал выглядеть так:
![Финальная версия графа после удаления Perl Финальная версия графа после удаления Perl](https://habrastorage.org/getpro/habr/upload_files/875/d2c/2c1/875d2c2c1eaa72a8784a8777f2c720e2.png)
Так мы и переехали на Go.
Результаты
Процесс занял больше трёх лет и до сих пор ещё полностью не завершён. Причём мы повторяли его несколько раз. Ведь одна из основных фишек AppHost — это возможность обрабатывать разные запросы разными графами. Поэтому запросы из веб‑сервисов мы обрабатываем одним графом, а запросы из приложений — другим. Всего у нас несколько десятков графов. Например, мы приняли эксперименты на графе с вебом, а потом сделали всё то же самое для графа приложений.
Сейчас всё самое основное уже работает на Go — веб, приложения, NTP. Однако на Perl все еще осталось несколько продуктов и множество вспомогательных ручек. Что‑то из этого мы переписываем прямо сейчас, что‑то перепишем в будущем. Какие‑то из продуктовых сервисов с течением времени потеряют актуальность и перестанут поддерживаться, например, старые версии приложений — поэтому мы их не планируем переписывать.
Каких же результатов мы добились, переписав бэкенд на Go?
Мы сэкономили вычислительные ресурсы, потому что Go расходует их оптимальнее, но честно и точно измерить экономию не получается. За три года нашего переезда многое поменялось, и сравнить состояние ДО и состояние ПОСЛЕ просто невозможно.
Плюс сократилось время ответа бэкенда примерно на 20%. Приятный бонус, хотя делали мы это всё не ради этого.
Зато мы можем померить нетехнические метрики. Например, число стажёров за год в нашей команде выросло с 1 до 10+. У нас была проблема с их наймом. Найти стажёра, который пишет на Perl, было весьма проблематично. Сейчас на команду из 15 бэкендеров приходится больше 10 стажеров каждый год. Это очень много. Молодые ребята приходят, очень быстро учатся, развиваются, многие остаются в команде.
Я пытался придумать, какой метрикой можно описать качество кода, и решил посчитать количество комментариев с WTF в коде на Perl и на Go. Оказалось, что в Perl их было 110, а в Go — ни одного.
grep -iRh --include "*.pm" ”WTF" .
# ??? WTF?
# WTF CODE?! АЫАЫАЫАЫ
# WTF??? but i beleve them
# WTF CODE?! /\s?[,;]+\s?/ => /[,;\s]+/
Также раньше мы не умели мерить покрытие тестами. Сейчас в Go мы это хорошо умеем и делаем. И это касается не только юнит‑тестов: мы разработали способ измерять покрытие функциональными и интеграционными тестами.
Даже самую сложную систему можно переписать. Go этому способствует: мы переписали на него главную страницу Яндекса! У нас всё получилось, и у вас получится.
Комментарии (35)
slog2
12.02.2025 09:25Наблюдаю как ya.ru идёт по пути mail.ru. Yandex.ru уже там. Были в принципе вполне юзабельные поисковики, а потом главная страница превратилась в какой-то трэш с кучей бесполезной рекламы. Ещё и окно с настойчивым предложением установить яндекс браузер стало вылазить. Мне это вообще не нравится. А что там внутри, Perl или Golang мне вообще без разницы.
ssj100
12.02.2025 09:25ну так если продать yandex.ru то ya.ru - должно стать им - где возьмешь точку входа на свои сервисы... кстати когда там истекает контракт на аренду yandex.ru ? 2 или 3 года напомните? так хочется чтоб это обратно переехало обратно
ganzmavag
12.02.2025 09:25Так сменится же только то, что будет открываться по этому домену. Сам тот сервис вместе с той страницей уже у VK.
ssj100
12.02.2025 09:25да - и это было стартовая страница/каталог для всего сервиса, а аскетичный ya.ru кроме как поиска/почты/переход на главную не давал.... как убрали страницу-каталог для сервисов Яндекса (а их штук 30) то теперь это что было на главной начали пихать в аскетичный дизайн и он начал разбухать
BigBeaver
12.02.2025 09:25А гению, убравшему сервисы с главной, наверное еще и премию дали.
ganzmavag
12.02.2025 09:25В той ситуации это могло быть оправданное решение - приоритетом стал не трафик на сервисы, а переманивание пользователей на новый домен.
ssj100
12.02.2025 09:25с главной,
Вы про какие? yandex.ru? Во время аренды домена yandex.ru - новые владельцы делают с ней что хотят
landedK
12.02.2025 09:25Привет вашему фронтенду, докатившемуся до маскировки банера с браузером под системные уведомления в стиле ОС (win10), даже и так уже "коммерческим" пользователям за 500р\мес. Сколько ещё вам платить?
EDIT: О, теперь, похоже новое днище - нарисовали новые стили этого главного окошка про браузер - единственная кнопка "ДА", без крестика в окне вовсе.
https://habrastorage.org/webt/dv/yp/mb/dvypmbfgwamvn8bubrw437d5w-g.png Старое аля ОС в win10: https://habrastorage.org/webt/eu/5u/9x/eu5u9xjqyf5o0fmb2zgfqbge4vy.png
BigBeaver
12.02.2025 09:25Это всё интересно и занимательно, но всё равно остается один главный вопрос - зачем вообще продолжать разработку уже давно нормально работающего продукта?
Оптимизация всяких внутренностей под всё растущий интернет вопросов не вызывает, но зачем вообще что-то делать с фронтом поисковика?
sse
12.02.2025 09:25KPI(ой, простите, мы же не в водопаде из 90х) OKR требует запускать фичи-фичулечки, иначе можно и на аттестации банан получить
DimkoD
12.02.2025 09:25Когда коту делать нечего, он лижет яйца. Когда сотрудникам крупной компании делать нечего - они занимаются сломом хорошо работающего продукта. Скажите, какие гении решили убрать идеально выверенную по функциональности страничку, где были цветом обозначены погода и пробки именно там, куда удобно смотреть, и сначала а) убрать их в дальний угол, сделав блеклыми, потом откатить, потом снова сделать погоду с низкоконтрастным шрифтом и без цветов, и убрать пробки? Мне теперь +4 клика чтобы узнать как дела на дорогах в городе. А вам - отдать мне целиком страницу карт. Зато огроменный баннер рекламы, цветной, мигающий - тут как тут! Знаете что я сделаю? Поставлю жесткую рекламорезку, и прямую ссылку на карту, чтобы на вашу главную вообще не ходить. Такая была задача, устранить пользователя?
Причём у меня платный аккаунт, что не мешает мне каждый божий день подсовывать баннер с предложением скачать ваш браузер. А на мобилке - поставить вас дефолтным поиском. Никто там из менеджеров головой не думает, что это БЕСИТ? Я платник, не бесплатный причём юзер
Была одна из лучших соцсетей в мире, вк. Ныне все в телеге, инсте, тиктоке. Яндекс решил повторить?
В качестве вишенки, я написал в обратной связи. Первый раз, когда попал под пробную выкатку. Там как обычно боты, ну мне не очень сильно надо, я через них пробиваться не стал (мы обработали +1 обращение нашим ботом бесплатно! - отрапортует маркетинг). Второй раз решил таки пробиться, пока делать нечего. Хотя бы отвечали, что учтут пожелания, как раньше было с картами - фиг там. Цитирую:
"Мы постоянно работаем над улучшением Главной страницы, чтобы сделать ее полезнее. Перед этим мы провели тестирование, а также уже некоторое время применяем такое расположение в мобильной версии Главной страницы. По результатам мы видим, что в таком формате главная страница удобнее для пользователей. (тут шла реклама их виджетов алисы - спасибо нет, мне не надо лишних приложух яндекса, и так шпионов хватает) Переключиться на прежний дизайн не получится, и мы надеемся, что со временем новый вид главной страницы станет для вас удобным и привычным "
Как вы видите, что страница стала удобней? На ней стали проводить меньше времени? Или чаще кликать по рекламе, которая больше всей полезной площади? Если вы постоянно работаете над улучшениями, то получается что раньше плохо поработали, раз пришлось всё переделать? Так значит, что и сейчас могло получиться очень плохо, и надо снова переделывать?
BigBeaver
12.02.2025 09:25Вообще, инетересно наблюдать, как люди жалуются, что трудно дорого нанять программистов, в то время, как другие занимаются вот такой ерундой просто потому, что у них уже есть фронтенд отдел.
DimkoD
12.02.2025 09:25И ставят метрикой успеха "число стажеров в команде", да
BigBeaver
12.02.2025 09:25Не знаю насчет стажеров, но последние годы меня очень сильно печет от того, что одни люди долго и методично работают над порчей интерфейсов, а другие платят им за это большие деньги.
Бывает, что от чтения про новшества в каком-то продукте возникают мысли, что общество бы в целом выиграло, если бы отдел разработки в полном составе ушел класть асфальт, оставив бы только админов, кто сервера поддерживает.
DimkoD
12.02.2025 09:25Если посмотреть историю развития верстки главной, то окажется что туда сначала напихивали всё что могли, а потом наоборот, убирали всё что могли. А юзеры как шли за строчкой поиска, так и идут. Что достаточно хорошо понимают в гугле, и на глагне гугла как был много лет только поиск, так и остается. А все сервисы живут по клику на кнопку. Хотя мне нравилось что можно бегло увидеть картину дня в повестке (пока её не фильтровали), да и погода с пробками и курсом валют - очень даже удобно и полезно. И тут вот возникает вопрос, сколько человек работали над всеми этими итерациями главной? Тестировали, рисовали, писали, согласовывали? Ради чего вся эта работа велась - чтобы сначала накидать, а потом скинуть? Что оставила после себя эта работа - пустую страницу? А зачем она нужна была? Движение есть - прогресса нет(с), говаривал герой одного фильма... Так что не могу не согласиться, то что один раз удачно сделано, может работать годами, а вот если каждый раз делать не очень... Это ж все при деле, все с работой! Культура написания софта и фич "в процессе" с одной стороны, дала большую гибкость и простоту исправления, внедрения нового, с другой - ещё ниже опустила уровень проработки до запуска. Зачем думать, что мы делаем, как, для чего, как сделать хорошо - можно запуститься, а там видно будет! А потом прибежала толпа маркетолухов, и закидала супер пупер хотелками... И снова все при деле!
BigBeaver
12.02.2025 09:25Иногда я тешу (утешаю?) себя мыслью, что где-то у кого-то в глубине отдела аналитики есть обоснвоание, что рост прибыли в результате этих изменений превышает затраты на отдел разработки. Но верится с трудом, если честно. Скорее всего дело все-таки в излишней сытости. В монструозной системе слишком трудно выделить, что приносит пользу, и потому, пока есть средства, держат все отделы занятыми просто чтобы было.
bungu
12.02.2025 09:25А помимо веб‑страниц бэкенд обслуживает разнообразные приложения под iOS и Android, NTP (New Tab Page) в разных браузерах, и еще несколько десятков вспомогательных ручек: для установки cookies, сохранения настроек, получения конфигов, и так далее.
Возможно у вас было бы меньше проблем, если бы главная страница отображала то, для чего она была создана изначально - для поиска информации. А сейчас это какой-то алиэкспресс
2Roman2
12.02.2025 09:25стиль кода «кошка прошлась по клавиатуре»
Это называется отсутствие ревью кода, когда код проверяют перед выкладыванием на тест.
количество комментариев с WTF в коде на Perl
Это тоже к код ревью и компетентности программистов, т.к. по последней строке "WTF CODE?! /\s?[,;]+\s?/ => /[,;\s]+/" видно что переписали на что-то более нормальное и WTF не убрали.
sappience
12.02.2025 09:25При этом, это тривиальное регулярное выражение. Что там может не читаться? Там всего-то полтора десятка символов. Так можно доскрестить до чего угодно. До обилия угловых скобочек, слэшей и кавычек в XML, например. Или до фигурных скобочек в C и Java. Можно это регулярное выажение переписать на что-то "более нормальное" в виде кода размером с пол-экрана, но читаться оно будет лучше только для тех, кто не знает регулярных выражений.
neenik
12.02.2025 09:25Ну что ж, я был предсказателем. В этот раз переписали главную Яндекса.
bogolt
12.02.2025 09:25Это же клон первопарельского интервью Страуструпа про создание плюсов! Не считается.
ganzmavag
12.02.2025 09:25Я пытался придумать, какой метрикой можно описать качество кода, и решил посчитать количество комментариев с WTF в коде на Perl и на Go. Оказалось, что в Perl их было 110, а в Go — ни одного.
Но это же только потому, что код пока свежий и остались люди, которые помнят TF так сделано.
apevzner
12.02.2025 09:25Я пытался придумать, какой метрикой можно описать качество кода, и решил посчитать количество комментариев с WTF в коде на Perl и на Go. Оказалось, что в Perl их было 110, а в Go — ни одного.
Может, новое поколение разработчиков просто не знает аббревиатуры WTF, и выражает эту мысль каким-то другим способом? ;)
drVit
12.02.2025 09:25ya.ru был когда-то максимально минималистичным, на нём много лет не было совершенно ничего, кроме строки поиска, а вся ненужная муть была на yandex.ru - да, хорошие были времена...
dmpink
Молодцы! Сломать идеальную страницу поиска, коей ya.ru был большую часть времени своего существования, было не просто, но вы справились.
BarakAdama
К слову, выкатили новую, более лаконичную версию. Отключил в настройках те блоки, которые лично мне не нужны. Теперь главная страница у меня выглядит так:
ssj100
Как на нее попасть ?
BarakAdama
Это новый дизайн ya.ru
ssj100
хммм почти.. удивлен
А это переедет на основную страницу Яндекса? Когда?
DimkoD
Обратите внимание, реклама яркая и контрастная, и мигает, а иконки и текст основной части страницы - блеклые и низкоконтрастные, чтобы вам было ещё удобнее!
BarakAdama
Блок рекламы отключается в настройках, как и раньше.
ssj100
А курс валют?(кстати если уж определили локацию зачем мне рубль?) а кнопка алисы? если есть микрофон в строке, а сэндвич если есть кнопка войти
И самый важный когда там истекает контракт на аренду yandex.ru ? и планируете все лишнее туда отправить?