Люди не согласны с тем, как выглядит хороший API. Однако, я думаю, все могут согласиться с этим.

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

«Документация была устаревшей, поэтому мы удалили ее»

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

Пусть каждый метод получает массив параметров

Вскоре документация была восстановлена, хотя до сих пор неясно, была ли она перекомпилирована или все еще устарела. Я надеялся. Был четкий список категорий, каждая с методами. Документация создавалась автоматически, что давало мне надежду, что она актуальна.

Все меняется, когда я действительно проверяю документацию на наличие метода. Метод принимал один параметр. Массив под названием «args». К счастью, некоторые, но не все методы имели примеры.

Иметь документацию, состоящую только из примеров

Некоторые методы, к счастью, также имеют описания. К сожалению, вскоре я узнаю, что описание — всего лишь один пример. Поскольку вы сверхчеловек, вам может быть легко понять значение createNewUser(['bill', 4, 25, 522, 'Bill', false, false])I, однако у меня возникли некоторые проблемы.

Если что-то и было сказано о возвращаемом значении, оно было столь же непрозрачным. Все вернулось «динамически» в соответствии с сгенерированной документацией, у некоторых были примеры, но эти примеры часто были неполными.

Используйте один и тот же вызов API для разных типов данных.

Один из методов был примерно таким:

getUserGroup(groupId)
/* Returns:
-> {"name": "group0",
    "type": "none",
    "id": "45",
    "group": 45,
    "users": [
        {"name": "...", "type": ""}
    ]} */

Это работало достаточно хорошо. Однако, как ни странно, каждая группа содержала одного «пользователя-призрака» с типом, установленным на none, и с тем же именем, что и у группы. Отфильтровать их для отображения было достаточно просто, и я больше не думал об этом.

Позже клиент запросил функцию, позволяющую создавать группы. Однако, похоже, не было вызова createGroup API. После обращения к разработчикам, которые ответили через несколько дней, оказалось, что способ создания группы - это использование createUser с type="none". «Пользователь-призрак» на самом деле был самой группой, которая на самом деле была не группой, а пользователем особого типа. Участники, где только пользователи, которые имеют общий идентификатор группы, в то время как идентификатор группы не совпадает с идентификатором группы. Очевидно, что ничего из этого нигде не было задокументировано.

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

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

Средний веб-сайт использует своего рода управление версиями, в основном состоящее из ошибок, если номера версий не совпадают.

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

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

shareDocument(document, user, allow_view=True, allow_edit=False, transfer_ownership=False)

Приложение может вызывать это так:

shareDocument(myDocument, user, True, True)

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

shareDocument(document, user, allow_edit, transfer_ownership)

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

Создайте тестовую версию API, которая на самом деле запускает более старую версию, чем настоящий API.

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

Сначала все идет по плану. По крайней мере, вы можете безопасно протестировать свое клиентское приложение. Однако ваше клиентское приложение обычно не вызывает проблем. В свое время провайдер выпускает еще одно критическое изменение, а затем сразу же начинает пересылать вам отчеты об ошибках. Вскоре вы обнаружите, что изменение не было отправлено на тестовый сервер. У вас нет другого выбора, кроме как протестировать в продакшене, как в старые добрые времена. Вы связываетесь с провайдером, и они также обновляют тестовый сервер — через пару недель.

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

Финал

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

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