mirror of
https://github.com/twirl/The-API-Book.git
synced 2025-01-23 17:53:04 +02:00
Глава 12
This commit is contained in:
parent
d3d7b9afcd
commit
4c29ab177b
@ -2,10 +2,96 @@
|
||||
|
||||
Как обычно, дадим смысловой определение «обратной совместимости», прежде чем начинать изложение.
|
||||
|
||||
Обратная совместимость — это прежде всего свойство системы API быть стабильной во времени. Это значит следующее: **код, написанный разработчиками с использованием вашего API, продолжает работать функционально корректно в течение длительного времени**. К этому определению есть два больших вопроса, и два уточнения к ним.
|
||||
Обратная совместимость — это всего свойство системы API быть стабильной во времени. Это значит следующее: **код, написанный разработчиками с использованием вашего API, продолжает работать функционально корректно в течение длительного времени**. К этому определению есть два больших вопроса, и два уточнения к ним.
|
||||
|
||||
1. Что значит «функционально корректно»? Это значит, что код продолжает выполнять свою функцию — решать какую-то задачу пользователя. Это не означает, что он продолжает работать одинаково: например, если вы предоставляете UI-библиотеку, то изменение функционально несущественных деталей дизайна, типа глубины теней или формы штриха границы, обратную совместимость не нарушит. А вот, например, изменение размеров компонентов, скорее всего, приведёт к тому, что какие-то пользовательские макеты развалятся.
|
||||
1. Что значит «функционально корректно»?
|
||||
|
||||
2. Что значит «длительное время»? С нашей точки зрения длительность поддержания обратной совместимости следует увязывать с длительностью жизненных циклов приложений в соответствующей предметной области. Хороший ориентир в большинстве случаев — это LTS-периоды платформ. Так как приложение все равно будет переписано в связи с окончанием поддержки платформы, нормально предложить также и переход на новую версию API. В основных предметных областях (веб-приложения) этот срок исчисляется несколькими годами.
|
||||
Это значит, что код продолжает выполнять свою функцию — решать какую-то задачу пользователя. Это не означает, что он продолжает работать одинаково: например, если вы предоставляете UI-библиотеку, то изменение функционально несущественных деталей дизайна, типа глубины теней или формы штриха границы, обратную совместимость не нарушит. А вот, например, изменение размеров визуальных компонентов, скорее всего, приведёт к тому, что какие-то пользовательские макеты развалятся.
|
||||
|
||||
Почему обратную совместимость необходимо поддерживать (в том числе на этапе проектирования API) — понятно из определения. Прекращение работы приложения (полное или частичное) по вине поставщика API — крайне неприятное событие, а то и катастрофа, для любого разработчика, особенно если он платит за это API деньги.
|
||||
2. Что значит «длительное время»?
|
||||
|
||||
С нашей точки зрения длительность поддержания обратной совместимости следует увязывать с длительностью жизненных циклов приложений в соответствующей предметной области. Хороший ориентир в большинстве случаев — это LTS-периоды платформ. Так как приложение все равно будет переписано в связи с окончанием поддержки платформы, нормально предложить также и переход на новую версию API. В основных предметных областях (веб-приложения) этот срок исчисляется несколькими годами.
|
||||
|
||||
Почему обратную совместимость необходимо поддерживать (в том числе на этапе проектирования API) — понятно из определения. Прекращение работы приложения (полное или частичное) по вине поставщика API — крайне неприятное событие, а то и катастрофа, для любого разработчика, особенно если он платит за это API деньги.
|
||||
|
||||
Но развернём теперь проблему в другую сторону: а почему вообще возникает проблема с поддержанием обратной совместимости? Почему мы можем *хотеть* её нарушить? Ответ на этот вопрос, при кажущейся простоте, намного сложнее, чем на предыдущий.
|
||||
|
||||
Мы могли бы сказать, что *обратную совместимость приходится нарушать для расширения функциональности API*. Но это лукавство: новая функциональность на то и *новая*, она не может затронуть старый код, который её не использует. Более честно было бы сказать, что мы *не хотим поддерживать* ту функциональность, которую когда-то предоставили в виде API. По разным причинам:
|
||||
|
||||
* банально морально устарел и требует переписывания сам код, реализующий старую функциональность;
|
||||
|
||||
* новая функциональность не была предусмотрена в старом интерфейсе: мы хотели бы наделить уже существующие сущности новыми свойствами, но не можем, а умножать сущности тоже не очень хороший вариант;
|
||||
|
||||
* наконец, за прошедшее после изначального релиза время мы узнали о предметной области и практике применения нашего API гораздо больше, и сделали бы многие вещи иначе.
|
||||
|
||||
Эти аргументы можно обобщить как «разработчики API не хотят работать со старым кодом», не сильно покривив душой. Но и это вновь подмена вопроса другим: *а что мешает оставить старый код как есть и не трогать его*?
|
||||
|
||||
А вот этот вопрос уже более близок к сути проблемы. Напомним, [API — это мост](https://twirl.github.io/The-API-Book/docs/API.ru.html#chapter-2), средство соединения разных программируемых контекстов. И как бы нам ни хотелось зафиксировать конструкцию моста, наши возможности ограничены: мост-то мы можем зафиксировать — да вот края ущелья, как и само ущелье, не можем. В этом корень проблемы: мы не можем оставить *свой* код без изменений, поэтому нам придётся рано или поздно потребовать, чтобы клиенты изменили *свой*.
|
||||
|
||||
Помимо наших собственных поползновений в сторону изменения архитектуры API, три других тектонических процесса происходит одновременно: размывание клиентов, предметной области и нижележащей платформы.
|
||||
|
||||
#### Фрагментация клиентских приложений
|
||||
|
||||
В тот момент, когда вы выпустили первую версию API, и первые клиенты начали использовать её — ситуация идеальна. Есть только одна версия, и все клиенты работают с ней. А вот дальше возможны два варианта развития событий:
|
||||
|
||||
1. Если платформа поддерживает on-demand получение кода, как старый-добрый Веб, и вы не поленились это получение кода реализовать (в виде платформенного SDK, например, JS API), то развитие API более или менее находится под вашим контролем. Поддержание обратной совместимости сводится к поддержанию обратной совместимости *клиентской библиотеки*, а вот в части сервера и клиент-серверного взаимодействия вы свободны.
|
||||
|
||||
Это не означает, что вы не можете нарушить обратную совместимость — всё ещё можно напортачить с заголовками кэширования SDK или банально допустить баг в коде. Кроме того, даже on-demand системы все равно не обновляются мгновенно — автор сталкивался с ситуацией, когда пользователи намеренно держали вкладку браузера открытой *неделями*, чтобы не обновляться на новые версии. Тем не менее, вам почти не придётся поддерживать более двух (последней и предпоследней) минорных версий клиентского SDK. Более того, вы можете попытаться в какой-то момент переписать предыдущую мажорную версию, имплементировав её на основе API новой версии.
|
||||
|
||||
2. Если поддержка on-demand кода платформой не поддерживается или запрещена условиями, как это произошло с современными мобильными платформами, то ситуация становится гораздо сложнее. По сути, каждый клиент — это «слепок» кода, который работает с вашим API, зафиксированный в том состоянии, в котором он был на момент компиляции. Обновление клиентских приложений по времени растянуто гораздо дольше, нежели Web-приложений; самое неприятное здесь состоит в том, что некоторые клиенты *не обновятся вообще никогда* — по одной из трёх причин:
|
||||
|
||||
* разработчики просто не выпускают новую версию приложения, его развитие заморожено;
|
||||
* пользователь не хочет обновляться (в т.ч. потому, что, по мнению пользователя, разработчики приложения его «испортили» в новых версиях);
|
||||
* пользователь не может обновиться вообще, потому что его устройство больше не поддерживается.
|
||||
|
||||
В современных реалиях все три категории в сумме легко могут составлять десятки процентов аудитории. Это означает, что прекращение поддержки любой версии API является весьма заметным событием — особенно если приложения разработчика поддерживают более широкий спектр версий платформы, нежели ваше API.
|
||||
|
||||
Вы можете не выпускать вообще никаких SDK, предоставляя только серверное API в виде, например, HTTP эндпойнтов. Вам может показаться, что таким образом, пусть ваше API и стало менее конкурентоспособным на рынке из-за отсутствия SDK, вы облегчили себе задачу поддержания обратной совместимости. На самом деле это совершенно не так: раз вы не предоставляете свой SDK — разработчики возьмут или неофициальный SDK (если кто-то его напишет), или просто каждый из них напишет по фреймворку. Стратегия «ваш фреймворк — ваша ответственность», к счастью или к сожалению, работает плохо: если на вашем API пишут некачественные приложения — значит, ваше API само некачественное. Уж точно по мнению разработчиков, а может и по мнению пользователей точно, если работа API внутри приложения пользователю видна.
|
||||
|
||||
Конечно, если ваше API достаточно stateless и не требует клиентских SDK (или же можно обойтись просто автогенерацией SDK из спецификации), эти проблемы будут гораздо менее заметны, но избежать их полностью можно только одним способом — никогда не выпуская новых версий API. Во всех остальных случаях вы будете иметь дело с какой-то гребёнкой распределения количества пользователей по версиям API и версиям SDK.
|
||||
|
||||
#### Эволюция предметной области
|
||||
|
||||
Другая сторона ущелья — та самая нижележащая функциональность, к которой вы предоставляете API. Она, разумеется, тоже не статична и развивается в какую-то сторону:
|
||||
|
||||
* появляется новая функциональность;
|
||||
* старая функциональность перестаёт поддерживаться;
|
||||
* меняются интерфейсы.
|
||||
|
||||
Как правило, API абстрагирует некоторую более гранулярную предметную область. В случае нашего [примера с API кофе-машин](https://twirl.github.io/The-API-Book/docs/API.ru.html#chapter-7) разумно ожидать, что будут появляться новые модели с новым API, которые нам придётся включать в свою платформу, и гарантировать возможность сохранения того же интерфейса абстракции — весьма непросто. Даже если просто добавлять поддержку новых видов нижележащих устройств, не добавляя ничего во внешний интерфейс — это всё равно изменения в коде, которые могут в итоге привести к несовместимости, пусть и ненамеренно.
|
||||
|
||||
Стоит также отметить, что далеко не все поставщики API относятся к поддержанию обратной совместимости, да и вообще к качеству своего ПО, так же серьёзно, как и (надеюсь) вы. Стоит быть готовым к тому, что заниматься поддержанием вашего API в рабочем состоянии, т.е. написанием и поддержкой фасадов к меняющемуся ландшафту предметной области, придётся именно вам, и зачастую довольно внезапно.
|
||||
|
||||
#### Дрифт платформ
|
||||
|
||||
Наконец, есть и третья сторона вопроса — «ущелье», через которое вы перекинул свой мост в виде API. Код, который напишут разработчики, исполняется в некоторой среде, которую вы не можете контролировать, и она тоже эволюционирует. Появляются новые версии операционной системы, браузеров, протоколов, языка SDK. Разрабатываются новые стандарты и принимаются новые соглашения, некоторые из которых сами по себе обратно несовместимы, и поделать с этим ничего нельзя.
|
||||
|
||||
Как и в случае со старыми версиями приложений, старые версии платформ также приводят к фрагментации, поскольку, с одной стороны, разработчикам (в том числе и разработчикам API) объективно тяжело поддерживать старые платформы, а пользователям столь же объективно тяжело обновляться, поскольку обновление операционной системы зачастую невозможно без замены самого устройства на более новое.
|
||||
|
||||
Самое неприятное во всём этом то, что к изменениям в API подталкивает не только поступательный прогресс в виде новых платформ и протоколов, но и банальная мода и вкусовщина. Буквально несколько лет назад были в моде объёмные реалистичные иконки, от которых все отказались в пользу плоских и абстрактных — и большинству разработчиков визуальных компонентов пришлось, вслед за модой, переделывать свои библиотеки, выпуская новые наборы иконок или заменяя старые. Аналогично прямо сейчас повсеместно внедряется поддержка «ночных» тем интерфейсов, что требует изменений в большом количестве API.
|
||||
|
||||
#### Политика обратной совместимости
|
||||
|
||||
Итого, если суммировать:
|
||||
* вследствие итерационного развития приложений, платформ и предметной области вы будете вынуждены выпускать новые версии вашего API, рано или поздно; следует отметить, что в разных областях скорость развития разная, но никогда не нулевая;
|
||||
* вкупе это приведёт к фрагментации используемой версии API по приложениям и платформам;
|
||||
* вам придётся принимать решения, критически влияющие на надёжность вашего API в глазах потребителей.
|
||||
|
||||
Опишем кратко ключевые принципы принятия этих решений.
|
||||
|
||||
1. Как часто выпускать мажорные версии API.
|
||||
|
||||
Это в основном *продуктовый* вопрос. Новая мажорная версия API выпускается, когда накоплена критическая масса функциональности, которую невозможно или слишком дорого поддерживать в рамках предыдущей мажорной версии. В стабильной ситуации такая необходимость возникает, как правило, раз в несколько лет. На динамично развивающихся рынках новые мажорные версии можно выпускать чаще, здесь ограничителем являются только ваши возможности выделить достаточно ресурсов для поддержания зоопарка версий. Однако следует заметить, что выпуск новой мажорной версии до стабилизации предыдущей выглядит для разработчиков очень плохим сигналом, означающим риск *постоянно* сидеть на сырой платформе.
|
||||
|
||||
2. Какое количество версий (мажорных и минорных) поддерживать одновременно.
|
||||
|
||||
Что касается мажорных версий, то *теоретический* ответ мы дали выше: в идеальной ситуации жизненный цикл мажорной версии должен быть чуть длиннее жизненного цикла платформы. Для стабильных ниш типа десктопных операционных систем это порядка 5-10 лет, для новых и динамически развивающихся — меньше, но всё равно несколько лет. *Практически* следует смотреть на долю потребителей, реально продолжающих пользоваться версией.
|
||||
|
||||
Для минорных версий возможны два варианта:
|
||||
* если вы предоставляете только серверное API и компилируемые SDK, вы можете в принципе не поддерживать никакие минорные версии API, помимо актуальной: серверное API находится полностью под вашим контролем, и вы можете оперативно исправить любые проблемы с логикой;
|
||||
* если вы предоставляете code-on-demand SDK, то вот здесь хорошим тоном является поддержка предыдущих минорных версий SDK в работающем состоянии на срок, достаточный для того, чтобы разработчики могли протестировать своё приложение с новой версией и внести какие-то правки по необходимости. Так как полностью переписывать приложения при этом не надо, разумно ориентировать на длину релизных циклов в вашей индустрии, обычно это несколько месяцев в худшем случае.
|
||||
|
||||
3. Каким образом предупреждать потребителей о выходе новых версий и прекращении поддержки старых.
|
||||
4. Каким образом стимулировать потребителей переходить на новые версии API.
|
||||
|
||||
Вопросы \#1 и \#2 мы рассмотрим более подробно в следующих главах. Вопросы \#3 и \#4 относятся скорее к маркетингу и работе с комьюнити, о них речь пойдёт в следующем разделе.
|
Loading…
x
Reference in New Issue
Block a user