Комментарии 24
Ребята, вы как всегда вовремя! Как раз собирался писать API.
Поделитесь, пожалуйста, ссылочкой на доклад Марата про проектирование систем, о котором в начале видео говорится. Ссылка из доклада (http://study.yandex-team.ru/events/kmb-2/techno/talks/901) наружу не доступна.
Кажется, этот семинар ещё не выкладывали. Можно взамен Макконела почитать )
очень странно выглдит совет использовать события — это требует глобального/встраевоемого везде медежера событий с интерфейсовм set/get event data, формат которых не задан через интерфейсы
У нас в API карт так и есть — почти все объекты реализуют IEventEmitter
Интерфейсы же для передаваемых событием данных, в общем случае, не нужны — все данные должны быть доступны через интерфейс объекта, бросающего события.
Интерфейсы же для передаваемых событием данных, в общем случае, не нужны — все данные должны быть доступны через интерфейс объекта, бросающего события.
Последняя фраза не очень понятна.
К примеру, есть чат и объект Юзер. У юзера событие — «пришло новое сообщение».
Как подписчику узнать содержимое сообщения, у юзера должен быть метод типа «покажи последние N сообщений» и подписавшийся на юзера клиент должен в них покопаться и найти новое?
К примеру, есть чат и объект Юзер. У юзера событие — «пришло новое сообщение».
Как подписчику узнать содержимое сообщения, у юзера должен быть метод типа «покажи последние N сообщений» и подписавшийся на юзера клиент должен в них покопаться и найти новое?
Да.
Только не совсем ясно, зачем «копаться». Новое = последнее.
Только не совсем ясно, зачем «копаться». Новое = последнее.
Только в полностью синхронных системах. Т.е., пока подписчик не вышел из обработчика события, никто не может добавить сообщение, иначе эта логика сломается.
В асинхронных системах доставать ид сообщения из события вообще неправильно и довольно бессмысленно.
Тогда поток обработки событий должен хранить ид последнего обработанного сообщения, а по событию обновления запрашивать все сообщения, новее чем этот id.
Тогда поток обработки событий должен хранить ид последнего обработанного сообщения, а по событию обновления запрашивать все сообщения, новее чем этот id.
Спасибо за труд!
Хотелось бы больше информации по п. 7: как именно вы поддерживаете версионность тестов относительно версий API, какие лучшие практики совместного рефакторинга самой функциональности API и соответствующих тестов, как лучше анализировать необычное поведение устаревших версий API, когда приходится идти на компромиссы в данных — добавлять фейковую информацию, т.к. новейшее API становится в некоторых процессах уже несовместимым со старым.
Например, в старой версии были ± лайки, в новой решили сделать только лайк, а дислайк в обязательной форме указания причины дислайка. Что в этом случае было бы по вашим процессам создания/поддержки API и тестов со старым функционалом дислайков? Это просто пример, когда со временем развитие API приводит к несовместимостям в логике. Часто в таких случаях применяют разделение на большие ветки версий 1.0/2.0, интересно было бы услышать сталкивались ли вы с таким в процессе развития и какие решения принимались и на основе чего для разрешения подобных задач.
Хотелось бы больше информации по п. 7: как именно вы поддерживаете версионность тестов относительно версий API, какие лучшие практики совместного рефакторинга самой функциональности API и соответствующих тестов, как лучше анализировать необычное поведение устаревших версий API, когда приходится идти на компромиссы в данных — добавлять фейковую информацию, т.к. новейшее API становится в некоторых процессах уже несовместимым со старым.
Например, в старой версии были ± лайки, в новой решили сделать только лайк, а дислайк в обязательной форме указания причины дислайка. Что в этом случае было бы по вашим процессам создания/поддержки API и тестов со старым функционалом дислайков? Это просто пример, когда со временем развитие API приводит к несовместимостям в логике. Часто в таких случаях применяют разделение на большие ветки версий 1.0/2.0, интересно было бы услышать сталкивались ли вы с таким в процессе развития и какие решения принимались и на основе чего для разрешения подобных задач.
> как именно вы поддерживаете версионность тестов относительно версий API
У наших тестировщиков, например, подняты стенды, которые сравнивают результаты тестов текущей версии с предыдущими (в т.ч. с продакшеном).
> какие лучшие практики совместного рефакторинга самой функциональности API и соответствующих тестов
Эта тема тянет, как минимум, на пару таких семинаров, но, на самом деле, при правильно определённых интерфейсах можно рефакторить как угодно. Проблемы, как правило, не в самом рефакторинге — а в том, что интерфейс был изначально недоопределён или ошибочен.
> как лучше анализировать необычное поведение устаревших версий API
Не понял вопроса.
> Например, в старой версии были ± лайки, в новой решили сделать только лайк, а дислайк в обязательной форме указания причины дислайка.
Это эффективный слом обратной совместимости. Прятать его за какие-то фейковые фасады = гримировать труп.
> Часто в таких случаях применяют разделение на большие ветки версий 1.0/2.0, интересно было бы услышать сталкивались ли вы с таким в процессе развития и какие решения принимались и на основе чего для разрешения подобных задач.
В данный момент мы поддерживаем одновременно четыре мажорных версии АПИ, и пока не планируем сворачивать поддержку старых версий.
Наше соглашение примерно следующее: должны поддерживаться (= исправляться любые критические ошибки) не менее двух последних мажорных версий; развивается при этом (добавляется новый функционал) только последняя мажорная; должен быть прямой доступ как минимум к двум минорным версиям в рамках актуальной мажорной.
Мы выпускаем мажорные версии со следующим расчетом: если проект, использующий наше АПИ, актуален и развивается, то он раз в несколько лет неизбежно будет переписан и сможет встроить обновление до новой мажорной версии в свой продуктовый цикл. В реальности получается темп «одна мажорная версия раз в два-три года», который, кажется, всех устраивает.
У наших тестировщиков, например, подняты стенды, которые сравнивают результаты тестов текущей версии с предыдущими (в т.ч. с продакшеном).
> какие лучшие практики совместного рефакторинга самой функциональности API и соответствующих тестов
Эта тема тянет, как минимум, на пару таких семинаров, но, на самом деле, при правильно определённых интерфейсах можно рефакторить как угодно. Проблемы, как правило, не в самом рефакторинге — а в том, что интерфейс был изначально недоопределён или ошибочен.
> как лучше анализировать необычное поведение устаревших версий API
Не понял вопроса.
> Например, в старой версии были ± лайки, в новой решили сделать только лайк, а дислайк в обязательной форме указания причины дислайка.
Это эффективный слом обратной совместимости. Прятать его за какие-то фейковые фасады = гримировать труп.
> Часто в таких случаях применяют разделение на большие ветки версий 1.0/2.0, интересно было бы услышать сталкивались ли вы с таким в процессе развития и какие решения принимались и на основе чего для разрешения подобных задач.
В данный момент мы поддерживаем одновременно четыре мажорных версии АПИ, и пока не планируем сворачивать поддержку старых версий.
Наше соглашение примерно следующее: должны поддерживаться (= исправляться любые критические ошибки) не менее двух последних мажорных версий; развивается при этом (добавляется новый функционал) только последняя мажорная; должен быть прямой доступ как минимум к двум минорным версиям в рамках актуальной мажорной.
Мы выпускаем мажорные версии со следующим расчетом: если проект, использующий наше АПИ, актуален и развивается, то он раз в несколько лет неизбежно будет переписан и сможет встроить обновление до новой мажорной версии в свой продуктовый цикл. В реальности получается темп «одна мажорная версия раз в два-три года», который, кажется, всех устраивает.
Ага, примерно так и предполагал, спасибо что поделились. Похоже что у вас изначально все было сделано «по уму» и не случалось резких поворотов в функциональности внутри одной версии. Это когда сделали, к примеру, фатально кривой RPC (уже не важны причины) для мобильного API, приложение в релизе несколько недель, заметили только сейчас. Да, заниматься поддержкой такой ошибки в итоге — это прятать запах освежителем, чем вынести причину его появления, но вопрос как всегда в цене. Варианта вижу два:
1) очень плохой — забить на тех, кто остался с необновленным приложением, передающим уже неправильные запросы. Если их в соотношении с остальными меньше определенного порогового уровня. К примеру, за эти две недели скачали 100 человек и не обновились, а всего активных пользователей приложения под миллион.
2) сделать костыль, для конкретной версии API конкретных приложений с занесением информации что после, к примеру, полугода этот костыль принудительно убрать. Пусть как-то хромает, но мы не нарушим серьезно работоспособность всего приложения и оно будет «хромать».
Со временем пришел к такому решению: с самой первой релизной версии в приложении при его старте делать RPC, отправляющий версию API (или билд), с которой приложение гарантировано было протестировано. При описанной выше проблемной ситуации, в приложение приходил бы ответ с обязательностью уведомления в виде alert-а (не суть как) о необходимости обновить приложение по причине критических багов. Можно это сделать на уровне всех вызовов API, не суть.
Я понимаю, что такие ситуации нужно избегать и делать все возможное, чтобы такого не было, но интерес у меня возник именно на тему разрешения/поведения в нестандартных ситуациях, когда что-то сломали и шага назад сделать нельзя.
В принципе, я ответ уже получил, просто хотел пояснить ранее озвученный мой вопрос. Еще раз спасибо!
1) очень плохой — забить на тех, кто остался с необновленным приложением, передающим уже неправильные запросы. Если их в соотношении с остальными меньше определенного порогового уровня. К примеру, за эти две недели скачали 100 человек и не обновились, а всего активных пользователей приложения под миллион.
2) сделать костыль, для конкретной версии API конкретных приложений с занесением информации что после, к примеру, полугода этот костыль принудительно убрать. Пусть как-то хромает, но мы не нарушим серьезно работоспособность всего приложения и оно будет «хромать».
Со временем пришел к такому решению: с самой первой релизной версии в приложении при его старте делать RPC, отправляющий версию API (или билд), с которой приложение гарантировано было протестировано. При описанной выше проблемной ситуации, в приложение приходил бы ответ с обязательностью уведомления в виде alert-а (не суть как) о необходимости обновить приложение по причине критических багов. Можно это сделать на уровне всех вызовов API, не суть.
Я понимаю, что такие ситуации нужно избегать и делать все возможное, чтобы такого не было, но интерес у меня возник именно на тему разрешения/поведения в нестандартных ситуациях, когда что-то сломали и шага назад сделать нельзя.
В принципе, я ответ уже получил, просто хотел пояснить ранее озвученный мой вопрос. Еще раз спасибо!
Отличный троллинг с вашей стороны писать такие статьи. Сужу это в первую очередь со стороны человека, который занимался переводом проектов с использование API карт версии 1 на версию 2. Причина перехода была связана с фичами, которые были в 2.0 (кажется поддержка HTTPS). Испытывал кучу нелестных чувств к вам как сторонний разработчик. Имхо, бытует не совсем верное мнение, что в мажорной версии можно полностью сломать обратную совместимость. Это не совсем верно. Если пофиг на пользователей, то да. А если не пофиг, то делать даже в мажорной версии такие изменения нужно точечно и аккуратно. Иначе цена прикручивания новой фичи (поддержки HTTPS) выливается в стоимость полностью переписывания клиентского слоя работавшего с картой. Поверьте, да не устраивает такой вариант — нет. Стороннему разработчику может быть глубоко фиолетово на то, что причина полного изменения всех внешних интерфейсов — лишь обостренное чувство прекрасного у разработчика API. Да, это очень мешает двигаться вперед достаточно быстро, но это неизбежные копромиссы на которые крайне желательно идти, если есть желание быть лицом к пользователям. В коммерческом проекте, такой фокус легко просто не прокатит — крупные заказчики скажут «нет» и вы уйдете думать над менее радикальными изменениями и более плавному их внедрению.
Причиной создания версии 2.0 было вовсе не «обострённое чувство прекрасного» — из обострённых чувств мы обратную совместимость никогда не меняем — а вполне конкретные доводы:
— нам требовалось поддерживать соврменные технологии (transform & transition) и новые устройства (тач-девайсы, в первую очередь), чего архитектура первой версии не позволяла;
— нам требовалась гораздо более гибкая и менее связная модульность, нежели это было возможно в рамках версии 1.х
— нам требовалась глубокая локализация, с различными настройками (например, единиц измерения) для разных стран
— наконец, нас не устраивало качество клиентских решений — иными словами, вебмастера делали на нашем АПИ неудобные и неюзабельные сайты, и нам очень хотелось, насколько это возможно, с этим побороться со своей стороны.
Обо всём этом я довольно подробно рассказал в 2012 году на РИТ++ и ещё на нескольких конференциях. Кроме того, версия 2.0 была изначально запущена с подробным гайдом по переходу.
Ваша боль мне ясна; более того, АПИ 2.1 построено именно так, как вы предлагаете — итеративно с весьма незначительными изменениями. Однако, мы стараемся руководствоваться в первую очередь интересами конечных потребителей АПИ, а они на момент 2011 года явно диктовали потребность в радикальном обновлении архитектуры проеекта.
— нам требовалось поддерживать соврменные технологии (transform & transition) и новые устройства (тач-девайсы, в первую очередь), чего архитектура первой версии не позволяла;
— нам требовалась гораздо более гибкая и менее связная модульность, нежели это было возможно в рамках версии 1.х
— нам требовалась глубокая локализация, с различными настройками (например, единиц измерения) для разных стран
— наконец, нас не устраивало качество клиентских решений — иными словами, вебмастера делали на нашем АПИ неудобные и неюзабельные сайты, и нам очень хотелось, насколько это возможно, с этим побороться со своей стороны.
Обо всём этом я довольно подробно рассказал в 2012 году на РИТ++ и ещё на нескольких конференциях. Кроме того, версия 2.0 была изначально запущена с подробным гайдом по переходу.
Ваша боль мне ясна; более того, АПИ 2.1 построено именно так, как вы предлагаете — итеративно с весьма незначительными изменениями. Однако, мы стараемся руководствоваться в первую очередь интересами конечных потребителей АПИ, а они на момент 2011 года явно диктовали потребность в радикальном обновлении архитектуры проеекта.
Как-то работал с очередями сообщении. Если быть точнее — IBM WebSphere MQ.
Вот где поддержка старых версии идет как нигде и никогда.
Например, в оттранслированном заголовочном файле из С в Паскаль:
Вот где поддержка старых версии идет как нигде и никогда.
Например, в оттранслированном заголовочном файле из С в Паскаль:
(****************************************************************)
(* MQCNO Structure -- Connect Options *)
(****************************************************************)
type
MQCNO = record
StrucId : MQCHAR4 ;(* Structure identifier *)
Version : MQLONG ;(* Structure version number *)
Options : MQLONG ;(* Options that control the action of MQCONNX *)
(* Ver:1 *)
ClientConnOffset : MQLONG ;(* Offset of MQCD structure for client connection *)
ClientConnPtr : MQPTR ;(* Address of MQCD structure for client connection *)
(* Ver:2 *)
ConnTag : MQBYTE128;(* Queue-manager connection tag *)
(* Ver:3 *)
SSLConfigPtr : PMQSCO ;(* Address of MQSCO structure for client connection *)
SSLConfigOffset : MQLONG ;(* Offset of MQSCO structure for client connection *)
(* Ver:4 *)
ConnectionId : MQBYTE24 ;(* Unique Connection Identifier *)
SecurityParmsOffset: MQLONG ;(* Offset of MQCSP structure *)
SecurityParmsPtr : PMQCSP ;(* Address of MQCSP structure *)
(* Ver:5 *)
end;
PMQCNO = ^MQCNO;
PPMQCNO = ^PMQCNO;
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Как правильно разрабатывать API с поддержкой обратной совместимости. Семинар в Яндексе