Сегодня произошло одно из самых значительных обновлений Яндекс.Карт за всю историю. Во-первых, Народная карта объединяется с основной, а значит каждый сможет сам быстро и легко добавить на карту свой дом или поправить неточность. Результаты изменений будут доступны всем — на Яндекс.Картах, а также в мобильных Картах и Навигаторе. И во-вторых, Яндекс.Карты получили новый интерфейс, о бета-версии которого мы когда-то уже рассказывали на Хабре на ранних этапах работы над ним (большое спасибо за все замечания и советы, которые тогда были высказаны).
Под катом я расскажу о том, как мы работали над интерфейсом, как решили задачу быстрой загрузки объектов в браузере, придумывали и реализовывали новые инструменты, которые должны защищать правки пользователей, как сделали так, что новая жизнь вообще стала возможной, и почему карты теперь будут обновляться быстрее, чем когда бы то ни было и при этом будут точными, и многое другое.
Первая версия Народных карт была запущена ровно пять лет назад — 8 апреля 2010 года. В то время Яндекс.Карты полностью зависели от поставщиков картографических данных. Запуская Народную карту, мы хотели дать людям возможность самостоятельно влиять на полноту и качество данных. Реальность превзошла все наши ожидания: за эти пять лет усилиями пользователей отрисовано множество городов и населенных пунктов РФ и ближайшего зарубежья. При открытии новых развязок исправления в карту вносятся в течение дня, а чаще всего — часа.
Так выглядела первая версия Народной карты в 2010 году
Но мир не стоит на месте, и нас ждал следующий вызов — сделать из Народной карты инструмент, с помощью которого даже не знакомые с картографией люди, могли бы создавать профессиональные карты, пригодные для использования в автомобильной маршрутизации.
Но, ставя себе такую цель, мы осознавали и задачи, которые нам придется решить. Во-первых, сделать интерфейс новой Народной карты настолько интуитивным и дружелюбным, чтобы с ним мог работать любой человек. Во-вторых, нужно было научиться редактировать очень большие объекты в браузере. В старой Народной карте при загрузке объекта с большим количеством узлов (>20K) браузер подвисал. В новой Народной карте, какой мы ее задумали, такое неприемлемо.
И в-третьих, так как после сегодняшних изменений мы даем людям редактировать данные, которые потом увидят десятки миллионов пользователей Яндекс.Карт, необходимо ещё надежнее защитить результаты труда «народных» картографов от недобросовестных пользователей, которых мы называем вандалами.
Работа над интерфейсом
В процессе работы мы определили, что у нас есть две группы пользователей:
- новички, которые ни разу не пробовали редактировать карту;
- опытные пользователи, к которым можно отнести картографов и активных пользователей Народной карты.
Для нас это означало, что интерфейс должен быть простым и понятным для первых, и должен удовлетворять требованиям гибкости и удобства редактирования опытных пользователей. Но как этого добиться?
Мы выдвинули гипотезу, что интерфейс должен быть двухуровневый. Первый уровень для совсем новых пользователей, чтобы они могли выполнить простые сценарии, а второй уровень для опытных, когда требуется сделать что-то более сложное. Примеры я приведу ниже.
Чтобы проверить эту гипотезу, мы изучили пользовательские сессии на Народной карте и выяснили, что среди самых популярных сценариев создания и редактирования данных выделяются следующие:
- редактирование организации;
- редактирование здания и его адреса;
- редактирование простых площадных объектов (парк, газон, территория школы или детсада);
- редактирование дороги.
А раз с этих сценариев начинается знакомство с редактированием карты, значит, они должны быть суперлогичными и интуитивными. Если человек с ними разберется, и ему будет все еще интересно редактировать карту, тогда он может нажать кнопку «Показать еще». За этим кликом пользователь обнаружит больше инструментов, с которыми ему придется разобраться, — почитать инструкции, спросить совета более опытных пользователей.
В процессе проектирования пользовательского интерфейса мы сразу столкнулись с необходимостью динамических прототипов. Оказалось очень тяжело обсуждать сложные сценарии редактирования, имея на руках статические макеты. Возникало множество вопросов вида: «А что будет, если я нажму вот эту кнопку и сделаю вот это?» Когда сценариев очень много и с каждым нажатием кнопки они ветвятся и пересекаются, «динамические прототипы» — отличное решение. Они помогают быстро и наглядно продемонстрировать, как должно происходить взаимодействием пользователя с интерфейсом.
С них мы и начали тестирование пользовательского интерфейса. Первыми нашими испытуемыми стали наши разработчики. Как только мы им продемонстрировали желаемое взаимодействие пользователей с нашим продуктом, услышали: «Мы не понимаем, как сделать такую магию. Давайте сначала сделаем просто с точки зрения разработки, а потом будем пробовать упрощать интерфейс для пользователей».
Хоть какое-то решение лучше, чем никакого. Поэтому мы переделали все прототипы интерфейсов до понятной нам реализации. В итоге у нас появился прототип, в котором все данные редактируются, но местами неудобно и нелогично.
Давайте лучше объясню на примере. Возьмём озеро Байкал. Как удобно редактировать простому пользователю? Байкал — это площадной объект, поэтому естественно его редактировать как площадной объект. Но есть проблема — Байкал состоит из 527 замкнутых контуров (сам контур плюс вырезанные острова), более чем 59 200 узлов и к тому же имеет общие границы с множеством рек.
Если попытаться загрузить все эти данные с сервера пользователю в браузер — все повиснет. Поэтому у нас в данных все представлено несколько иначе.
Есть объект гидрографии «озеро Байкал», у которого есть только название, и нет геометрии.
При выборе объекта показываются все его контуры
Есть связанные с этим объектом замкнутые контуры, которые представляют собой внешний контур озера и вырезанные дырки под острова. Они имеют атрибут «внешний» или «внутренний» (контур), но так же не имеют своей геометрии.
Обратите внимание, я выбрал только один контур — подсветка всех остальных пропала
Все эти контуры состоят из одного или чаще множества участков границ гидрографии, которые и представляют собой фактическую геометрию.
На картинке подсвечен один из участков внешнего контура Байкала
Это значит, что чтобы создать такое озеро, мы должны:
- нарисовать фактические границы озера и всех островов;
- создать объект «озеро Байкал» и добавить к нему контуры, собранные из заранее нарисованных участков границ.
Вот так видят и создают данные наши картографы. И такой вариант редактирования данных мы выбрали в качестве отправной точки для поэтапного улучшения интерфейса.
В тот момент, когда первая версия интерфейса редактирования была разработана и поднята на тестовом сервисе, мы всей командой отправились его тестировать. По результатам тестирования мы снова собрались и обсудили, что в этом способе редактирования можно улучшить.
Первое, с чем мы определились — это то, что рисование Байкала — редкий случай, и пользователь-новичок вероятнее пойдет рисовать что-то проще. К примеру, местный пруд. А это тривиальный случай, и пруд будет состоять из одного объекта гидрографии, одного контура и одного участка границ. Так давайте в таких случаях он будет его создавать как простой площадной объект без всей этой мороки с участками границ и контурами, а мы его сохраним, как три отдельных объекта (объект гидрографии, контур, граница). Сказано — сделано.
Создание границы объекта, контура и объекта гидрографии в один прием
А если получается так создавать тривиальные объекты, то давайте тривиальные объекты так же редактировать. Готово!
Редактирование объекта, состоящего из одной границы объекта, одного контура и объекта гидрографии
Отлично! А давайте так же редактировать и те объекты, которые состоят из одного контура, но нескольких участков.
Редактирование объекта, состоящего из трех границ объекта, одного контура и объекта гидрографии
Отлично. А давайте так же редактировать и объекты с «общими границами», и те, у которых много контуров. А вот тут не получится. В случае объекта, у которого есть общие с другими объектами границы, мы не знаем, что хочет сделать пользователь — подвинуть общую границу или отвязать объект от этой общей границы. А в случае объектов с большим количеством контуров необходимо понять, какой контур пользователь будет сейчас редактировать. Значит, необходимо продумать сценарии для этих случаев и реализовать инструменты выбора и редактирования.
Пруд, у которого один внешний контур, несколько внутренних и внешний контур имеет общую границу с каналом
Окей, теперь мы поняли, где проходит граница между простыми и сложными сценариями редактирования. Но простые случаи у нас уже реализованы, и… вы не поверите, они выглядят почти так, как спроектировали интерфейсы в самом начале проекта. Просто магия стала понятной и реализуемой.
В ходе следующих исследований мы придумали, как сделать понятными и сложные сценарии редактирования данных, но решение получилось не настолько элегантными, как нам хотелось. Мы научились обнаруживать, когда пользователь сталкивается со сложным сценарием. Сервис предлагает ознакомиться с правилами редактирования смежных объектов и даже подсказывает пользователю, где, возможно, произошла ошибка.
Показывается ошибка со ссылкой на документацию и маркер, где обнаружена ошибка
Скорость загрузки
С базовыми интерфейсами разобрались, но, продолжая разговор об озере Байкал, надо понять, как мы будем его редактировать, если от 20K узлов, загруженных в браузер, компьютер уже зависает?
Давайте эту проблему решать тоже поэтапно. Редактировать можно атрибуты и геометрию, причем, если контуров много, то за один этап можно отработать геометрию только одного контура:
Редактирование доступно только с определенного масштаба карты, и пользователю предлагается выбрать, геометрию какого контура он хочет отредактировать
И вот, когда пользователь выбирает контур для редактирования, снова срабатывает «магия» — если контур небольшой (к примеру, внутренний контур под остров), мы подгружаем его полностью и даем редактировать как простой площадной объект.
Случай редактирования простого контурного объекта
А если контур очень большой, то подгружаем только видимые участки границ и позволяем их редактировать. Если пользователь переместит карту и на ней будут находиться только новые участки границ, мы их тоже загрузим для редактирования. Таким образом, пользователь в почти простом режиме может редактировать сложные объекты, даже не замечая этого.
Загружен только один участок границы объекта из множества
Таким хитрым образом мы обошли ограничения браузера — скорость подгрузки данных для редактирования и ограничения на количество одновременных точек, доступных для него.
Защита правок
Следующей важной задачей для нас было сделать сервис устойчивым к пользователям, которые портят данные. В старой Народной карте уже были реализованы меры для противодействия им. Но в новой любой желающий сможет редактировать данные, которыми пользуются десятки миллионов пользователей. Мы должны сделать все возможное, чтобы испортить их было нельзя.
Для этого мы сменили систему модерации всех правок пользователей — с постмодерации на премодерацию. То есть с сегодняшнего дня все правки в Народной карте будут проходить обязательное проверку модераторами. Мы надеемся, что это еще улучшит качество данных.
У нас нет задачи откатить все данные на определенную дату или ревизию, у нас есть задача — удалить только часть пользовательских правок, сохранив при этом все остальные, да еще и сохранить целостное состояние данных. Результатом стала наша внутренняя разработка хранения данных, их ревизий и отдельного представления.
Одним из важных преимуществ нашей системы является то, что мы научились хорошо контролировать целостность данных. К примеру, я редактирую участок дороги и изменяю его геометрию.
Редактирование геометрии участка дороги напрямую
Потом перехожу в соседний узел, где пересекаются несколько участков дорог, и пробую редактировать его, но косвенно правлю геометрию предыдущего участка.
Редактирование геометрии участка дороги косвенно
Значит, у меня получаются две связанные правки. Если бы мы не умели контролировать и версионировать такие косвенные правки, то мы бы не смогли вернуть объект в то состояние, в котором он был до косвенной правки. А значит, нужно было бы запрещать все косвенные правки поверх прямых.
В принципе, в таком решении нет ничего страшного, некоторые картографические сервисы так и делают. Но такое решение полностью исключает возможность отредактировать дорожную развязку, так как при правках графа дорог всегда происходят косвенные изменения данных.
Еще одна важная тема, связанная с версионирование данных, это визуальное представление diff правки. Всегда можно посмотреть, как выглядит последняя версия объекта, но для удобной модерации важно видеть, как объект выглядел до правки и после правки. Особенно важно сделать такой diff для геометрии объекта:
Вот так выглядит геометрический и атрибутивный diff для правок, которые я сделал для демонстрации прямого и косвенного редактирования объекта
А вот я дорисовал пешеходную дорогу, которая разрезала автомобильную дорогу на два участка
А вот так выглядит diff для простых объектов типа здания
Такое визуальное представление правок позволяет быстрее и проще разбираться в том, кто что и как отредактировал.
В итоге нам удалось реализовать простой и понятный интерфейс для пользователей, которые не знакомы с картографией и не хотят разбираться в структуре данных. Одновременно мы сделали удобный и гибкий интерфейс для опытных пользователей. Попутно научились редактировать в браузере очень большие и «тяжелые» объекты и поместили все правки пользователей под версионный контроль.
И все это для того, чтобы пользователям стало еще удобней делиться своими знаниями о местности с окружающими.
Автор: paradigm