Особенности разработки API: какой API является хорошим? +28

Наверное, абсолютно все читатели используют API, работая с фрэймворками, библиотеками, виджетами, как некий язык общения между сущностью и основным приложением. И вы наверняка замечали, что некоторыми API удобнее пользоваться, а в некоторых есть явные проблемы. Всеволод Шмыров (@vsesh) в своем докладе на Frontend Conf, расшифровку которого вы найдете под катом, постарался ответить на вопрос, какой API является хорошим.

Рассказ опирается на опыт разработки АPI Яндекс.Карт, и хотя это и JavaScript-библиотека, многие принципы и особенности его разработки применимы и к другим типам АPI, к примеру, к серверным API и Standalone библиотекам. Все то, о чем пойдет речь, относится именно к публичному АPI. Если к API вашей библиотеки обращаются только ваши коллеги, которым вы можете легко рассказать, что где-то что-то надо поменять, то вы, скорее всего, не столкнетесь с теми проблемами, с которыми сталкиваются разработчики публичного АPI.

image

Однако, в докладе не будет ответа на вопрос, нужен ли вам свой API. Надеемся, после прочтения вы взвесите все «за» и «против» и сами поймете, нужен ли он вам. Всеволод просто расскажет, с какими сложностями приходится сталкиваться разработчикам API, какие проблемы решать и что еще делать, а именно про эти четыре важных пункта:



О спикере: Всеволод Шмыров — старший разработчик интерфейсов в компании Яндекс, непосредственно участвовал в разработке API Яндекс.Карты и конструкторе карт Яндекс.

Перед вами материал по докладу на Frontend Conf в 2017 году, какие-то моменты, например список поддерживаемых версий браузера, могли измениться, но критерии хорошего API по-прежнему актуальны. Далее рассказ пойдет от лица Всеволода, приятного чтения.

Будь проще


API должно быть простым, ну и желательно логичным. Вроде бы, казалось, это так просто, что может пойти не так. Но тем не менее в это слово люди вкладывают совершенно разные значения — степень простоты у всех совершенно разная. Давайте сразу перейдем к негативному примеру, чтобы вы поняли, о чем я говорю.

Несколько лет назад я столкнулся с API одной социальной сети. Там был метод getFriends.

getFriends( ) => [ ]

На самом деле, несмотря на то что на слайде у меня JS-псевдокод, это была серверный endpoint, которому ты послал запрос getFriends с параметром и получал список друзей. Вроде все логично, запрашиваешь друзей, получаешь друзей. Мой код, который работал с этим API выглядел бы как-то так:

var friends = getFriends( );

Но разработчики почему-то решили, что этого недостаточно. Они решили сделать следующее, если у тебя нету друзей, то вместо пустого списка ты получаешь Null.

Ладно, мой код тогда стал выглядеть соответствующе:

var friends = getFriends ( );
If (friends) {
    // …
} else {
    // …
}

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

Становится понятно, что API непростой, нелогичный. Мой код стал уже выглядеть так:

var friends = getFriends( );
If (isUser(friends)) { /*…*/}
elseif (friends) { /*…*/}
else { /*…*/}

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

Хороший API — это тот, который не заставляет писать лишнее. Вы используете какой-то метод на API и дальше работаете с данными, и вам не нужно писать страшные условия.

Давайте подытожим, интерфейс должен быть:

  • Простым и логичным
  • Консистентным
  • Но не в ущерб возможностям

Под консистентным, тут подразумевается то, что, если в API есть методы, которые работают с одними и теми же типами данных, эти типы данных должны быть описаны одинаково.

iCanShowYou({x: 1, y: 1});
NoUCant([1, 2]);
ButIMust(Point);

К примеру, в API Карт часто используется тип данных координаты, они у нас представлены в виде массива — широта, долгота. И они так описаны везде, то есть у нас нет методов, которые принимали бы объект XY, объекты Long Lat или вообще два объектами. Координаты везде представлены именно массивом.

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

someAwesomeMethod(
   elem, /* required */
   index, /* = "key" */
    startValue, /* = 0 */ 
    endValue /* = 1 */
);

В примере выше метод, который принимает какие-нибудь четыре аргумента. Мы стараемся вывести наиболее вероятны кейсы и записать стандартные значения параметров таким образом, чтобы они решали эти кейсы.

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

new ymaps.GeoObject(
    geometry, /* {Object} */
    properties, /* {Object} */
    options, /* {Object} */
);

В этом примере, мы группируем параметры по объектам. В других языках это может быть класс или экземпляр конкретного класса или интерфейса. То есть объект GeoObject может обладать определенной геометрией, он может быть точкой, линией, полигоном, у него есть определенные свойства, например название, и у него есть опции, такие как цвет и т.д. Между всеми этими аргументами нет особой разницы, но мы их математически разделили, чтобы было удобнее. Да и прямо скажем, геометрия меняются значительно реже, чем свойства.

new ymaps.GeoObject(geometry), 
    // Любыегеометрии
new ymaps.Placemark(coord), 
    // Только “Point” 

Также мы делаем специальные программные хелперы. Как я сказал, объект может быть точкой, линией, полигоном. Мы заметили, что, к примеру, точками пользуются значительно чаще и сделали специальный класс Placemark, который на вход принимает не абстрактную геометрию, а только лишь пару координат.

Ниже кейс неопределенного результата, это совершенно другая задача. Бывает так, что таки приходится городить костыли, только в публичном API все их увидят, что усложняет дело.

geolocation.get()
    .then(function (result) {
        // success
    }, function (error) {
        // error
    });

Метод geolocation.get возвращает promise, в котором будет или текущее положение пользователя или ошибка. Из-за того, что возможна ошибка, нам пришлось использовать в данном методе promise, к тому же этот метод асинхронный. Geolocation.get по умолчанию использует браузерную геолокацию, которую поддерживают не все браузеры.

Работает это следующим образом, разработчик пишет в коде geolocation.get, этот код исполняется, а в браузере вылезает такое окошечко.



Пользователь сайта может разрешить сайту получить местоположение свое или запретить. Но в некоторым браузерах были баги — если человек нажимал на крестик или нажимал где-то на странице, это окошко пропадало и geolocation.get не возвращал никакое значение, promise висел без значения. Поэтому нам пришлось здесь скрутить тайм-аут, такое железобетонное решение, если в течении тридцати секунд человек ничего не нажал или это окошко пропало, то мы кидаем реджект тайм-аут. Это не очень красиво, но тем не менее, позволяет повысить стабильность нашего кода.

Рукописи не горят


Этот раздел посвящен обратной совместимости. У вас наверняка был такой случай.
Вы отдыхаете, возможно это выходной, скорее всего ночь, вы расслаблены, вдруг вам кто-то звонит и говорит, что ничего не работает в продакшене, ваш продукт сломался. А вы кое-как вспоминаете, что последний релиз был три недели назад, все было хорошо, и ничего не должно было сломаться. Ничего, как говорится, не предвещало беды.
Вы срочно подключаетесь к рабочей сети, открываете отладчик, начинаете разбираться, что происходит, и вдруг понимаете, что с вашей стороны все хорошо. Сломался какой-то API, который вы использовали. Точнее он даже не сломался, он просто стал работать по-другому, не так, как вы ожидали. Это значит, что произошел слом обратной совместимости.

Обратная совместимость


Обратная совместимость — это гарант того, что однажды опубликованный интерфейс будет поддерживаться и в будущем. В принципе хорошо бы до бесконечности, но, на самом деле, в рамках текущей мажорной версии.

Вообще все логично, сделал, работает — не трогай!

Чтобы сделать что-то новое, сделай это где-то в стороне, старое не трогай. Но не все так просто. Обратная совместимость накладывает очень сильное ограничение на разработку любых новых компонентов, любых новых интерфейсов, сейчас я расскажу про это подробнее.

Во-первых, когда вы решаете опубликовать новый интерфейс, вы должны подумать про степень свободы разработчика.



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

К тому же все это поддерживать очень дорого, приходится ставить дополнительные юнит-тесты, дополнительные интеграционные тесты, перед каждой минорной версии все проверять.

Если вы все-таки решили опубликовать некоторую сущность, нужно думать о том, что интерфейс будет расширяемым.

Давайте рассмотрим пример. У нас когда-то был метод, впринципе он и сейчас есть, balloon.setPosition. Туда можно было передать две координаты, широта, долгота, которые ниже обозначены x и y.

balloon.setPosition(
   x, y// обязательные аргументы
)

Как я говорил ранее у нас все координаты записывается не двумя аргументами, а одним, так как они оба являются обязательным аргументом. Поэтому лучше их скрепить в один аргумент [x, y] и пометить его как обязательный. Потом мы подумали, что хорошо бы разрешить передавать кроме широты и долготы еще и проекцию, у нас есть проекция по умолчанию, но можно задать какую-то собственную проекцию. Мы могли бы добавить опцию Projection, но потом нам наверняка потребовалось бы добавить какие-то еще опции. Тогда мы решили, что мы сразу сделаем options, внутри укажем проекцию и в будущем сможем добавлять любые другие ключи. То есть мы сделали интерфейс расширяемым, и он никак не блокирует будущую разработку.

Все то, о чем я сейчас говорил, нужно для того, чтобы понять, не станет ли ваш новый интерфейс «блокером» в будущем?

Давайте я снова сразу перейду к примеру. Когда-то давным-давно мы решили опубликовать метод getLayout в сущности overlay. На тот момент у нас был один единственный Layout, который был реализаций класса символа HTMLLayout. Мы могли бы опубликовать интерфейс так:

overlay.getLayout()
    // HTMLLayout

Тогда в будущем мы бы не смогли создавать Layout кроме как html. Поэтому мы сделали метод, который возвращает интерфейс ILayout, который будет возвращать HTMLLayout.

overlay.getLayout()
    // ILayout
    // HTMLLayout, CanvasLayout…

А разработчик, который использует API, уже в зависимости от своих нужд может поставить переключиться, например, на CanvasLayout.

Потом мы еще подумали и добавили вообще Promise, потому что поняли, что нужно делать API компонентно и, если метод станет асинхронным, у нас будет возможность в этом месте добавить подгрузку модулей.

Исправление ошибок


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

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

Мы часто используем алиасы, но это тоже в принципе не очень хорошее решение. Например, у нас есть макеты иконок, и мы в данном случае используем оба варианта написания слова «grey», так как часть пользователей пишет по-американски, а часть по-английски.

presets.get(‘islands#greyicon’);
presets.get(‘islands#grayicon’);

То же самое мы делали с методами, когда находили опечатки.

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

Где-то примерно два года назад, мы переписывали бэкенд API с одной серверной технологии на другую. Разработчики, которые используют API, использовали следующим образом: по ссылке

https://api-maps.yandex.ru/2.1/?lang=ru_RU&mode=debug

подключали скрипт на страницы и все прекрасно работало.

Мы переехали на Node.js и вдруг пошли жалобы от пользователей. Дело было в амперсанде — часть пользователей копировала ссылку со спец символом «&», который в html трактуется как амперсанд и хорошо работает. Но часть пользователей копировала эту ссылку как есть, то есть такой запрос и отправлялся не сервер. При это происходила следующая ошибка, вместо параметра «mode» приходил «amp;mode». Старый бэкенд это обрабатывал, потому что считал символ «;» разделителем get параметров наравне с символом амперсанда. То есть там приходил lang, mode и куча пустых amp.

Мы посмотрели сколько пользователей делали такие запросы к нам и поняли, что мы не можем всем объяснить то, что так делать неправильно. Поэтому мы просто добавили middleware, который удаляет amp из get параметров и только лишь после этого их обрабатывает. Да, это глупо, но приходится и с таким жить.

Мажорные релизы


Но не все так безнадежно, ошибка в обратной совместимости не будет преследовать вас до конца жизни. Только до конца, до следующей мажорной версии.



Где-то года три назад мы решили выпустить мажорную версию API 2.1, чтобы обновить список браузеров, которые мы поддерживаем. Версия API 2.0 она была очень старая, она поддерживала даже IE 6 — понимаете, какая это боль. Но, к сожалению, в 2.1 мы все еще поддерживаем IЕ 8, потому что три года назад это был достаточно актуальный браузер (сейчас IE 8 уже находится в слабой поддержке).
Если честно, я вам скажу по секрету, только между нами, в будние дни доля IЕ 8 где-то порядка 4%, а на выходных она проседает меньше 1%. Если у вас на предприятии используется IЕ, обновляйтесь, хватит терпеть.
Так вот, обновление списка браузеров — это тоже слом обратной совместимости, в старых браузерах API работать не будет, поэтому мы и назвали эту версию 2.1. Заодно решили пуститься во все тяжкие и сломать обратную совместимость даже там, где это не было необходимо. Мы почистили код от всех тех алиасов и от костылей, которые нам было необходимо поддерживать из-за обратной совместимости, удалили некоторые старые полифилы для IЕ 6.

Понятно, что мажорная версия — это не панацея, выпуск новой мажорной версии тоже стресс для разработчиков, которые используют ваш API. Им придется заново чистить документацию, поэтому все-таки мажорными версиями лучше не баловаться. Выпуск мажорной версии все равно заставит их переписывать код, что говорит о том, что ваш API был бы не таким хорошим, если бы вы не заставляли это делать пользователей. Частичным решением является специальный режим работы.

«Особый режим» работы


В JavaScript есть строгий режим работы ‘use strict’, когда вы пишите тот же самый код, он визуально выглядит также, но трактуется немножко по-другому. У нас есть похожий режим работы, правда он служит совершенно для другой цели.

https://api-maps.yandex.ru/2.1/?lang=ru_RU&coordorder=longlat

У нас есть get параметр coordorder, которым можно управлять порядком координат в массиве, про который я говорил ранее. По умолчанию у нас широта, долгота (longlat). Можно передать долготу, широту (latlong). В разных гео-системах используется разный порядок координат. Соответственно, при указании get параметров получается другой режим работы.

Весь API работает немножко по-другому, и при расчетах это нужно учитывать.

Что еще можно сказать про обратную совместимость? Обратная совместимость влияет не только на код, как можно было бы подумать.



Если вы разрабатываете визуально API, то есть API, который что-то показывает, то у вас есть обратная совместимость и на визуальную составляющую. Не так давно мы выпустили новую минорную версию API, в котором обновили элементы управления карты. Они стали более светлыми, более плоскими, как сейчас модно, но они практически не изменили свой размер. Почему мы так поступили? Мы могли в теории сделать большущие кнопки, сделать их полукруглыми, изменить иконки или вообще убрать иконки, но это нарушало бы обратную совместимость.

Когда мы создавали элементы управления в API, мы подумали, что было бы хорошо дать разработчикам возможность добавлять собственные элементы управления, причем среди наших. То есть не сверху, а вот прямо посреди. Соответственно, если бы мы сделали стандартный макет кнопок больше, то у разработчиков на сайтах поехала бы верстка. Так что даже с таким приходится мириться и учитывать при создании новой минорной версии.



Еще хочу заметить, что очень часто обратная совместимость ломается каскадно. В нашем случае, что-то в браузере ломается — что-то ломается в API.



У нас был такой немножко грустный забавный случай, когда в одном браузере, у которого уже примерно 80% доли пользователей, в событии MouseEventвдруг поменялся знак. На прокрутку колесика мышки стал приходить не плюс, а минус. Естественно, когда человек пытался приблизить карту колесиком мышки, она начинала от него отдаляться. Нам за два дня, пока браузер это не починил, нам пришло порядка трех тысяч писем в день. Чтобы вы понимали, обычно даже в самые напряженные дни приходит около десяти писем, то есть людям действительно доставило неудобство то, что карта вдруг резко поменяла свое поведение.

Свой среди чужих


Этот раздел посвящен JavaScript API, но тем не менее он тоже достаточно интересен. API работает в чужом контексте, что это значит? Допустим есть первый сайт, который использует API карт, и там все хорошо работает. Есть второй сайт, который использует API, но еще он использует и библиотеку jQuery — тоже все работает нормально. А есть третий сайт, который использует API карт и некоторые evil.js, который зачем-то переопределяет базовые методы.



В примере ниже ошибка в том, что indexOf не возвращает минус один. Видимо разработчик этого метода решил поддерживать IЕ 6, не проверил существование настоящего indexOf и написал такой:

Array.prototype.indexOf = function (item) {
    for (var i = 0; i < this.length; i++)
        if (item ==this [i])
            return i;
};

API естественно в этом случае ломается. Или, к примеру, мы сталкивались с таким кодом:

* {
transition: 2s all ease;
}

Кто-то зачем-то написал такой CSS селектор, который оставляет абсолютно все на странице быть анимированным.

В рамках этой статьи я не буду углубляться в то, как с этим бороться, да и в принципе не всегда это возможно, подробности можно посмотреть тут.

Но я хочу подчеркнуть то, что на это тоже нужно тратить ресурсы. Обычно у нас это происходит следующим образом: в поддержку приходит жалоба пользователя то, что что-то не работает, с приложенной ссылкой; мы ее открываем, смотрим что в API что-то сломалось; начинаем смотреть CSS, JS и это не всегда бывает удобно. На это тоже придется тратить время, если вы разрабатываете именно JS-библиотеку или API, который внедряется в чужой контекст.

Вы не знаете свой продукт


API, как я говорил раньше, это продукт, и вы не знаете, как вашим продуктом пользуются. Когда-то в версии 2.0 мы столкнулись с тем, что очень много людей создавало такие маленькие карты, а мы про этот кейс просто не подумали.



Карта малюсенькая, где-то 150*150 пикселей, и на левой карте все управляющие элементы друг на друга наехали. А мы просто, когда создавали 2.0 об этом не подумали, ну кому нужна такая малюсенькая карта. Но когда мы это увидели, в 2.1 мы проработали над этим, и на правом рисунке уже все помещается. Мы сделали адаптивные элементы — это очень простое решение, чем шире карта, тем шире элементы.



Соответственно, на больших картах поиск полностью отображается, а на маленьких кнопочка, по клику на которую сверху выползает поиск. Но это стало возможно только лишь после навешивания метрик на собственные методы API.

Метрики


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

В нашем случае важным параметром был размер карты. Мы сталкивались с тем, что люди создавали, как маленькие карты, так и очень большие — бывают значения порядка 5000*4000. Видимо, такого размер карта отображается на каком-то стенде, но я даже не представляю, сколько она открывается.

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

Думай как…


Чтобы еще лучше понимать, как люди используют ваш API, вам нужно самим использовать API. Знаете, не просто абстрактно знать, как он работает, а постараться придумать задачу, которую бы решил разработчик при помощи вашего API. К примеру, так я не сколько лет назад пытался сделать приложение для Вконтакте — карту, на которой люди бы могли отмечать, где они путешествовали ранее.



Идея простая, можно: поставить метку, открыть карту друзей и поделиться этим на стене (это было года четыре назад). И пока я делал приложение, я нашел много узких мест в документации, где было не очень понятно, как это можно реализовать. Да, я понимаю то, что разработчик API сам критикует документацию, звучит немного странно, но это было просто необходимо.
Я постарался очистить сознание, в таком состоянии открыл документацию и пытался думать, как разработчик-пользователь.
Плюс я смог найти несколько достаточно критических багов работы API внутри Iframe просто потому, что такой кейс нам еще не приходил в голову, а он оказался важен. Вконтакте открывает html приложения через Iframe, соответственно, Iframe открывается с другого домена и проявляются особенности работы, например, с событиями, которые мы, к счастью, учли.

Документируй это


В любом рассказе про API, наверное, невозможно избежать темы документации, хотя она достаточно нудная. Никакой API не может обойтись без документации.
API без документации — не API.
Документация — это документ, который подтверждает те публичные методы, которые должны обладать свойством обратной совместимости.



У нас документацию пишут сами разработчики через JSDoc. У нас есть, как справочник по всем методам, так и некоторые вводные статьи, к примеру, как подключить API или как создать карту.



Но опыт показывает, что людям это не очень интересно. Да, при желании они могут зайти в документацию, но когда разработчик еще не работал с вашим API, он зайдет в поисковую систему и наберет «создать карту доставки», «отметить карту доставки» или что-нибудь подобное. Соответственно, документация по такому запросу не будет выдана, потому что она рассказывает про более абстрактные вещи. Поэтому нужно создавать специальные стенды и собирать там популярные кейсы, у нас таким стендом является песочница.



Там можно посмотреть на живые примеры использования API: слева код, справа результат. Можно даже что-то подправить, а потом экспортировать в JSFiddle. Но и тут оказывается не все так просто, как могло показаться.

Однажды мы заметили такие карты.



На первый взгляд все в порядке, но если приглядеться, можно увидеть, что тут почему-то два элемента изменения масштаба (слева шкала, кнопочки справа). Мы стали думать, почему так получилось, и оказалось, что так было в одном из наших примеров. Мы хотели сделать пример с элементами управления на карте и подумали, что будет хорошей идеей добавить два зум контрола: «посмотрите, у нас есть большой зум контрол и маленький, работает так и так». Разработчики просто копировали код как есть и вставляли себе на страницу. После этого мы решили, что в примерах будем делать максимально живые кейсы. То есть если есть кейс про поиск, то там будет только поиск, никаких дополнительных крутых опций, которые могут не потребоваться большинству разработчиков.

Call me maybe


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



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

Продай мне эту ручку


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



На это тоже нужно тратить время.

Еще проще


Я начал рассказ с пункта «Будь проще», но можно пойти де еще дальше и вообще не заставлять разработчика программировать. Наиболее популярный кейс можно позволить решить через какой-нибудь специальный инструмент. К примеру, нашим популярным кейсом является просто отображение карты на странице или отображение карты на странице с какой-то меткой. Поэтому мы сделали конструктор.



Человек открывает карту в браузере, накликивает метки, рисует линии и полигоны, задает описание и получает код для вставки на сайт.



Все логично, но и тут не все так просто, как кажется на первый взгляд.

Конструктор

  • Простое решение популярных задач
  • Меньше «свободы» для разработчика
  • Обход ограничения обратной совместимости

По сути, конструктор является упрощенной версией API, им могут пользоваться даже не разработчики, поэтому мы в нем даем меньше «свободы». И это намеренный шаг. Сейчас я поясню.

<script src="
.../constructor/?um={id}&width=514&height=326
"></script>

Когда пользователь получает код для вставки на сайт, он получает не тот же самый код, который он бы запрограммировал через API. Он получает скрипт, который подключает специальный модуль, который уже сам загружает API и на основе данных, указанных в конструкторе, создает карту. В данном случае пользователь может управлять небольшим количеством параметров, например, шириной и высотой карты. Если он создал карту в конструкторе, он потом уже никак не может с ней взаимодействовать на странице, поставить другой центр, добавить метку и так далее.

Мы это сделали намеренно, потому что это очень хороший способ обойти ограничения обратной совместимости. Если человек не может ничего контролировать, как в данном случае, то мы можем делать все, что угодно. Например, в этом виджете мы спокойно переключили версию с 2.0 на 2.1 и не поступило вообще ни одной жалобы. Если бы мы оставили возможность программно что-то редактировать, то мы дали бы большую степень свободы разработчикам и соответсвенно, это привело бы к каким-то неопределеностям и ошибкам.

Так что возможно, вам и не нужен API, возможно вам нужен такой инструмент, который позволяет что-то делать вместо API. В нашем случае, если разработчикам требуется легкий кейс, мы рекомендуем конструктор. Если более сложный, допустим нужно сделать боковое меню рядом с картой и как-то с ней взаимодействовать — то тогда уже нужен API.

Итог


Как я уже говорил:

  • хороший API не заставляет разработчиков писать лишнего,
  • но всегда помнит про обратную совместимость и не ломает ее;
  • разработчик, который создает API, должен исследовать свой API чтобы понимать, как им пользуются.

Напоследок, пара интересных ссылок:


Следующий Frontend Conf совсем скоро, 28 и 29 мая нас, как всегда, ждет много интересного и даже холиварного, например, вот несколько принятых докладов:

  • Chris Lilley (W3C). WebFonts in 2018: Everything Changes.
  • Виктор Русакович (GP Solutions). Зачем мы переписываем приложение на Elm, и кто его знает?
  • Тимофей Лавренюк (KeepSolid). Как сделать веб приложение нативнее, а пользователя счастливее с помощью современных возможностей браузера.

Кстати, в этом году будет больше конференций — 4 и 5 октября мы организуем еще один Frontend Conf Moscow, как самостоятельное мероприятие. Подать заявку на доклад можно аж до 3 августа, если вы упустили такую возможность на РИТ++, а в течение мая можно забронировать билеты по себестоимости.

Вы можете помочь и перевести немного средств на развитие сайта



Комментарии (13):

  1. Odrin
    /#11358912 / +1

    Где-то года три назад мы решили выпустить мажорную версию API 2.1
    Версия API 2.0 она была очень старая

    Почему вы называете минорную версию мажорной?

    • mapron
      /#11358922 / +1

      Потому что они не используют SemVer, и это их право? да, это слегка так непривычно, но это не значит что это незаконно)

      • Odrin
        /#11358930

        Я ни в коем случае не считаю, что это незаконно. Просто при прочтении возник диссонанс и стало действительно интересно, почему так.

    • forgotten
      /#11358924

      Потому что система версионирования API Яндекс.Карт (в которой вторая цифра означает обратно несовместимые изменения) на год старше семвера.

      • Odrin
        /#11358932

        Погуглил немного и нашел ответ на свой вопрос. Действительно, у Яндекс.Карт своя система версионирования, несколько отличная от semver. Спасибо за небольшую историческую справку.

  2. nikitasius
    /#11358928

    Хороший API — это тот, который не заставляет писать лишнее. Вы используете какой-то метод на API и дальше работаете с данными, и вам не нужно писать страшные условия.

    Это в сказке. На деле есть разного рода идиоты, которые видят мир через воткнутые в глаза карандаши и из-за которых и приходится, порой, дописывать "страшные условия" в красивый АПИ.


    upd: комментарий со стороны того, кто апи пишет. А не того, кто пишет под апи.
    upd#2: тоже много крови.

    • flancer
      /#11359494

      Вы живёте в страшном мире, коллега. Вас окружают идиоты с торчащими из глаз карандашами и вокруг всё в крови. Сюрненько.

  3. x-foby
    /#11359214

    Понимаю, что нужно в обратную совместимость, но было бы, конечно, просто замечательно увидеть новую версию API, написанную под современные браузеры на современном js. Ждём, надеемся и верим.

    Ну и да, документация — это, пожалуй, самое слабое место Яндекс.Карт. Очень многие вещи проще нагуглить, чем найти в документации (я уже молчу про понять).

    • vsesh
      /#11359496

      Спасибо за фидбек!
      Про новую версию апи сказать не могу, так как прямо сейчас уже не так тесно связан API карт. Но я знаю, что где-то полгода назад для старых версий браузеров (все ie кроме 11, opera, старые android) зафризили определенную версию API 2.1
      tech.yandex.ru/maps/doc/jsapi/2.1/quick-start/tasks/quick-start-docpage

  4. glader
    /#11359442

    Как лучше оповещать разработчиков, использующих мое АПИ, что версия, которую они используют, скоро помрет?

  5. vlasenkofedor
    /#11359578

    Где ваша реализация getFriends?
    Почему нет упоминаний о кодах состояний ответов?

  6. lxsmkv
    /#11359742 / +1

    Я всегда задаю себе вопрос «как ты будешь это использовать?». Т.е. нужно, чтобы в точке использования все было просто. В первую очередь код на стороне клиента должен быть простым и понятным. Поэтому я обычно начинаю с наброска клиентского кода, и если он меня устраивает, он простой и понятный, то из него формируется интерфейс. Нельзя придумывать интерфейс «в вакууме».

    У меня был интересный опыт, я затребовал фичу у фреймворка, представил им кусок клиентского кода и сказал: «сделайте так, чтобы это заработало». Удивительно как быстро все было готово, и без ошибок. Никаких совещаний и переписок не понадобилось.

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

  7. vmm86
    /#11361354

    если разработчикам требуется легкий кейс, мы рекомендуем конструктор. Если более сложный, допустим нужно сделать боковое меню рядом с картой и как-то с ней взаимодействовать — то тогда уже нужен API
    Был опыт использования API Яндекс.Карт в небольшом проекте. При этом предварительно нужно было получить координаты балунов, расставленных вручную на карте в Констукторе, для последующей работы с ними. Получилось их выдернуть из исходного кода страницы, но между тем экспорт содержимого карты (в первую очередь координат элементов карты) в API-совместимой структуре данных из самого Конструктора был бы удобен и полезен.