1
0
mirror of https://github.com/twirl/The-API-Book.git synced 2025-01-05 10:20:22 +02:00

reference integrity

This commit is contained in:
Sergey Konstantinov 2023-04-07 19:56:48 +03:00
parent 11655f5303
commit dd5a02c148
74 changed files with 699 additions and 601 deletions

View File

@ -3,6 +3,10 @@
{
"language": "markdown",
"scheme": "vscode-vfs"
},
{
"language": "markdown",
"scheme": "file"
}
]
}

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -51,53 +51,53 @@
<ul><li>
<h4><a href="API.en.html#section-1">Introduction</a></h4>
<ul>
<li><a href="API.en.html#chapter-1">Chapter 1. On the Structure of This Book</a></li>
<li><a href="API.en.html#chapter-2">Chapter 2. The API Definition</a></li>
<li><a href="API.en.html#chapter-3">Chapter 3. API Quality Criteria</a></li>
<li><a href="API.en.html#chapter-4">Chapter 4. Backwards Compatibility</a></li>
<li><a href="API.en.html#chapter-5">Chapter 5. On Versioning</a></li>
<li><a href="API.en.html#chapter-6">Chapter 6. Terms and Notation Keys</a></li>
<li><a href="API.en.html#intro-structure">Chapter 1. On the Structure of This Book</a></li>
<li><a href="API.en.html#intro-api-definition">Chapter 2. The API Definition</a></li>
<li><a href="API.en.html#intro-api-quality">Chapter 3. API Quality Criteria</a></li>
<li><a href="API.en.html#intro-back-compat">Chapter 4. On Backwards Compatibility</a></li>
<li><a href="API.en.html#intro-versioning">Chapter 5. On Versioning</a></li>
<li><a href="API.en.html#intro-terms-notation">Chapter 6. Terms and Notation Keys</a></li>
</ul>
</li>
<li>
<h4><a href="API.en.html#section-2">Section I. The API Design</a></h4>
<ul>
<li><a href="API.en.html#chapter-7">Chapter 7. The API Contexts Pyramid</a></li>
<li><a href="API.en.html#chapter-8">Chapter 8. Defining an Application Field</a></li>
<li><a href="API.en.html#chapter-9">Chapter 9. Separating Abstraction Levels</a></li>
<li><a href="API.en.html#chapter-10">Chapter 10. Isolating Responsibility Areas</a></li>
<li><a href="API.en.html#chapter-11">Chapter 11. Describing Final Interfaces</a></li>
<li><a href="API.en.html#chapter-12">Chapter 12. Annex to Section I. Generic API Example</a></li>
<li><a href="API.en.html#api-design-context-pyramid">Chapter 7. The API Contexts Pyramid</a></li>
<li><a href="API.en.html#api-design-defining-field">Chapter 8. Defining an Application Field</a></li>
<li><a href="API.en.html#api-design-separating-abstractions">Chapter 9. Separating Abstraction Levels</a></li>
<li><a href="API.en.html#api-design-isolating-responsibility">Chapter 10. Isolating Responsibility Areas</a></li>
<li><a href="API.en.html#api-design-describing-interfaces">Chapter 11. Describing Final Interfaces</a></li>
<li><a href="API.en.html#api-design-annex">Chapter 12. Annex to Section I. Generic API Example</a></li>
</ul>
</li>
<li>
<h4><a href="API.en.html#section-3">Section II. The Backwards Compatibility</a></h4>
<ul>
<li><a href="API.en.html#chapter-13">Chapter 13. The Backwards Compatibility Problem Statement</a></li>
<li><a href="API.en.html#chapter-14">Chapter 14. On the Waterline of the Iceberg</a></li>
<li><a href="API.en.html#chapter-15">Chapter 15. Extending through Abstracting</a></li>
<li><a href="API.en.html#chapter-16">Chapter 16. Strong Coupling and Related Problems</a></li>
<li><a href="API.en.html#chapter-17">Chapter 17. Weak Coupling</a></li>
<li><a href="API.en.html#chapter-18">Chapter 18. Interfaces as a Universal Pattern</a></li>
<li><a href="API.en.html#chapter-19">Chapter 19. The Serenity Notepad</a></li>
<li><a href="API.en.html#back-compat-statement">Chapter 13. The Backwards Compatibility Problem Statement</a></li>
<li><a href="API.en.html#back-compat-iceberg-waterline">Chapter 14. On the Waterline of the Iceberg</a></li>
<li><a href="API.en.html#back-compat-abstracting-extending">Chapter 15. Extending through Abstracting</a></li>
<li><a href="API.en.html#back-compat-strong-coupling">Chapter 16. Strong Coupling and Related Problems</a></li>
<li><a href="API.en.html#back-compat-weak-coupling">Chapter 17. Weak Coupling</a></li>
<li><a href="API.en.html#back-compat-universal-interfaces">Chapter 18. Interfaces as a Universal Pattern</a></li>
<li><a href="API.en.html#back-compat-serenity-notepad">Chapter 19. The Serenity Notepad</a></li>
</ul>
</li>
<li>
<h4><a href="API.en.html#section-4">Section III. The API Product</a></h4>
<ul>
<li><a href="API.en.html#chapter-20">Chapter 20. API as a Product</a></li>
<li><a href="API.en.html#chapter-21">Chapter 21. The API Business Models</a></li>
<li><a href="API.en.html#chapter-22">Chapter 22. Developing a Product Vision</a></li>
<li><a href="API.en.html#chapter-23">Chapter 23. Communicating with Developers</a></li>
<li><a href="API.en.html#chapter-24">Chapter 24. Communicating with Business Owners</a></li>
<li><a href="API.en.html#chapter-25">Chapter 25. The API Services Range</a></li>
<li><a href="API.en.html#chapter-26">Chapter 26. The API Key Performance Indicators</a></li>
<li><a href="API.en.html#chapter-27">Chapter 27. Identifying Users and Preventing Fraud</a></li>
<li><a href="API.en.html#chapter-28">Chapter 28. The Technical Means of Preventing ToS Violations</a></li>
<li><a href="API.en.html#chapter-29">Chapter 29. Supporting customers</a></li>
<li><a href="API.en.html#chapter-30">Chapter 30. The Documentation</a></li>
<li><a href="API.en.html#chapter-31">Chapter 31. The Testing Environment</a></li>
<li><a href="API.en.html#chapter-32">Chapter 32. Managing expectations</a></li>
<li><a href="API.en.html#api-product">Chapter 20. API as a Product</a></li>
<li><a href="API.en.html#api-product-business-models">Chapter 21. The API Business Models</a></li>
<li><a href="API.en.html#api-product-vision">Chapter 22. Developing a Product Vision</a></li>
<li><a href="API.en.html#api-product-devrel">Chapter 23. Communicating with Developers</a></li>
<li><a href="API.en.html#api-product-business-comms">Chapter 24. Communicating with Business Owners</a></li>
<li><a href="API.en.html#api-product-range">Chapter 25. The API Services Range</a></li>
<li><a href="API.en.html#api-product-kpi">Chapter 26. The API Key Performance Indicators</a></li>
<li><a href="API.en.html#api-product-antifraud">Chapter 27. Identifying Users and Preventing Fraud</a></li>
<li><a href="API.en.html#api-product-tos-violations">Chapter 28. The Technical Means of Preventing ToS Violations</a></li>
<li><a href="API.en.html#api-product-customer-support">Chapter 29. Supporting customers</a></li>
<li><a href="API.en.html#api-product-documentation">Chapter 30. The Documentation</a></li>
<li><a href="API.en.html#api-product-testing">Chapter 31. The Testing Environment</a></li>
<li><a href="API.en.html#api-product-expectations">Chapter 32. Managing expectations</a></li>
</ul>
</li>
</ul>

View File

@ -51,53 +51,53 @@
<ul><li>
<h4><a href="API.ru.html#section-1">Введение</a></h4>
<ul>
<li><a href="API.ru.html#chapter-1">Глава 1. О структуре этой книги</a></li>
<li><a href="API.ru.html#chapter-2">Глава 2. Определение API</a></li>
<li><a href="API.ru.html#chapter-3">Глава 3. Критерии качества API</a></li>
<li><a href="API.ru.html#chapter-4">Глава 4. Обратная совместимость</a></li>
<li><a href="API.ru.html#chapter-5">Глава 5. О версионировании</a></li>
<li><a href="API.ru.html#chapter-6">Глава 6. Условные обозначения и терминология</a></li>
<li><a href="API.ru.html#intro-structure">Глава 1. О структуре этой книги</a></li>
<li><a href="API.ru.html#intro-api-definition">Глава 2. Определение API</a></li>
<li><a href="API.ru.html#intro-api-quality">Глава 3. Критерии качества API</a></li>
<li><a href="API.ru.html#intro-back-compat">Глава 4. Обратная совместимость</a></li>
<li><a href="API.ru.html#intro-versioning">Глава 5. О версионировании</a></li>
<li><a href="API.ru.html#intro-terms-notation">Глава 6. Условные обозначения и терминология</a></li>
</ul>
</li>
<li>
<h4><a href="API.ru.html#section-2">Раздел I. Проектирование API</a></h4>
<ul>
<li><a href="API.ru.html#chapter-7">Глава 7. Пирамида контекстов API</a></li>
<li><a href="API.ru.html#chapter-8">Глава 8. Определение области применения</a></li>
<li><a href="API.ru.html#chapter-9">Глава 9. Разделение уровней абстракции</a></li>
<li><a href="API.ru.html#chapter-10">Глава 10. Разграничение областей ответственности</a></li>
<li><a href="API.ru.html#chapter-11">Глава 11. Описание конечных интерфейсов</a></li>
<li><a href="API.ru.html#chapter-12">Глава 12. Приложение к разделу I. Модельный API</a></li>
<li><a href="API.ru.html#api-design-context-pyramid">Глава 7. Пирамида контекстов API</a></li>
<li><a href="API.ru.html#api-design-defining-field">Глава 8. Определение области применения</a></li>
<li><a href="API.ru.html#api-design-separating-abstractions">Глава 9. Разделение уровней абстракции</a></li>
<li><a href="API.ru.html#api-design-isolating-responsibility">Глава 10. Разграничение областей ответственности</a></li>
<li><a href="API.ru.html#api-design-describing-interfaces">Глава 11. Описание конечных интерфейсов</a></li>
<li><a href="API.ru.html#api-design-annex">Глава 12. Приложение к разделу I. Модельный API</a></li>
</ul>
</li>
<li>
<h4><a href="API.ru.html#section-3">Раздел II. Обратная совместимость</a></h4>
<ul>
<li><a href="API.ru.html#chapter-13">Глава 13. Постановка проблемы обратной совместимости</a></li>
<li><a href="API.ru.html#chapter-14">Глава 14. О ватерлинии айсберга</a></li>
<li><a href="API.ru.html#chapter-15">Глава 15. Расширение через абстрагирование</a></li>
<li><a href="API.ru.html#chapter-16">Глава 16. Сильная связность и сопутствующие проблемы</a></li>
<li><a href="API.ru.html#chapter-17">Глава 17. Слабая связность</a></li>
<li><a href="API.ru.html#chapter-18">Глава 18. Интерфейсы как универсальный паттерн</a></li>
<li><a href="API.ru.html#chapter-19">Глава 19. Блокнот душевного покоя</a></li>
<li><a href="API.ru.html#back-compat-statement">Глава 13. Постановка проблемы обратной совместимости</a></li>
<li><a href="API.ru.html#back-compat-iceberg-waterline">Глава 14. О ватерлинии айсберга</a></li>
<li><a href="API.ru.html#back-compat-abstracting-extending">Глава 15. Расширение через абстрагирование</a></li>
<li><a href="API.ru.html#back-compat-strong-coupling">Глава 16. Сильная связность и сопутствующие проблемы</a></li>
<li><a href="API.ru.html#back-compat-weak-coupling">Глава 17. Слабая связность</a></li>
<li><a href="API.ru.html#back-compat-universal-interfaces">Глава 18. Интерфейсы как универсальный паттерн</a></li>
<li><a href="API.ru.html#back-compat-serenity-notepad">Глава 19. Блокнот душевного покоя</a></li>
</ul>
</li>
<li>
<h4><a href="API.ru.html#section-4">Раздел III. API как продукт</a></h4>
<ul>
<li><a href="API.ru.html#chapter-20">Глава 20. Продукт API</a></li>
<li><a href="API.ru.html#chapter-21">Глава 21. Бизнес-модели API</a></li>
<li><a href="API.ru.html#chapter-22">Глава 22. Формирование продуктового видения</a></li>
<li><a href="API.ru.html#chapter-23">Глава 23. Взаимодействие с разработчиками</a></li>
<li><a href="API.ru.html#chapter-24">Глава 24. Взаимодействие с бизнес-аудиторией</a></li>
<li><a href="API.ru.html#chapter-25">Глава 25. Линейка сервисов API</a></li>
<li><a href="API.ru.html#chapter-26">Глава 26. Ключевые показатели эффективности API</a></li>
<li><a href="API.ru.html#chapter-27">Глава 27. Идентификация пользователей и борьба с фродом</a></li>
<li><a href="API.ru.html#chapter-28">Глава 28. Технические способы борьбы с несанкционированным доступом к API</a></li>
<li><a href="API.ru.html#chapter-29">Глава 29. Поддержка пользователей API</a></li>
<li><a href="API.ru.html#chapter-30">Глава 30. Документация</a></li>
<li><a href="API.ru.html#chapter-31">Глава 31. Тестовая среда</a></li>
<li><a href="API.ru.html#chapter-32">Глава 32. Управление ожиданиями</a></li>
<li><a href="API.ru.html#api-product">Глава 20. Продукт API</a></li>
<li><a href="API.ru.html#api-product-business-models">Глава 21. Бизнес-модели API</a></li>
<li><a href="API.ru.html#api-product-vision">Глава 22. Формирование продуктового видения</a></li>
<li><a href="API.ru.html#api-product-devrel">Глава 23. Взаимодействие с разработчиками</a></li>
<li><a href="API.ru.html#api-product-business-comms">Глава 24. Взаимодействие с бизнес-аудиторией</a></li>
<li><a href="API.ru.html#api-product-range">Глава 25. Линейка сервисов API</a></li>
<li><a href="API.ru.html#api-product-kpi">Глава 26. Ключевые показатели эффективности API</a></li>
<li><a href="API.ru.html#api-product-antifraud">Глава 27. Идентификация пользователей и борьба с фродом</a></li>
<li><a href="API.ru.html#api-product-tos-violations">Глава 28. Технические способы борьбы с несанкционированным доступом к API</a></li>
<li><a href="API.ru.html#api-product-customer-support">Глава 29. Поддержка пользователей API</a></li>
<li><a href="API.ru.html#api-product-documentation">Глава 30. Документация</a></li>
<li><a href="API.ru.html#api-product-testing">Глава 31. Тестовая среда</a></li>
<li><a href="API.ru.html#api-product-expectations">Глава 32. Управление ожиданиями</a></li>
</ul>
</li>
</ul>

View File

@ -5,7 +5,7 @@
"author": "Sergey Konstantinov <twirl-team@yandex.ru>",
"repository": "github.com:twirl/The-API-Book",
"devDependencies": {
"@twirl/book-builder": "0.0.19",
"@twirl/book-builder": "0.0.22",
"html-docx-js": "^0.3.1",
"nodemon": "^2.0.19",
"puppeteer": "^13.1.2"

View File

@ -1,5 +1,5 @@
### On the Structure of This Book
### [On the Structure of This Book][intro-structure]
The book you're holding in your hands comprises this Introduction and three sections: “The API Design,” “The Backwards Compatibility,” and “The API Product.”
In Section I, we will discuss designing APIs as a concept: how to build the architecture properly, from high-level planning down to final interfaces.

View File

@ -1,4 +1,4 @@
### The API Definition
### [The API Definition][intro-api-definition]
Before we start talking about the API design, we need to explicitly define what the API is. Encyclopedia tells us that “API” is an acronym for the “Application Program Interface.” This definition is fine, but useless. Much like the “Man” definition by Plato: Man stood upright on two legs without feathers. This definition is fine again, but it gives us no understanding of what's so important about a Man. (Actually, not “fine” either. Diogenes of Sinope once brought a plucked chicken, saying “That's Plato's Man.” And Plato had to add “with broad nails” to his definition.)

View File

@ -1,4 +1,4 @@
### API Quality Criteria
### [API Quality Criteria][intro-api-quality]
Before we start laying out the recommendations, we ought to specify what API we consider “fine,” and what's the profit of having a “fine” API.

View File

@ -1,4 +1,4 @@
### On Backwards Compatibility
### [On Backwards Compatibility][intro-back-compat]
Backwards compatibility is a *temporal* characteristic of your API. An obligation to maintain backwards compatibility is the crucial point where API development differs from software development in general.

View File

@ -1,4 +1,4 @@
### On Versioning
### [On Versioning][intro-versioning]
Here and throughout this book, we firmly stick to [semver](https://semver.org/) principles of versioning.
@ -11,4 +11,4 @@ Sentences “a major API version” and “new API version, containing backwards
It is usually (though not necessary) agreed that the last stable API release might be referenced by either a full version (e.g. `1.2.3`) or a reduced one (`1.2` or just `1`). Some systems support more sophisticated schemes of defining the desired version (for example, `^1.2.3` reads like “get the last stable API release that is backwards-compatible to the `1.2.3` version”) or additional shortcuts (for example, `1.2-beta` to refer to the last beta release of the `1.2` API version family). In this book, we will mostly use designations like `v1` (`v2`, `v3`, etc.) to denote the latest stable release of the `1.x.x` version family of an API.
The practical meaning of this versioning system and the applicable policies will be discussed in more detail in the “Backwards Compatibility Problem Statement” chapter.
The practical meaning of this versioning system and the applicable policies will be discussed in more detail in the [“Backwards Compatibility Problem Statement”](#back-compat-statement) chapter.

View File

@ -1,4 +1,4 @@
### Terms and Notation Keys
### [Terms and Notation Keys][intro-terms-notation]
Software development is characterized, among other things, by the existence of many different engineering paradigms, whose adepts sometimes are quite aggressive towards other paradigms' adepts. While writing this book, we are deliberately avoiding using terms like “method,” “object,” “function,” and so on, using the neutral term “entity” instead. “Entity” means some atomic functionality unit, like class, method, object, monad, prototype (underline what you think is right).

View File

@ -1,4 +1,4 @@
### The API Contexts Pyramid
### [The API Contexts Pyramid][api-design-context-pyramid]
The approach we use to design APIs comprises four steps:
* defining an application field

View File

@ -1,4 +1,4 @@
### Defining an Application Field
### [Defining an Application Field][api-design-defining-field]
The key question you should ask yourself before we start developing any software product, including an API, is: what problem do we solve? It should be asked four times, each time putting an emphasis on another word.

View File

@ -1,4 +1,4 @@
### Separating Abstraction Levels
### [Separating Abstraction Levels][api-design-separating-abstractions]
“Separate abstraction levels in your code” is possibly the most general advice to software developers. However, we don't think it would be a grave exaggeration to say that abstraction levels separation is also the most difficult task for API developers.

View File

@ -1,4 +1,4 @@
### Isolating Responsibility Areas
### [Isolating Responsibility Areas][api-design-isolating-responsibility]
In the previous chapter, we concluded that the hierarchy of abstractions in our hypothetical project would comprise:

View File

@ -1,4 +1,4 @@
### Describing Final Interfaces
### [Describing Final Interfaces][api-design-describing-interfaces]
When all entities, their responsibilities, and their relations to each other are defined, we proceed to the development of the API itself. We are to describe the objects, fields, methods, and functions nomenclature in detail. In this chapter, we're giving purely practical advice on making APIs usable and understandable.
@ -1096,7 +1096,7 @@ However, if we take a deeper look, all these disadvantages are actually imaginat
* finally, this naïve approach to organizing collaborative editing works only with transitive changes (e.g. if the final result does not depend on the order in which the operations were executed), and in our case, it's already not true: deletion of the first element and editing the second element are non-transitive;
* often, in addition to sparing traffic on requests, the same concept is applied to responses as well, e.g. no data is returned for modifying operations; thus two clients making simultaneous edits do not see one another's changes.
**Better**: split the functionality. This also correlates well with the [decomposition principle](#chapter-10) we've discussed in the previous chapter.
**Better**: split the functionality. This also correlates well with the decomposition principle we've discussed in the previous chapter.
```
// Creates an order comprising

View File

@ -1,4 +1,4 @@
### Annex to Section I. Generic API Example
### [Annex to Section I. Generic API Example][api-design-annex]
Let's summarize the current state of our API study.

View File

@ -1,4 +1,4 @@
### The Backwards Compatibility Problem Statement
### [The Backwards Compatibility Problem Statement][back-compat-statement]
As usual, let's conceptually define “backwards compatibility” before we start.
@ -10,31 +10,31 @@ Backwards compatibility is a feature of the entire API system to be stable in ti
2. What does “a long period of time” mean?
From our point of view, the backwards compatibility maintenance period should be reconciled with the typical lifetime of appliactions in the subject area. Platform LTS periods are decent guidance in most cases. Since apps will be rewritten anyway when the platform maintenance period ends, it is reasonable to expect developers to move to the new API version as well. In mainstream subject areas (e.g. desktop and mobile operating systems) this period lasts several years.
From our point of view, the backwards compatibility maintenance period should be reconciled with the typical lifetime of applications in the subject area. Platform LTS periods are decent guidance in most cases. Since the applications will be rewritten anyway when the platform maintenance period ends, it is reasonable to expect developers to move to the new API version as well. In mainstream subject areas (e.g. desktop and mobile operating systems) this period lasts several years.
From the definition becomes obvious why backwards compatibility needs to be maintained (including taking necessary measures at the API design stage). An outage, full or partial, caused by the API vendor, is an extremely uncomfortable situation for every developer, if not a disaster — especially if they pay money for the API usage.
From the definition becomes obvious why backwards compatibility needs to be maintained (including taking necessary measures at the API design stage). An outage, full or partial, caused by an API vendor, is an extremely uncomfortable situation for every developer, if not a disaster — especially if they pay money for the API usage.
But let's take a look at the problem from another angle: why the maintaining backwards compatibility problem exists at all? Why would anyone *want* to break it? This question, though it looks quite trivial, is much more complicated than the previous one.
But let's take a look at the problem from another angle: why the problem of maintaining backwards compatibility exists in the first place? Why would anyone *want* to break it? This question, though it looks quite trivial, is much more complicated than the previous one.
We could say the *we break backwards compatibility to introduce new features to the API*. But that would be deceiving: new features are called *“new”* just because they cannot affect existing implementations which are not using them. We must admit there are several associated problems, which lead to the aspiration to rewrite *our* code, the code of the API itself, and ship a new major version:
We could say that *we break backwards compatibility to introduce new features to the API*. But that would be deceiving: new features are called *“new”* for a reason, as they cannot affect existing implementations which are not using them. We must admit there are several associated problems, which lead to the aspiration to rewrite *our* code, the code of the API itself, and ship a new major version:
* the code eventually becomes outdated; making changes, even introducing totally new functionality, becomes impractical;
* the codebase eventually becomes outdated; making changes, even introducing totally new functionality, becomes impractical;
* the old interfaces aren't suited to encompass new features; we would love to extend existing entities with new properties, but we simply couldn't;
* the old interfaces aren't suited to encompass new features; we would love to extend existing functionality with new properties, but we simply couldn't;
* finally, with years passing since the initial release, we have understood more about the subject area and API usage best practices, and we would implement many things differently.
* finally, with years passing since the initial release, we have understood more about the subject area and API best practices, and we would implement many things differently.
These arguments could be summarized frankly as “the API vendors don't want to support the old code.” But this explanation is still incomplete: even if you're not going to rewrite the API code to add new functionality, or you're not going to add it at all, you still have to ship new API versions, minor and major alike.
**NB**: in this chapter, we don't make any difference between minor versions and patches: “minor version” means any backwards-compatible API release.
Let us remind that [an API is a bridge]((https://twirl.github.io/The-API-Book/docs/API.en.html#chapter-2)), a meaning of connecting different programmable contexts. No matter how strong our desire to keep the bridge intact is, our capabilities are limited: we could lock the bridge, but we cannot command the rifts and the canyon itself. That's the source of the problems: we can't guarantee that *our own* code won't change. So at some point, we will have to ask the clients to rewrite *their* code.
Let us remind the reader that [an API is a bridge](#intro-api-definition), a meaning of connecting different programmable contexts. No matter how strong our desire to keep the bridge intact is, our capabilities are limited: we could lock the bridge, but we cannot command the rifts and the canyon itself. That's the source of the problems: we can't guarantee that *our own* code won't change. So at some point, we will have to ask the clients to rewrite *their* code.
Apart from our aspirations to change the API architecture, three other tectonic processes are happening at the same time: user agents, subject areas, and underlying platforms erosion.
#### Consumer applications fragmentation
#### The fragmentation of consumer applications
When you shipped the very first API version, and the first clients started to use it, the situation was perfect. There was only one version, and all clients were using only it. When this perfection ends, two scenarios are possible.
When you shipped the very first API version, and the very first clients started to use it, the situation was perfect. There was only one version, and all clients were using only it. When this perfection ends, two scenarios are possible.
1. If the platform allows for fetching code on-demand as the good old Web does, and you weren't too lazy to implement that code-on-demand feature (in a form of a platform SDK — for example, JS API), then the evolution of your API is more or less under your control. Maintaining backwards compatibility effectively means keeping *the client library* backwards-compatible. As for client-server interaction, you're free.
@ -112,4 +112,4 @@ The important (and undeniable) advantage of the *semver* system is that it provi
Of course, preserving minor versions infinitely isn't possible (partly because of security and compliance issues that tend to pile up). However, providing such access for a reasonable period of time is rather a hygienic norm for popular APIs.
**NB**. Sometimes to defend the single accessible API version concept, the following argument is put forward: preserving the SDK or API application server code is not enough to maintain strict backwards compatibility as it might be relying on some un-versioned services (for example, some data in the DB that are shared between all the API versions). We, however, consider this an additional reason to isolate such dependencies (see “The Serenity Notepad” chapter) as it means that changes to these subsystems might lead to the inoperability of the API.
**NB**. Sometimes to defend the single accessible API version concept, the following argument is put forward: preserving the SDK or API application server code is not enough to maintain strict backwards compatibility as it might be relying on some un-versioned services (for example, some data in the DB that are shared between all the API versions). We, however, consider this an additional reason to isolate such dependencies (see [“The Serenity Notepad”](#back-compat-serenity-notepad) chapter) as it means that changes to these subsystems might lead to the inoperability of the API.

View File

@ -1,4 +1,4 @@
### On the Waterline of the Iceberg
### [On the Waterline of the Iceberg][back-compat-iceberg-waterline]
Before we start talking about the extensible API design, we should discuss the hygienic minimum. A huge number of problems would have never happened if API vendors had paid more attention to marking their area of responsibility.

View File

@ -1,8 +1,8 @@
### Extending through Abstracting
### [Extending through Abstracting][back-compat-abstracting-extending]
In the previous chapters, we have tried to outline theoretical rules and illustrate them with practical examples. However, understanding the principles of the change-proof API design requires practice above all things. An ability to anticipate future growth problems comes from a handful of grave mistakes once made. One cannot foresee everything but can develop a certain technical intuition.
So, in the following chapters, we will try to probe [our study API](#chapter-12) from the previous Section, testing its robustness from every possible viewpoint, thus carrying out some “variational analysis” of our interfaces. More specifically, we will apply a “What If?” question to every entity, as if we are to provide a possibility to write an alternate implementation of every piece of logic.
So, in the following chapters, we will try to probe [our study API](#api-design-annex) from the previous Section, testing its robustness from every possible viewpoint, thus carrying out some “variational analysis” of our interfaces. More specifically, we will apply a “What If?” question to every entity, as if we are to provide a possibility to write an alternate implementation of every piece of logic.
**NB**. In our examples, the interfaces will be constructed in a manner allowing for dynamic real-time linking of different entities. In practice, such integrations usually imply writing an ad hoc server-side code in accordance with specific agreements made with specific partners. But for educational purposes, we will pursue more abstract and complicated ways. Dynamic real-time linking is more typical in complex program constructs like operating system APIs or embeddable libraries; giving educational examples based on such sophisticated systems would be too inconvenient.
@ -83,7 +83,7 @@ More specifically, if we talk about changing available order options, we should
Usually, just adding a new optional parameter to the existing interface is enough; in our case, adding non-mandatory `options` to the `PUT /coffee-machines` endpoint.
**NB**. When we talk about defining the contract as it works right now, we're talking about *internal* agreements. We must have asked partners to support those three options while negotiating the interaction format. If we had failed to do so from the very beginning, and now are defining these in a course of expanding the public API, it's a very strong claim to break backwards compatibility, and we should never do that (see [Chapter 14](#chapter-14)).
**NB**. When we talk about defining the contract as it works right now, we're talking about *internal* agreements. We must have asked partners to support those three options while negotiating the interaction format. If we had failed to do so from the very beginning, and now are defining these in a course of expanding the public API, it's a very strong claim to break backwards compatibility, and we should never do that (see the previous chapter).
#### Limits of Applicability

View File

@ -1,4 +1,4 @@
### Strong Coupling and Related Problems
### [Strong Coupling and Related Problems][back-compat-strong-coupling]
To demonstrate the strong coupling problematics let us move to *really interesting* things. Let's continue our “variation analysis”: what if the partners wish to offer not only the standard beverages but their own unique coffee recipes to end-users? There is a catch in this question: the partner API as we described it in the previous chapter does not expose the very existence of the partner network to the end-user, and thus describes a simple case. Once we start providing methods to alter the core functionality, not just API extensions, we will soon face next-level problems.
@ -22,7 +22,7 @@ POST /v1/recipes
At first glance, again, it looks like a reasonably simple interface, explicitly decomposed into abstraction levels. But let us imagine the future — what would happen with this interface when our system evolves further?
The first problem is obvious to those who read [chapter 11](#chapter-11-paragraph-20) thoroughly: product properties must be localized. That will lead us to the first change:
The first problem is obvious to those who read the [“Describing Final Interfaces”](#api-design-describing-interfaces) chapter thoroughly: product properties must be localized. That will lead us to the first change:
```
"product_properties": {
@ -198,7 +198,7 @@ POST /v1/recipe-builder
}
```
We should also note that providing a newly created entity identifier by the requesting side isn't exactly the best pattern. However, since we decided from the very beginning to keep recipe identifiers semantically meaningful, we have to live with this convention. Obviously, we're risking getting lots of collisions on recipe names used by different partners, so we actually need to modify this operation: either the partner must always use a pair of identifiers (i.e. recipe's one plus partner's own id), or we need to introduce composite identifiers, as we recommended earlier in [Chapter 11](#chapter-11-paragraph-8).
We should also note that providing a newly created entity identifier by the requesting side isn't exactly the best pattern. However, since we decided from the very beginning to keep recipe identifiers semantically meaningful, we have to live with this convention. Obviously, we're risking getting lots of collisions on recipe names used by different partners, so we actually need to modify this operation: either the partner must always use a pair of identifiers (i.e. recipe's one plus partner's own id), or we need to introduce composite identifiers, as we recommended earlier in the [“Describing Final Interfaces”](#api-design-describing-interfaces) chapter.
```
POST /v1/recipes/custom

View File

@ -1,6 +1,6 @@
### Weak Coupling
### [Weak Coupling][back-compat-weak-coupling]
In the previous chapter we've demonstrated how breaking the strong coupling of components leads to decomposing entities and collapsing their public interfaces down to a reasonable minimum. A mindful reader might have noted that this technique was already used in our API study much earlier in [Chapter 9](#chapter-9) with regards to the “program” and “program run” entities. Indeed, we might do it without the `program-matcher` endpoint and make it this way:
In the previous chapter we've demonstrated how breaking the strong coupling of components leads to decomposing entities and collapsing their public interfaces down to a reasonable minimum. A mindful reader might have noted that this technique was already used in our API study much earlier in the [“Separating Abstraction Levels”](#api-design-separating-abstractions) chapter with regards to the “program” and “program run” entities. Indeed, we might do it without the `program-matcher` endpoint and make it this way:
```
GET /v1/recipes/{id}/run-data/{api_type}
@ -17,7 +17,7 @@ Then developers would have to make this trick to get coffee prepared:
Obviously, such an interface is absolutely unacceptable, simply because in the majority of use cases developers don't care at all, which API type the specific coffee machine runs. To avoid the necessity of introducing such bad interfaces we created a new “program” entity, which constitutes merely a context identifier, just like a “recipe” entity does. A `program_run_id` entity is also organized in this manner, it also possesses no specific properties, being *just* a program run identifier.
But let us return to the question we have previously mentioned in [Chapter 15](#chapter-15): how should we parametrize the order preparation process implemented via third-party API. In other words, what's this `program_execution_endpoint` that we ask upon the API type registration?
But let us return to the question we have previously mentioned in the previous chapter: how should we parametrize the order preparation process implemented via third-party API. In other words, what's this `program_execution_endpoint` that we ask upon the API type registration?
```
PUT /v1/api-types/{api_type}
@ -80,7 +80,7 @@ So, how would we tackle this issue? Using one of two possible approaches: either
* the higher-level program API level doesn't actually know how the execution of its commands works; it formulates the tasks at its own level of understanding: brew this recipe, sprinkle with cinnamon, allow this user to take it;
* the underlying program execution API level doesn't care what other same-level implementations exist; it just interprets those parts of the task which make sense to it.
If we take a look at the principles described in the previous chapter, we would find that this principle was already formulated: we need to describe *informational contexts* at every abstraction level and design a mechanism to translate them between levels. Furthermore, in a more general sense, we formulated it as early as in [“The Data Flow” paragraph of Chapter 9](#chapter-9).
If we take a look at the principles described in the previous chapter, we would find that this principle was already formulated: we need to describe *informational contexts* at every abstraction level and design a mechanism to translate them between levels. Furthermore, in a more general sense, we formulated it as early as in “The Data Flow” paragraph of the [“Separating Abstraction Levels”](#api-design-separating-abstractions) chapter.
In our case we need to implement the following mechanisms:
* running a program creates a corresponding context comprising all the essential parameters;
@ -229,7 +229,7 @@ ProgramContext.dispatch = (action) => {
#### Test Yourself
So, we have designed the interaction with third-party APIs as described in the previous paragraph. And now we should (actually, must) check whether these interfaces are compatible with our own abstraction we had developed in the [Chapter 9](#chapter-9). In other words, could we start an execution of an order if we operate the low-level API instead of the high-level one?
So, we have designed the interaction with third-party APIs as described in the previous paragraph. And now we should (actually, must) check whether these interfaces are compatible with our own abstraction we had developed in the [“Separating Abstraction Levels”](#api-design-separating-abstractions) chapter. In other words, could we start order execution if we operate the low-level API instead of the high-level one?
Let us recall that we had proposed the following abstract interfaces to work with arbitrary coffee machine API types:
@ -274,4 +274,4 @@ From what was said, one more important conclusion follows: doing a real job, e.g
Contrariwise, applying the paradigm of concretizing the contexts at each new abstraction level, we will eventually fall into the bunny hole deep enough to have nothing to concretize: the context itself unambiguously matches the functionality we can programmatically control. And at that level, we must stop detailing contexts further, and just realize the algorithms needed. Worth mentioning that the abstraction deepness for different underlying platforms might vary.
**NB**. In the [Chapter 9](#chapter-9) we have illustrated exactly this: when we speak about the first coffee machine API type, there is no need to extend the tree of abstractions further than running programs, but with the second API type, we need one more intermediary abstraction level, namely the runtimes API.
**NB**. In the [“Separating Abstraction Levels”](#api-design-separating-abstractions) chapter we have illustrated exactly this: when we speak about the first coffee machine API type, there is no need to extend the tree of abstractions further than running programs, but with the second API type, we need one more intermediary abstraction level, namely the runtimes API.

View File

@ -1,4 +1,4 @@
### Interfaces as a Universal Pattern
### [Interfaces as a Universal Pattern][back-compat-universal-interfaces]
Let us summarize what we have written in the three previous chapters.
@ -23,7 +23,7 @@ Then we would have come to the understanding that a “search result” is actua
So our interface (let us call it `ISearchResult`) is actually a composition of two other interfaces: `IOrderParameters` (an entity that allows for creating an order) and `ISearchItemViewParameters` (some abstract representation of the search result in the UI). This interface split should automatically lead us to additional questions.
1. How will we couple the former and the latter? Obviously, these two sub-interfaces are related: the machine-readable price must match the human-readable one, for example. This will naturally lead us to the “formatter” concept described in the [Chapter 16](#chapter-16).
1. How will we couple the former and the latter? Obviously, these two sub-interfaces are related: the machine-readable price must match the human-readable one, for example. This will naturally lead us to the “formatter” concept described in the [“Strong Coupling and Related Problems”](#back-compat-strong-coupling) chapter.
2. And what is the “abstract representation of the search result in the UI”? Do we have other kinds of search, should the `ISearchItemViewParameters` interface be a subtype of some even more general interface, or maybe a composition of several such ones?

View File

@ -1,4 +1,4 @@
### The Serenity Notepad
### [The Serenity Notepad][back-compat-serenity-notepad]
Apart from the abovementioned abstract principles, let us give a list of concrete recommendations: how to make changes in the existing API to maintain the backwards compatibility.
@ -20,7 +20,7 @@ Any software must be tested, and APIs ain't an exclusion. However, there are som
##### Isolate the dependencies
In the case of a gateway API that provides access to some underlying API or aggregates several APIs behind a single façade, there is a strong temptation to proxy the original interface as is, thus not introducing any changes to it and making a life much simpler by sparing an effort needed to implement the weak-coupled interaction between services. For example, while developing program execution interfaces as described in the [Chapter 9](#chapter-9) we might have taken the existing first-kind coffee-machine API as a role model and provided it in our API by just proxying the requests and responses as is. Doing so is highly undesirable because of several reasons:
In the case of a gateway API that provides access to some underlying API or aggregates several APIs behind a single façade, there is a strong temptation to proxy the original interface as is, thus not introducing any changes to it and making a life much simpler by sparing an effort needed to implement the weak-coupled interaction between services. For example, while developing program execution interfaces as described in the [“Separating Abstraction Levels”](#api-design-separating-abstractions) chapter we might have taken the existing first-kind coffee-machine API as a role model and provided it in our API by just proxying the requests and responses as is. Doing so is highly undesirable because of several reasons:
* usually, you have no guarantees that the partner will maintain backwards compatibility or at least keep new versions more or less conceptually akin to the older ones;
* any partner's problem will automatically ricochet into your customers.
@ -36,7 +36,7 @@ The best practice is quite the opposite: isolate the third-party API usage, e.g.
There is an antipattern that occurs frequently: API developers use some internal closed implementations of some methods which exist in the public API. It happens because of two reasons:
* often the public API is just an addition to the existing specialized software, and the functionality, exposed via the API, isn't being ported back to the closed part of the project, or the public API developers simply don't know the corresponding internal functionality exists;
* on a course of extending the API, some interfaces become abstract, but the existing functionality isn't affected; imagine that while implementing the `PUT /formatters` interface described in the [Chapter 16](#chapter-16) developers have created a new, more general version of the volume formatter but hasn't changed the implementation of the existing one, so it continues working in case of pre-existing languages.
* on a course of extending the API, some interfaces become abstract, but the existing functionality isn't affected; imagine that while implementing the `PUT /formatters` interface described in the the [“Strong Coupling and Related Problems”](#back-compat-strong-coupling) chapter developers have created a new, more general version of the volume formatter but hasn't changed the implementation of the existing one, so it continues working in case of pre-existing languages.
There are obvious local problems with this approach (like the inconsistency in functions' behavior, or the bugs which were not found while testing the code), but also a bigger one: your API might be simply unusable if a developer tries any non-mainstream approach, because of performance issues, bugs, instability, etc.

View File

@ -1,4 +1,4 @@
### API as a Product
### [API as a Product][api-product]
There are two important statements regarding APIs viewed as products.

View File

@ -1,4 +1,4 @@
### The API Business Models
### [The API Business Models][api-product-business-models]
Before we proceed to the API product management principles description, let us draw your attention to the issue of profits that companies providing APIs might extract from it. As we will demonstrate in the next chapters, this issue directly affects making product decisions and setting KPIs for the API team. [In brackets, we will provide examples of such models applicable to our coffee-machine API study.]
@ -45,7 +45,7 @@ B2B services are a special case. As B2B Service providers benefit from offering
* internal customers usually employ quite a specific technological stack, and the API is poorly optimized to work with other programming languages / operating systems / frameworks;
* internal customers are much more familiar with the API concepts; they might take a look at the source code or talk to the API developers directly, so the learning curve is pretty flat for them;
* documentation only covers some subset of use-cases needed by internal customers;
* the API services ecosystem which we will describe in the corresponding chapter later usually doesn't exist.
* the API services ecosystem which we will describe in [“The API Services Range”](#api-product-range) chapter later usually doesn't exist.
* Any resources spent are directed to covering internal customer needs first. It means the following:
* API development plans are totally opaque to partners, and sometimes look just absurdly with obvious problems being neglected for years;
* technical support of external customers is financed on leftovers.

View File

@ -1,4 +1,4 @@
### Developing a Product Vision
### [Developing a Product Vision][api-product-vision]
The above-mentioned fragmentation of the API target audience, e.g. the “developers — business — end users” triad, makes API product management quite a non-trivial problem. Yes, the basics are the same: find your auditory's needs and satisfy them; the problem is that your product has several different auditories, and their interests sometimes diverge. The end users' request for an affordable cup of coffee does not automatically imply business demand for a coffee machine API.
@ -17,7 +17,7 @@ As both approaches are still heuristic, the API product vision is inevitably fuz
The same fuzziness should be kept in mind while making interviews and getting feedback. Software engineers will mainly report the problems they've got with the technical integrations, and rarely speak of business-related issues; meanwhile, business owners care little about code-writing inconvenience. Both will have some knowledge regarding the end users problems, but it's usually limited to the market segment the partner operates on.
If you do have an access to end users actions monitoring (see the “API KPIs” chapter), then you might try to analyze the typical user behavior through these logs, and understand how users interact with the partners' applications. But you will need to make this analysis on a per-application basis, and try to clusterize the most common scenarios.
If you do have an access to end users actions monitoring (see [“The API Key Performance Indicators”](#api-product-kpi) chapter), then you might try to analyze the typical user behavior through these logs, and understand how users interact with the partners' applications. But you will need to make this analysis on a per-application basis, and try to clusterize the most common scenarios.
#### Checking product hypotheses

View File

@ -1,4 +1,4 @@
### Communicating with Developers
### [Communicating with Developers][api-product-devrel]
As we have described in the previous chapters, managing an API product requires building relations with both business partners and developers. (Ideally, with end users as well; though this option is seldom available to API providers.)
@ -52,4 +52,4 @@ It will be more correct if we say that you're actually working for two main audi
* professional developers who possess a vast experience in integrating different third-party systems;
* beginners and amateurs, for whom each of those integration tasks would be completely new and unexplored territory.
This fact greatly affects everything we had discussed previously (except for, maybe, open-sourcing, as amateur developers pay little attention to it). Your pitches, webinars, lectures, etc., must somehow fit both professional and semi-professional auditories. There is a popular opinion that you actually can't satisfy both: the former seeks extensive customization capabilities (as they usually work in big IT companies that have a specific mindset regarding those integrations) while the latter just needs the gentlest possible learning curve. We would rather disagree with that, the reasons to be discussed in the “API Services Range” chapter.
This fact greatly affects everything we had discussed previously (except for, maybe, open-sourcing, as amateur developers pay little attention to it). Your pitches, webinars, lectures, etc., must somehow fit both professional and semi-professional auditories. There is a popular opinion that you actually can't satisfy both: the former seeks extensive customization capabilities (as they usually work in big IT companies that have a specific mindset regarding those integrations) while the latter just needs the gentlest possible learning curve. We would rather disagree with that, the reasons to be discussed in [“The API Services Range”](#api-product-range) chapter.

View File

@ -1,4 +1,4 @@
### Communicating with Business Owners
### [Communicating with Business Owners][api-product-business-comms]
The basics of interacting with business partners are to some extent paradoxically contrary to the basics of communicating with developers:
* on one side, partners are much more loyal and sometimes even enthusiastic regarding opportunities you offer (especially free ones);
@ -6,6 +6,6 @@ The basics of interacting with business partners are to some extent paradoxicall
After all, working with business auditory essentially means lucidly explaining the characteristics and the advantages of the product. In that sense, API “sells” just like any other kind of software.
As a rule, the farther some industry sector is from information technologies, the more enthusiastic its representatives are about your API features, and the less the chance is that this enthusiasm will be converted into a real integration. The one thing that should help the case is extensive work with the community (see the corresponding chapter) that will result in establishing a circle of freelances and outsourcers eager to help non-IT businesses with integrations. You might help develop this market by the creation of educational courses and issuing certificates proving the bearer's skills of working with your API (or some broader layer of technology).
As a rule, the farther some industry sector is from information technologies, the more enthusiastic its representatives are about your API features, and the less the chance is that this enthusiasm will be converted into a real integration. The one thing that should help the case is extensive work with the developer community (see the previous chapter) that will result in establishing a circle of freelances and outsourcers eager to help non-IT businesses with integrations. You might help develop this market by the creation of educational courses and issuing certificates proving the bearer's skills of working with your API (or some broader layer of technology).
Market research and getting feedback from business owners work similarly. Those businesses that are far from IT usually can't formulate their demands, so you should be rather creative (and critical-minded) while analyzing the gathered data.

View File

@ -1,4 +1,4 @@
### The API Services Range
### [The API Services Range][api-product-range]
The important rule of API product management that any major API provider will soon learn formulates like that: there is no sense to ship one specific API; there is always a room for a range of products, and this range is two-dimensional.
@ -22,7 +22,7 @@ However, frequently it makes sense to provide several API services manipulating
* at the same time, the second category is much more sensitive to the quality of both the product and customer support, and fulfilling their requests might be non-trivial.
The most important conclusion here is that the only way to cover the needs of all categories of customers is to develop a range of products with different entry thresholds and requirements for developers' professional level. We might name several API sub-types, ordered from the most technically demanding to less complex ones.
1. The most advanced level is that of physical APIs and the abstractions on top of them. [In our coffee example, the collection of entities describing working with APIs of physical coffee machines, see [Chapter 9](#chapter-9) and [Chapter 17](#chapter-17).]
1. The most advanced level is that of physical APIs and the abstractions on top of them. [In our coffee example, the collection of entities describing working with APIs of physical coffee machines, see the [“Separating Abstraction Levels”](#api-design-separating-abstractions) and the [“Weak Coupling”](#back-compat-weak-coupling) chapters.]
2. The basic level of working with product entities via formal interfaces. [In our study example, that will be HTTP API for making orders.]
3. Working with product entities might be simplified if SDKs are provided for some popular platforms that tailor API concepts according to the paradigms of those platforms (for those developers who are proficient with specific platforms only that will save a lot of effort on dealing with formal protocols and interfaces).
4. The next simplification step is providing services for code generation. In this service, developers choose one of the pre-built integration templates, customize some options, and got a ready-to-use piece of code that might be simply copy-pasted into the application code (and might be additionally customized by adding some level 1-3 code). This approach is sometimes called “point-and-click programming.” [In the case of our coffee API, an example of such a service might have a form or screen editor for a developer to place UI elements and get the working application code.]
@ -37,6 +37,6 @@ The most important advantage of having a range of APIs is not only about adaptin
4. Code generation makes it possible to manipulate the desired form of integrations. For example, if our KPI is a number of searches performed through the API, we might alter the generated code so it will show the search panel in the most convenient position in the app; as partners using code-generation services rarely make any changes in the resulting code, this will help you in reaching the goal.
5. Finally, ready-to-use components and widgets are under your full control, and you might experiment with functionality exposed through them in partners' applications just like if it was your own service. (However, it doesn't automatically mean that you might draw some profits from having this control; for example, if you're allowing inserting pictures by their direct URL, your control over this integration is rather negligible, so it's generally better to provide those kinds of integration that allow having more control over the functionality in partners' apps.)
**NB**. While developing a “vertical” range of APIs, following the principles stated in the [Chapter 14 “On the Iceberg's Waterline”](#chapter-14) is crucial. You might manipulate widget content and behavior if, and only if, developers can't “escape the sandbox,” e.g. have direct access to low-level objects encapsulated within the widget.
**NB**. While developing a “vertical” range of APIs, following the principles stated in the [“On the Waterline of the Iceberg”](#back-compat-iceberg-waterline) chapter is crucial. You might manipulate widget content and behavior if, and only if, developers can't “escape the sandbox,” e.g. have direct access to low-level objects encapsulated within the widget.
In general, you should aim to have each partner service using the API service that maximizes your profit as an API vendor. Where the partner doesn't try to make some unique experience and needs just a typical solution, you would benefit from making them use widgets, which are under your full control and thus ease the API version fragmentation problem and allow for experimenting in order to reach your KPIs. Where the partner possesses some unique expertise in the subject area and develops a unique service on top of your API, you would benefit from allowing full freedom in customizing the integration, so they might cover specific market niches and enjoy the advantage of offering more flexibility compared to using other APIs.

View File

@ -1,4 +1,4 @@
### The API Key Performance Indicators
### [The API Key Performance Indicators][api-product-kpi]
As we described in the previous chapters, there are many API monetization models, both direct and indirect. Importantly, most of them are fully or conditionally free for partners, and the direct to indirect benefits ratio tends to change during the API lifecycle. That naturally leads us to the question of how exactly shall we measure the API success and what goals are to be set for the product team.

View File

@ -1,4 +1,4 @@
### Identifying Users and Preventing Fraud
### [Identifying Users and Preventing Fraud][api-product-antifraud]
In the context of working with an API, we talk about two kinds of users of the system:

View File

@ -1,4 +1,4 @@
### The Technical Means of Preventing ToS Violations
### [The Technical Means of Preventing ToS Violations][api-product-tos-violations]
Implementing the paradigm of a centralized system of preventing partner endpoints-bound fraud, which we described in the previous chapter, in practice faces non-trivial difficulties.
@ -21,7 +21,7 @@ Generally speaking, there are two approaches we might take, the static one and t
As both static and behavioral analyses are heuristic, it's highly desirable to not make decisions based solely on their outcome, but rather ask the suspicious users to additionally prove they're making legitimate requests. If such a mechanism is in place, the quality of an anti-fraud system will be dramatically improved, as it allows for increasing system sensitivity and enabling pro-active defense, e.g. asking users to pass the tests in advance.
In the case of services for end users, the main method of acquiring the second factor is redirecting to a captcha page. In the case of the API it might be problematic, especially if you initially neglected the [“Stipulate restrictions”](#chapter-11-paragraph-19) advice. In many cases, you will have to impose this responsibility on partners (e.g. it will be partners who show captchas and identify users based on the signals received from the API endpoints). This will, of course, significantly impair the convenience of working with the API.
In the case of services for end users, the main method of acquiring the second factor is redirecting to a captcha page. In the case of the API it might be problematic, especially if you initially neglected the “Stipulate Restrictions” rule we've given in the [“Describing Final Interfaces”](#api-design-describing-interfaces) chapter. In many cases, you will have to impose this responsibility on partners (e.g. it will be partners who show captchas and identify users based on the signals received from the API endpoints). This will, of course, significantly impair the convenience of working with the API.
**NB**. Instead of captcha, there might be any other actions introducing additional authentication factors. It might be the phone number confirmation or the second step of the 3D-Secure protocol. The important part is that requesting an additional authentication step must be stipulated in the program interface, as it can't be added later in a backwards-compatible manner.

View File

@ -1,4 +1,4 @@
### Supporting customers
### [Supporting customers][api-product-customer-support]
First of all, an important remark: when we talk about supporting API customers, we mean supporting developers and to some extent business partners. End users seldom interact with APIs directly, with an exception of several non-standard cases.
@ -24,7 +24,7 @@ There are several options for tackling these issues.
2. The inverse scenario: partners must pay for technical support, and it's the API developers who answer the questions. It doesn't actually make a significant difference in terms of the quality of the issues (it's still inexperienced developers who use the API and ask questions; you will just cut off those who can't afford paid support) but at least you won't have a hiring problem as you might allow yourself the luxury of hiring engineers for the first line of support.
3. Partly (or, sometimes, fully) the developer community might help with solving the amateur problems (see the corresponding chapter). Usually, community members are pretty capable of answering those questions, especially if moderators help them.
3. Partly (or, sometimes, fully) the developer community might help with solving the amateur problems (see the [“Communicating with Developers”](#api-product-devrel) chapter). Usually, community members are pretty capable of answering those questions, especially if moderators help them.
Importantly, whatever options you choose, it's still the API developers in the second line of support simply because only they can fully understand the problem and the partners' code. That implies two important consequences.

View File

@ -1,4 +1,4 @@
### The Documentation
### [The Documentation][api-product-documentation]
Regretfully, many API providers pay miserable attention to the documentation quality. Meanwhile, the documentation is the face of the product and the entry point to it. The problem becomes even worse if we acknowledge that it's almost impossible to write the help docs the developers will consider at least satisfactory.

View File

@ -1,4 +1,4 @@
### The Testing Environment
### [The Testing Environment][api-product-testing]
If the operations executed via the API imply consequences for end users or partners (cost money, in particular) you must provide a test version of the API. In this testing API, real-world actions either don't happen at all (for instance, orders are created but nobody serves them) or are simulated by cheaper means (let's say, instead of sending an SMS to a user, an email is sent to the developer's mailbox).

View File

@ -1,4 +1,4 @@
### Managing expectations
### [Managing expectations][api-product-expectations]
Finally, the last aspect we would like to shed the light on is managing partners' expectations regarding the further development of the API. If we talk about the consumer qualities, APIs differ little from other B2B software products: in both cases, you need to form some understanding of SLA conditions, available features, interface responsiveness and other characteristics that are important for clients. Still, APIs have their specificities
@ -8,7 +8,7 @@ Ideally, the API once published should live eternally; but as we all are reasona
The author of this book formulates the rule of issuing new major API versions like this: the period of time after which partners will need to rewrite the code should coincide with the application lifespan in the subject area. Any program will once become obsolete and will be rewritten; and if during this re-developing partners need to also switch to a newer API version, it will be met with some degree of understanding. Of course, in different subject areas, this timespan differs, depending on the evolution rate of the underlying platform.
Apart from updating *major* versions, sooner or later you will face issues with accessing some outdated *minor* versions as well. As we mentioned in the “On the Waterline of the Iceberg” chapter, even fixing bugs might eventually lead to breaking some integrations, and that naturally leads us to the necessity of keeping older *minor* versions of the API until the partner resolves the problem.
Apart from updating *major* versions, sooner or later you will face issues with accessing some outdated *minor* versions as well. As we mentioned in the [“On the Waterline of the Iceberg”](#back-compat-iceberg-waterline) chapter, even fixing bugs might eventually lead to breaking some integrations, and that naturally leads us to the necessity of keeping older *minor* versions of the API until the partner resolves the problem.
In this aspect, integrating with large companies that have a dedicated software engineering department differs dramatically from providing a solution to individual amateur programmers: from one side, the former are much more likely to find undocumented features and unfixed bugs in your code; on the other side, because of the internal bureaucracy, fixing the related issues might easily take months, save not years. The common recommendation there is to maintain old minor API versions for a period of time long enough for the most dilatory partner to switch no the newest version.

View File

@ -1,4 +1,4 @@
### О структуре этой книги
### [О структуре этой книги][intro-structure]
Книга, которую вы держите в руках, состоит из введения и двух больших разделов (ещё один находится в разработке).

View File

@ -1,4 +1,4 @@
### Определение API
### [Определение API][intro-api-definition]
Прежде чем говорить о разработке API, необходимо для начала договориться о том, что же такое API. Энциклопедия скажет нам, что API — это программный интерфейс приложений. Это точное определение, но бессмысленное. Примерно как определение человека по Платону: «двуногое без перьев» — определение точное, но никоим образом не дающее нам представление о том, чем на самом деле человек примечателен. (Да и не очень-то и точное: Диоген Синопский как-то ощипал петуха и заявил, что это человек Платона; пришлось дополнить определение уточнением «с плоскими ногтями».)

View File

@ -1,4 +1,4 @@
### Критерии качества API
### [Критерии качества API][intro-api-quality]
Прежде чем излагать рекомендации, нам следует определиться с тем, что мы считаем «хорошим» API, и какую пользу мы получаем от того, что наш API «хороший».

View File

@ -1,4 +1,4 @@
### Обратная совместимость
### [Обратная совместимость][intro-back-compat]
Обратная совместимость — это некоторая *временна́я* характеристика качества вашего API. Именно необходимость поддержания обратной совместимости отличает разработку API от разработки программного обеспечения вообще.

View File

@ -1,4 +1,4 @@
### О версионировании
### [О версионировании][intro-versioning]
Здесь и далее мы будем придерживаться принципов версионирования [semver](https://semver.org/).
@ -11,4 +11,4 @@
Обычно (но не обязательно) устанавливается, что на последнюю стабильную версию API можно сослаться как по полной версии (`1.2.3`), так и по усечённой (`1.2` или просто `1`). Некоторые системы поддерживают и более сложные схемы указания подключаемой версии (например, `^1.2.3` читается как «подключить последнюю стабильную версию, обратно совместимую с версией `1.2.3`) или дополнительные шорткаты (например `1.2-beta` для подключения бета-версии API семейства `1.2`). В настоящей книге мы будем в основном использовать обозначения вида `v1` (`v2`, `v3` и так далее) для обозначения последнего стабильного релиза API семейства `1.x.x`.
Более подробно о смысле и политиках такого версионирования читайте в главе «Постановка проблемы обратной совместимости».
Более подробно о смысле и политиках такого версионирования читайте в главе [«Постановка проблемы обратной совместимости»](#back-compat-statement).

View File

@ -1,4 +1,4 @@
### Условные обозначения и терминология
### [Условные обозначения и терминология][intro-terms-notation]
В мире разработки программного обеспечения существует множество различных парадигм разработки, адепты которых зачастую настроены весьма воинственно по отношению к адептам других парадигм. Поэтому при написании этой книги мы намеренно избегали слов «метод», «объект», «функция» и так далее, используя нейтральный термин «сущность», под которым понимается некоторая атомарная единица функциональности: класс, метод, объект, монада, прототип (нужное подчеркнуть).

View File

@ -1,4 +1,4 @@
### Пирамида контекстов API
### [Пирамида контекстов API][api-design-context-pyramid]
Подход, который мы используем для проектирования, состоит из четырёх шагов:
* определение области применения;

View File

@ -1,4 +1,4 @@
### Определение области применения
### [Определение области применения][api-design-defining-field]
Ключевой вопрос, который вы должны задать себе четыре раза, выглядит так: какую проблему мы решаем? Задать его следует четыре раза с ударением на каждом из четырёх слов.

View File

@ -1,4 +1,4 @@
### Разделение уровней абстракции
### [Разделение уровней абстракции][api-design-separating-abstractions]
«Разделите свой код на уровни абстракции» — пожалуй, самый общий совет для разработчиков программного обеспечения. Однако будет вовсе не преувеличением сказать, что изоляция уровней абстракции — самая сложная задача, стоящая перед разработчиком API.

View File

@ -1,4 +1,4 @@
### Разграничение областей ответственности
### [Разграничение областей ответственности][api-design-isolating-responsibility]
Исходя из описанного в предыдущей главе, мы понимаем, что иерархия абстракций в нашем гипотетическом проекте должна выглядеть примерно так:
@ -203,7 +203,7 @@ POST /v1/orders
Получив такую ошибку, клиент должен проверить её род (что-то с предложением), проверить конкретную причину ошибки (срок жизни оффера истёк) и отправить повторный запрос цены. При этом если бы `checks_failed` показал другую причину ошибки — например, указанный `offer_id` не принадлежит данному пользователю — действия клиента были бы иными (отправить пользователя повторно авторизоваться, а затем перезапросить цену). Если же обработка такого рода ошибок в коде не предусмотрена — следует показать пользователю сообщение `localized_message` и вернуться к обработке ошибок по умолчанию.
Важно также отметить, что неустранимые ошибки в моменте для клиента бесполезны (не зная причины ошибки клиент не может ничего разумного предложить пользователю), но это не значит, что у них не должно быть расширенной информации: их всё равно будет просматривать разработчик, когда будет исправлять эту проблему в коде. Подробнее об этом в пп. 12-13 следующей главы.
Важно также отметить, что неустранимые ошибки в моменте для клиента бесполезны (не зная причины ошибки клиент не может ничего разумного предложить пользователю), но это не значит, что у них не должно быть расширенной информации: их всё равно будет просматривать разработчик, когда будет исправлять эту проблему в коде (подробнее об этом в следующей главе).
#### Декомпозиция интерфейсов. Правило «7±2»

View File

@ -1,4 +1,4 @@
### Описание конечных интерфейсов
### [Описание конечных интерфейсов][api-design-describing-interfaces]
Определив все сущности, их ответственность и отношения друг с другом, мы переходим непосредственно к разработке API: нам осталось прописать номенклатуру всех объектов, полей, методов и функций в деталях. В этой главе мы дадим сугубо практические советы, как сделать API удобным и понятным.

View File

@ -1,4 +1,4 @@
### Приложение к разделу I. Модельный API
### [Приложение к разделу I. Модельный API][api-design-annex]
Суммируем текущее состояние нашего учебного API.

View File

@ -1,4 +1,4 @@
### Постановка проблемы обратной совместимости
### [Постановка проблемы обратной совместимости][back-compat-statement]
Как обычно, дадим смысловое определение «обратной совместимости», прежде чем начинать изложение.
@ -28,7 +28,7 @@
**NB**: в рамках этой главы мы не разделяем минорные версии и патчи: под словами «минорная версия» имеется в виду любой обратно совместимый релиз API.
Напомним, что [API — это мост](https://twirl.github.io/The-API-Book/docs/API.ru.html#chapter-2), средство соединения разных программируемых контекстов. И как бы нам ни хотелось зафиксировать конструкцию моста, наши возможности ограничены: мост-то мы можем зафиксировать — да вот края ущелья, как и само ущелье, не можем. В этом корень проблемы: мы не можем оставить *свой* код без изменений, поэтому нам придётся рано или поздно потребовать, чтобы клиенты изменили *свой*.
Напомним, что [API — это мост](#intro-api-definition), средство соединения разных программируемых контекстов. И как бы нам ни хотелось зафиксировать конструкцию моста, наши возможности ограничены: мост-то мы можем зафиксировать — да вот края ущелья, как и само ущелье, не можем. В этом корень проблемы: мы не можем оставить *свой* код без изменений, поэтому нам придётся рано или поздно потребовать, чтобы клиенты изменили *свой*.
Помимо наших собственных поползновений в сторону изменения архитектуры API, три других тектонических процесса происходят одновременно: размывание клиентов, предметной области и нижележащей платформы.
@ -60,7 +60,7 @@
* старая функциональность перестаёт поддерживаться;
* меняются интерфейсы.
Как правило, API изначально покрывает только какую-то часть существующей предметной области. В случае нашего [примера с API кофемашин](https://twirl.github.io/The-API-Book/docs/API.ru.html#chapter-7) разумно ожидать, что будут появляться новые модели с новым API, которые нам придётся включать в свою платформу, и гарантировать возможность сохранения того же интерфейса абстракции — весьма непросто. Даже если просто добавлять поддержку новых видов нижележащих устройств, не добавляя ничего во внешний интерфейс — это всё равно изменения в коде, которые могут в итоге привести к несовместимости, пусть и ненамеренно.
Как правило, API изначально покрывает только какую-то часть существующей предметной области. В случае нашего [примера с API кофемашин](#api-design-annex) разумно ожидать, что будут появляться новые модели с новым API, которые нам придётся включать в свою платформу, и гарантировать возможность сохранения того же интерфейса абстракции — весьма непросто. Даже если просто добавлять поддержку новых видов нижележащих устройств, не добавляя ничего во внешний интерфейс — это всё равно изменения в коде, которые могут в итоге привести к несовместимости, пусть и ненамеренно.
Стоит также отметить, что далеко не все поставщики API относятся к поддержанию обратной совместимости, да и вообще к качеству своего ПО, так же серьёзно, как и (надеемся) вы. Стоит быть готовым к тому, что заниматься поддержанием вашего API в рабочем состоянии, то есть написанием и поддержкой фасадов к меняющемуся ландшафту предметной области, придётся именно вам, и зачастую довольно внезапно.
@ -112,4 +112,4 @@
Понятно, что бесконечное сохранение минорных версий в большинстве случаев невозможно (в т.ч. из-за накапливающихся проблем с безопасностью и соответствием законодательству), однако предоставление такого доступа в течение разумного времени для больших API является гигиенической нормой.
**NB**. Часто в защиту политики только одной доступной версии API можно услышать аргумент о том, что кодом SDK или сервера API проблема обратной совместимости не исчерпывается, т.к. он может опираться на какие-то неверсионируемые сервисы (например, на какие-то данные в БД, которые должны разделяться между всеми версиями API) или другие API, придерживающиеся менее строгих политик. Это соображение, на самом деле, является лишь дополнительным аргументом в пользу изоляции таких зависимостей (см. главу «Блокнот душевного покоя»), поскольку это означает только лишь то, что изменения в этих подсистемах могут привести к неработоспособности API сами по себе.
**NB**. Часто в защиту политики только одной доступной версии API можно услышать аргумент о том, что кодом SDK или сервера API проблема обратной совместимости не исчерпывается, т.к. он может опираться на какие-то неверсионируемые сервисы (например, на какие-то данные в БД, которые должны разделяться между всеми версиями API) или другие API, придерживающиеся менее строгих политик. Это соображение, на самом деле, является лишь дополнительным аргументом в пользу изоляции таких зависимостей (см. главу [«Блокнот душевного покоя»](#back-compat-serenity-notepad)), поскольку это означает только лишь то, что изменения в этих подсистемах могут привести к неработоспособности API сами по себе.

View File

@ -1,4 +1,4 @@
### О ватерлинии айсберга
### [О ватерлинии айсберга][back-compat-iceberg-waterline]
Прежде, чем начинать разговор о принципах проектирования расширяемого API, следует обсудить гигиенический минимум. Огромное количество проблем не случилось бы, если бы разработчики API чуть ответственнее подходили к обозначению зоны своей ответственности.
@ -135,4 +135,4 @@ GET /v1/orders/{id}/events/history
Представьте, что в один прекрасный день вы заводите специальный номер телефона, по которому клиент может позвонить в колл-центр и отменить заказ. Вы даже можете сделать это *технически* обратно-совместимым образом, добавив новых необязательных полей в сущность «заказ». Но конечный потребитель может просто *знать* нужный номер телефона, и позвонить по нему, даже если приложение его не показало. При этом код бизнес-аналитика партнёра всё так же может сломаться или начать показывать погоду на Марсе, т.к. он был написан когда-то, ничего не зная о возможности отменить заказ, сделанный в приложении партнёра, каким-то иным образом, не через самого партнёра же.
*Технически* корректным решением в данной ситуации могло бы быть добавление параметра «разрешено отменять через колл-центр» в функцию создания заказа — и, соответственно, запрет операторам колл-центра отменять заказы, если флаг не был указан при их создании. Но это в свою очередь плохое решение *с точки зрения продукта*. «Хорошее» решение здесь только одно — изначально предусмотреть возможность внешних отмен в API; если же вы её не предвидели — остаётся воспользоваться «блокнотом душевного спокойствия», речь о котором пойдёт в последней главе настоящего раздела.
*Технически* корректным решением в данной ситуации могло бы быть добавление параметра «разрешено отменять через колл-центр» в функцию создания заказа — и, соответственно, запрет операторам колл-центра отменять заказы, если флаг не был указан при их создании. Но это в свою очередь плохое решение *с точки зрения продукта*. «Хорошее» решение здесь только одно — изначально предусмотреть возможность внешних отмен в API; если же вы её не предвидели — остаётся воспользоваться «блокнотом душевного спокойствия», речь о котором пойдёт в [последней главе настоящего раздела](#back-compat-serenity-notepad).

View File

@ -1,8 +1,8 @@
### Расширение через абстрагирование
### [Расширение через абстрагирование][back-compat-abstracting-extending]
В предыдущих разделах мы старались приводить теоретические правила и иллюстрировать их на практических примерах. Однако понимание принципов проектирования API, устойчивого к изменениям, как ничто другое требует прежде всего практики. Знание о том, куда стоит «постелить соломку» — оно во многом «сын ошибок трудных». Нельзя предусмотреть всего — но можно выработать необходимый уровень технической интуиции.
Поэтому в этом разделе мы поступим следующим образом: возьмём наш [модельный API](#chapter-12) из предыдущего раздела, и проверим его на устойчивость в каждой возможной точке — проведём некоторый «вариационный анализ» наших интерфейсов. Ещё более конкретно — к каждой сущности мы подойдём с вопросом «что, если?» — что, если нам потребуется предоставить партнёрам возможность написать свою независимую реализацию этого фрагмента логики.
Поэтому в этом разделе мы поступим следующим образом: возьмём наш [модельный API](#api-design-annex) из предыдущего раздела, и проверим его на устойчивость в каждой возможной точке — проведём некоторый «вариационный анализ» наших интерфейсов. Ещё более конкретно — к каждой сущности мы подойдём с вопросом «что, если?» — что, если нам потребуется предоставить партнёрам возможность написать свою независимую реализацию этого фрагмента логики.
**NB**. В рассматриваемых нами примерах мы будем выстраивать интерфейсы так, чтобы связывание разных сущностей происходило динамически в реальном времени; на практике такие интеграции будут делаться на стороне сервера путём написания ad hoc кода и формирования конкретных договорённостей с конкретным клиентом, однако мы для целей обучения специально будем идти более сложным и абстрактным путём. Динамическое связывание в реальном времени применимо скорее к сложным программным конструктам типа API операционных систем или встраиваемых библиотек; приводить обучающие примеры на основе систем подобной сложности было бы, однако, чересчур затруднительно.
@ -83,7 +83,7 @@ PUT /v1/partners/{partnerId}/coffee-machines
Часто вместо добавления нового метода можно добавить просто необязательный параметр к существующему интерфейсу — в нашем случае, можно добавить необязательный параметр `options` к вызову `PUT /cofee-machines`.
**NB**. Когда мы говорим о фиксации договоренностей, действующих в настоящий момент — речь идёт о *внутренних* договорённостях. Мы должны были потребовать от партнёров поддерживать указанный список опций, когда обговаривали формат взаимодействия. Если же мы этого не сделали изначально, а потом решили зафиксировать договорённости в ходе расширения функциональности внешнего API — это очень серьёзная заявка на нарушение обратной совместимости, и так делать ни в коем случае не надо, см. [главу 14](#chapter-14).
**NB**. Когда мы говорим о фиксации договоренностей, действующих в настоящий момент — речь идёт о *внутренних* договорённостях. Мы должны были потребовать от партнёров поддерживать указанный список опций, когда обговаривали формат взаимодействия. Если же мы этого не сделали изначально, а потом решили зафиксировать договорённости в ходе расширения функциональности внешнего API — это очень серьёзная заявка на нарушение обратной совместимости, и так делать ни в коем случае не надо, см. главу [«О ватерлинии айсберга»](#back-compat-iceberg-waterline).
#### Границы применимости

View File

@ -1,4 +1,4 @@
### Сильная связность и сопутствующие проблемы
### [Сильная связность и сопутствующие проблемы][back-compat-strong-coupling]
Для демонстрации проблем сильной связности перейдём теперь к *действительно интересным* вещам. Продолжим наш «вариационный анализ»: что, если партнёры хотят не просто готовить кофе по стандартным рецептам, но и предлагать свои авторские напитки? Вопрос этот с подвохом: в том виде, как мы описали партнёрский API в предыдущей главе, факт существования партнёрской сети никак не отражён в нашем API с точки зрения продукта, предлагаемого пользователю, а потому представляет собой довольно простой кейс. Если же мы пытаемся предоставить не какую-то дополнительную возможность, а модифицировать саму базовую функциональность API, то мы быстро столкнёмся с проблемами совсем другого порядка.
@ -22,7 +22,7 @@ POST /v1/recipes
На первый взгляд, вполне разумный и простой интерфейс, который явно декомпозируется согласно уровням абстракции. Попробуем теперь представить, что произойдёт в будущем — как дальнейшее развитие функциональности повлияет на этот интерфейс.
Первая проблема очевидна тем, кто внимательно читал [главу 11](#chapter-11-paragraph-20): продуктовые данные должны быть локализованы. Это приведёт нас к первому изменению:
Первая проблема очевидна тем, кто внимательно читал главу [«Описание конечных интерфейсов»](#api-design-describing-interfaces): продуктовые данные должны быть локализованы. Это приведёт нас к первому изменению:
```
"product_properties": {
@ -201,7 +201,7 @@ POST /v1/recipe-builder
}
```
Заметим, что передача идентификатора вновь создаваемой сущности клиентом — не лучший паттерн. Но раз уж мы с самого начала решили, что идентификаторы рецептов — не просто случайные наборы символов, а значимые строки, то нам теперь придётся с этим как-то жить. Очевидно, в такой ситуации мы рискуем многочисленными коллизиями между названиями рецептов разных партнёров, поэтому операцию, на самом деле, следует модифицировать: либо для партнёрских рецептов всегда пользоваться парой идентификаторов (партнёра и рецепта), либо ввести составные идентификаторы, как мы ранее рекомендовали в [главе 11](#chapter-11-paragraph-8).
Заметим, что передача идентификатора вновь создаваемой сущности клиентом — не лучший паттерн. Но раз уж мы с самого начала решили, что идентификаторы рецептов — не просто случайные наборы символов, а значимые строки, то нам теперь придётся с этим как-то жить. Очевидно, в такой ситуации мы рискуем многочисленными коллизиями между названиями рецептов разных партнёров, поэтому операцию, на самом деле, следует модифицировать: либо для партнёрских рецептов всегда пользоваться парой идентификаторов (партнёра и рецепта), либо ввести составные идентификаторы, как мы ранее рекомендовали в главе [«Описание конечных интерфейсов»](#api-design-describing-interfaces).
```
POST /v1/recipes/custom

View File

@ -1,6 +1,6 @@
### Слабая связность
### [Слабая связность][back-compat-weak-coupling]
В предыдущей главе мы продемонстрировали, как разрыв сильной связности приводит к декомпозиции сущностей и схлопыванию публичных интерфейсов до минимума. Внимательный читатель может подметить, что этот приём уже был продемонстрирован в нашем учебном API гораздо раньше [в главе 9](#chapter-9) на примере сущностей «программа» и «запуск программы». В самом деле, мы могли бы обойтись без программ и без эндпойнта `program-matcher` и пойти вот таким путём:
В предыдущей главе мы продемонстрировали, как разрыв сильной связности приводит к декомпозиции сущностей и схлопыванию публичных интерфейсов до минимума. Внимательный читатель может подметить, что этот приём уже был продемонстрирован в нашем учебном API гораздо раньше в главе [«Разделение уровней абстракции»](#api-design-separating-abstractions) на примере сущностей «программа» и «запуск программы». В самом деле, мы могли бы обойтись без программ и без эндпойнта `program-matcher` и пойти вот таким путём:
```
GET /v1/recipes/{id}/run-data/{api_type}
@ -20,7 +20,7 @@ GET /v1/recipes/{id}/run-data/{api_type}
Аналогичным образом устроена и сущность `program_run_id`, идентификатор запуска программы. Он также по сути не имеет почти никакого интерфейса и состоит только из идентификатора запуска.
Вернёмся теперь к вопросу, который мы вскользь затронули в [главе 15](#chapter15) — каким образом нам параметризовать приготовление заказа, если оно исполняется через сторонний API. Иными словами, что такое этот самый `program_execution_endpoint`, передавать который мы потребовали при регистрации нового типа API?
Вернёмся теперь к вопросу, который мы вскользь затронули в предыдущей главе — каким образом нам параметризовать приготовление заказа, если оно исполняется через сторонний API. Иными словами, что такое этот самый `program_execution_endpoint`, передавать который мы потребовали при регистрации нового типа API?
```
PUT /v1/api-types/{api_type}
@ -77,7 +77,7 @@ PUT /v1/api-types/{api_type}
* вышестоящий API программ не знает, как устроен уровень исполнения его команд; он формулирует задание так, как понимает на своём уровне: сварить такой-то кофе такого-то объёма, с корицей, выдать такому-то пользователю;
* нижележащий API исполнения программ не заботится о том, какие ещё вокруг бывают API того же уровня; он трактует только ту часть задания, которая имеет для него смысл.
Если мы посмотрим на принципы, описанные в предыдущей главе, то обнаружим, что этот принцип мы уже формулировали: нам необходимо задать *информационный контекст* на каждом из уровней абстракции, и разработать механизм его трансляции. Более того, в общем виде он был сформулирован ещё в [разделе «Потоки данных»](#chapter-9).
Если мы посмотрим на принципы, описанные в предыдущей главе, то обнаружим, что этот принцип мы уже формулировали: нам необходимо задать *информационный контекст* на каждом из уровней абстракции, и разработать механизм его трансляции. Более того, в общем виде он был сформулирован ещё в разделе «Потоки данных» главы [«Разделение уровней абстракции»](#api-design-separating-abstractions).
В нашем конкретном примере нам нужно имплементировать следующие механизмы:
* запуск программы создаёт контекст её исполнения, содержащий все существенные параметры;
@ -228,7 +228,7 @@ ProgramContext.dispatch = (action) => {
#### Проверим себя
Описав указанным выше образом взаимодействие со сторонними API, мы можем (и должны) теперь рассмотреть вопрос, совместимы ли эти интерфейсы с нашими собственными абстракциями, которые мы разработали в [главе 9](#chapter-9); иными словами, можно ли запустить исполнение такого заказа, оперируя не высокоуровневым, а низкоуровневым API.
Описав указанным выше образом взаимодействие со сторонними API, мы можем (и должны) теперь рассмотреть вопрос, совместимы ли эти интерфейсы с нашими собственными абстракциями, которые мы разработали в в главе [«Разделение уровней абстракции»](#api-design-separating-abstractions); иными словами, можно ли запустить исполнение такого заказа, оперируя не высокоуровневым, а низкоуровневым API.
Напомним, что мы предложили вот такие абстрактные интерфейсы для работы с произвольными типами API кофемашин:
@ -273,4 +273,4 @@ POST /v1/programs/{id}/run
Напротив, применяя парадигму конкретизации контекста на каждом новом уровне абстракции мы рано или поздно спустимся вниз по кроличьей норе достаточно глубоко, чтобы конкретизировать было уже нечего: контекст однозначно соотносится с функциональностью, доступной для программного управления. И вот на этом уровне мы должны отказаться от дальнейшей детализации и непосредственно реализовать нужные алгоритмы. Важно отметить, что глубина абстрагирования будет различной для различных нижележащих платформ.
**NB**. В рамках [главы 9](#chapter-9) мы именно этот принцип и проиллюстрировали: в рамках API кофемашин первого типа нет нужды продолжать растить дерево абстракций, можно ограничиться запуском программ; в рамках API второго типа требуется дополнительный промежуточный контекст в виде рантаймов.
**NB**. В рамках главы [«Разделение уровней абстракции»](#api-design-separating-abstractions) мы именно этот принцип и проиллюстрировали: в рамках API кофемашин первого типа нет нужды продолжать растить дерево абстракций, можно ограничиться запуском программ; в рамках API второго типа требуется дополнительный промежуточный контекст в виде рантаймов.

View File

@ -1,4 +1,4 @@
### Интерфейсы как универсальный паттерн
### [Интерфейсы как универсальный паттерн][back-compat-universal-interfaces]
Попробуем кратко суммировать написанное в трёх предыдущих главах.
@ -23,7 +23,7 @@
Таким образом, наш интерфейс (назовём его `ISearchResult`) — это композиция двух других интерфейсов: `IOrderParameters` (сущности, позволяющей сделать заказ) и `ISearchItemViewParameters` (некоторого абстрактного представления результатов поиска в UI). Подобное разделение должно автоматически подводить нас к ряду вопросов.
1. Каким образом мы будем связывать одно с другим? Очевидно, что эти два суб-интерфейса зависимы: например, отформатированная человекочитаемая цена должна совпадать с машиночитаемой. Это естественным образом подводит нас к концепции абстрагирования форматирования, описанной в [главе 16](#chapter-16).
1. Каким образом мы будем связывать одно с другим? Очевидно, что эти два суб-интерфейса зависимы: например, отформатированная человекочитаемая цена должна совпадать с машиночитаемой. Это естественным образом подводит нас к концепции абстрагирования форматирования, описанной в главе [«Сильная связность и сопутствующие проблемы»](#back-compat-strong-coupling).
2. А что такое, в свою очередь, «абстрактное представление результатов поиска в UI»? Есть ли у нас какие-то другие виды поисков, не является ли `ISearchItemViewParameters` сам наследником какого-либо другого интерфейса или композицией других интерфейсов?

View File

@ -1,4 +1,4 @@
### Блокнот душевного покоя
### [Блокнот душевного покоя][back-compat-serenity-notepad]
Помимо вышеперечисленных абстрактных принципов хотелось бы также привести набор вполне конкретных рекомендаций по внесению изменений в существующий API с поддержанием обратной совместимости.
@ -20,7 +20,7 @@
##### Изолируйте зависимости
В случае, если API является гейтвеем, предоставляющим доступ к какому-то нижележащему API или агрегирующим несколько различных API за одним фасадом, велик соблазн предоставить оригинальный интерфейс as is, не внося в него изменений и не усложняя себя жизнь разработкой слабо связанного взаимодействия. Например, разрабатывая интерфейс для запуска программ, описанный в [главе 9](#chapter-9), мы могли бы взять за основу интерфейс кофемашин первого типа и предоставить его в виде API, проксируя запросы и ответы как есть. Делать так ни в коем случае нельзя по нескольким причинам:
В случае, если API является гейтвеем, предоставляющим доступ к какому-то нижележащему API или агрегирующим несколько различных API за одним фасадом, велик соблазн предоставить оригинальный интерфейс as is, не внося в него изменений и не усложняя себя жизнь разработкой слабо связанного взаимодействия. Например, разрабатывая интерфейс для запуска программ, описанный в главе [«Разделение уровней абстракции»](#api-design-separating-abstractions), мы могли бы взять за основу интерфейс кофемашин первого типа и предоставить его в виде API, проксируя запросы и ответы как есть. Делать так ни в коем случае нельзя по нескольким причинам:
* как правило, у вас нет никаких гарантий, что партнёр будет поддерживать свой API в обратно-совместимом или хотя бы концептуально похожем виде;
* любые проблемы партнёра будут автоматически отражаться на ваших клиентах.
@ -36,7 +36,7 @@
Часто можно увидеть антипаттерн: разработчики API используют внутренние непубличные реализации тех или иных методов взамен существующих в их API публичных. Это происходит по двум причинам:
* часто публичный API является лишь дополнением к более специализированному внутреннему ПО компании, и наработки, представленные в публичном API, не портируются обратно в непубличную часть проекта, или же разработчики публичного API попросту не знают о существовании аналогичных непубличных функций;
* в ходе развития API некоторые интерфейсы абстрагируются, но имплементация уже существующих интерфейсов при этом по разным причинам не затрагивается; например, можно представить себе, что при реализации интерфейса `PUT /formatters`, описанного в [главе 16](#chapter16), разработчики сделали отдельную, более общую, версию функции форматирования объёма для пользовательских языков в API, но не переписали существующую функцию форматирования для известных языков поверх неё.
* в ходе развития API некоторые интерфейсы абстрагируются, но имплементация уже существующих интерфейсов при этом по разным причинам не затрагивается; например, можно представить себе, что при реализации интерфейса `PUT /formatters`, описанного в главе [«Сильная связность и сопутствующие проблемы»](#back-compat-strong-coupling), разработчики сделали отдельную, более общую, версию функции форматирования объёма для пользовательских языков в API, но не переписали существующую функцию форматирования для известных языков поверх неё.
Помимо очевидных частных проблем, вытекающих из такого подхода (неконсистентность поведения разных функций в API, не найденные при тестировании ошибки), здесь есть и одна глобальная: легко может оказаться, что вашим API попросту невозможно будет пользоваться, если сделать хоть один «шаг в сторону» — попытка воспользоваться любой нестандартной функциональностью может привести к проблемам производительности, многочисленным ошибкам, нестабильной работе и так далее.

View File

@ -1,4 +1,4 @@
### Продукт API
### [Продукт API][api-product]
Когда мы говорим об API как о продукте, необходимо чётко зафиксировать два важных тезиса.

View File

@ -1,4 +1,4 @@
### Бизнес-модели API
### [Бизнес-модели API][api-product-business-models]
Прежде, чем переходить непосредственно к принципам продуктового управления API, позволим себе заострить внимание читателя на вопросе, каким образом наличие API как продукта приносит пользу компании, а также соответствующие модели монетизации, прямой и косвенной. Вопрос этот, как мы покажем в следующих главах, далеко не праздный, так как напрямую влияет на KPI API и принятие решений. [В квадратных скобках будем приводить примеры подобных моделей применительно к нашему учебному примеру с API кофе-машин.]

View File

@ -1,4 +1,4 @@
### Формирование продуктового видения
### [Формирование продуктового видения][api-product-vision]
Описанная выше фрагментация целевой аудитории API, триада «разработчики — бизнес — конечные пользователи», делает управление продуктом API весьма нетривиальной проблемой. Да, базовый принцип — выяснить потребности аудитории и удовлетворить их — всё тот же; только аудиторий у вашего продукта три, причём их интересы далеко не всегда коррелируют. Из потребности конечного пользователя в качественном и недорогом кофе отнюдь не следует потребность бизнеса в API для работы с кофе-машинами.
@ -17,7 +17,7 @@
Ту же неопределённость следует иметь в виду и при проведении интервью и сборе обратной связи. Программисты будут, в основном, сообщать вам о своих проблемах, возникающих при разработке сервиса — редко о проблемах бизнеса; бизнесу, в свою очередь, мало дела до неудобств разработчиков. И те, и другие обладают при этом каким-то представлением о проблемах пользователя, но зачастую это представление сильно ограничено сегментом рынка, в котором оперирует партнёр.
Если у вас есть доступ к инструментам отслеживания действий конечных пользователей (см. главу «KPI API»), то вы можете попробовать через их логи восстановить типичное поведение пользователей и понять, как они взаимодействуют с приложениями партнёров. Но вам вновь придётся эти данные анализировать для каждого приложения по отдельности и попытаться кластеризовать общие кейсы и частотные сценарии.
Если у вас есть доступ к инструментам отслеживания действий конечных пользователей (см. главу [«Ключевые показатели эффективности API»](#api-product-kpi)), то вы можете попробовать через их логи восстановить типичное поведение пользователей и понять, как они взаимодействуют с приложениями партнёров. Но вам вновь придётся эти данные анализировать для каждого приложения по отдельности и попытаться кластеризовать общие кейсы и частотные сценарии.
#### Проверка продуктовых гипотез

View File

@ -1,4 +1,4 @@
### Взаимодействие с разработчиками
### [Взаимодействие с разработчиками][api-product-devrel]
Как мы описали в предыдущих главах, управление продуктом API требует выстраивания отношений и с бизнес-партнёрами, и с разработчиками. (В идеале и с конечными пользователями, но эта опция для провайдеров API крайне редко доступна.)
@ -52,5 +52,5 @@
* профессиональных программистов, имеющих широкий опыт интеграции различного рода систем;
* начинающих и полупрофессиональных разработчиков, для которых каждая такого рода интеграция является новой и неизведанной территорией.
Этот факт напрямую влияет на всё, что мы обсуждали выше (кроме, может быть, Open Source — разработчики-любители редко обращают на него внимание.) Ваши лекции, семинары и выступления на конференциях должны как-то подходить и тем, и другим. Существует мнение, что угодить одновременно обеим аудиториям невозможно: первые ищут возможности глубокой кастомизации (поскольку работают в крупных ИТ-компаниях со сложившимся подходом к разработке), вторым необходим максимально заниженный порог входа. Мы с этим мнением склонны не согласиться по причинам, которые будут обсуждаться в главе «Линейка сервисов API».
Этот факт напрямую влияет на всё, что мы обсуждали выше (кроме, может быть, Open Source — разработчики-любители редко обращают на него внимание.) Ваши лекции, семинары и выступления на конференциях должны как-то подходить и тем, и другим. Существует мнение, что угодить одновременно обеим аудиториям невозможно: первые ищут возможности глубокой кастомизации (поскольку работают в крупных ИТ-компаниях со сложившимся подходом к разработке), вторым необходим максимально заниженный порог входа. Мы с этим мнением склонны не согласиться по причинам, которые будут обсуждаться в главе [«Линейка сервисов API»](#api-product-range).

View File

@ -1,4 +1,4 @@
### Взаимодействие с бизнес-аудиторией
### [Взаимодействие с бизнес-аудиторией][api-product-business-comms]
Основные принципы работы с партнёрами несколько парадоксально полностью противоположны принципам взаимодействия с разработчиками:
* с одной стороны, партнёры гораздо более лояльно и зачастую даже с энтузиазмом относятся к предлагаемым им возможностям, особенно бесплатным;
@ -6,6 +6,6 @@
Как итог, работа с бизнес-аудиторией в первую очередь сводится к тому, чтобы максимально доходчиво объяснить свойства и преимущества продукта. В остальных же смыслах API «продаётся» как и любое другое программное обеспечение.
Как правило, чем дальше некоторая отрасль находится от информационных технологий, тем с большим энтузиазмом её представители воспринимают рекламу возможностей API, и тем менее вероятно, что этот энтузиазм будет конвертирован в реальную интеграцию. Помочь решению этой проблемы должна интенсивная работа с комьюнити (см. соответствующую главу), благодаря которой появляется множество фрилансеров и аутсорсеров, готовых помочь не-ИТ бизнесам с интеграцией. Вы также можете помочь развитию рынка путём создания обучающих курсов для разработчика и выпуска сертификатов, подтверждающих навыки работы с вашим API (или более широким слоем технологий).
Как правило, чем дальше некоторая отрасль находится от информационных технологий, тем с большим энтузиазмом её представители воспринимают рекламу возможностей API, и тем менее вероятно, что этот энтузиазм будет конвертирован в реальную интеграцию. Помочь решению этой проблемы должна интенсивная работа с комьюнити (см. предыдущую главу), благодаря которой появляется множество фрилансеров и аутсорсеров, готовых помочь не-ИТ бизнесам с интеграцией. Вы также можете помочь развитию рынка путём создания обучающих курсов для разработчика и выпуска сертификатов, подтверждающих навыки работы с вашим API (или более широким слоем технологий).
Аналогичным образом обстоит дело и с исследованиями рынка и получением обратной связи. Далёкие от ИТ бизнесы, как правило, не могут сформулировать свои потребности, поэтому к обработке полученных сведений следует подходить творчески (и критически).

View File

@ -1,4 +1,4 @@
### Линейка сервисов API
### [Линейка сервисов API][api-product-range]
Важное правило управления продуктом API, которое любой достаточно крупный поставщик API довольно быстро для себя откроет, звучит так: нет смысла поставлять всего лишь один какой-то API; есть смысл говорить о наборе продуктов, причём сразу в двух измерениях.
@ -22,7 +22,7 @@
* при этом вторая категория потребителей будет гораздо более требовательна к качеству как продукта, так и поддержки, и при этом удовлетворить их запросы будет крайне нетривиально.
Самый важный вывод здесь такой: максимально полно покрыть нужды всех категорий пользователей можно только разработав множество продуктов с разным порогом входа и требовательностью к профессиональному уровню программиста. Можно выделить следующие подвиды API, по убыванию требуемого уровня разработчиков.
1. Самый сложный уровень — физического API и семейства абстракций над ними. [В нашем кофейном примере — та часть интерфейсов, которая описывает работу с физическим API кофе машин, см. [главу 9](#chapter-9) и [главу 17](#chapter-17).]
1. Самый сложный уровень — физического API и семейства абстракций над ними. [В нашем кофейном примере — та часть интерфейсов, которая описывает работу с физическим API кофе машин, см. главу [«Разделение уровней абстракции»](#api-design-separating-abstractions) и главу [«Слабая связность»](#back-compat-weak-coupling).]
2. Базовый уровень — работы с продуктовыми сущностями через формальные интерфейсы. [В случае нашего учебного API этому уровню соответствует HTTP API заказа.]
3. Упростить работу с продуктовыми сущностями можно, предоставив SDK для различных платформ, скрывающие под собой сложности работы с формальными интерфейсами и адаптирующие концепции API под соответствующие парадигмы (что позволяет разработчикам, знакомым только с конкретной платформой, не тратить время и не разбираться в формальных интерфейсах и протоколах).
4. Ещё более упростить работу можно с помощью сервисов, генерирующих код. В таком интерфейсе разработчик выбирает один из представленных шаблонов интеграции, кастомизирует некоторые параметры, и получает на выходе готовый фрагмент кода, который он может вставить в своё приложение (и, возможно, дописать необходимую функциональность с использованием API 1-3 уровней). Подобного рода подход ещё часто называют «программированием мышкой». [В случае нашего кофейного API примером такого сервиса мог бы служить визуальный редактор форм/экранов, в котором пользователь расставляет UI элементы, и в конечном итоге получает полный код приложения.]
@ -37,6 +37,6 @@
4. Кодогенерация позволяет вам манипулировать желательным видом приложений. Например, если для вас важным показателем является количество поисков через сторонние приложения, вы можете добавить в генерированный код показ панели поиска на видном месте; пользователи, прибегающие к помощи генератора кода, как правило, не меняют сгенерированный результат.
5. Наконец, готовые компоненты и виджеты находятся полностью под вашим контролем, и вы можете экспериментировать с доступной через них функциональностью так же свободно, как если бы это было ваше собственное приложение. (Здесь следует, правда, отметить, что не всегда от этого контроля есть толк: например, если вы позволяете вставлять изображение по прямому URL, ваш контроль над этой интеграцией практически отсутствует; при прочих равных следует выбирать тот вид интеграции, который позволяет получить больший контроль над соответствующей функциональностью в приложении партнёра.)
**NB**. При разработке «вертикального» семейства API замечания, описанные в главе [«О ватерлинии айсберга»](#chapter-14) особенно важны. Вы можете свободно манипулировать контентом и поведением виджета, если и только если у разработчика нет способа «сбежать из песочницы», т.е. напрямую получить низкоуровневый доступ к объектам внутри виджета.
**NB**. При разработке «вертикального» семейства API замечания, описанные в главе [«О ватерлинии айсберга»](#back-compat-iceberg-waterline) особенно важны. Вы можете свободно манипулировать контентом и поведением виджета, если и только если у разработчика нет способа «сбежать из песочницы», т.е. напрямую получить низкоуровневый доступ к объектам внутри виджета.
Как правило, вы должны стремиться к тому, чтобы каждый партнёрский сервис использовал тот вид API, который вам как разработчику наиболее выгоден. Там, где партнёр не стремится создать какую-то уникальную функциональность и размещает типовое решение, вам выгодно иметь виджет, который полностью находится под вашим контролем и, с одной стороны, снимает с вас головную боль относительно обновления версий API, и, с другой стороны, даёт вам свободу экспериментировать с внешним видом и поведением интеграций с целью оптимизации ваших KPI. Там, где партнёр обладает экспертизой и желанием разработать какой-то уникальный сервис поверх вашего API, вам выгодно предоставить ему максимальную свободу действий, чтобы, во-первых, покрыть тем самым уникальные продуктовые ниши, и, во-вторых, обладать конкурентным преимуществом в виде возможности глубокой кастомизации относительно других API на рынке.

View File

@ -1,4 +1,4 @@
### Ключевые показатели эффективности API
### [Ключевые показатели эффективности API][api-product-kpi]
Как мы описали выше, существует большое количество различных моделей монетизации API, прямой и косвенной. Важной их особенностью является то, что, во-первых, большинство из них является частично или полностью бесплатными для партнёра, а, во-вторых, соотношение прямой и косвенной выгоды часто меняется в течение жизненного цикла API. Возникает вопрос, каким же образом следует измерять успех API и какие цели ставить продуктовой команде.

View File

@ -1,4 +1,4 @@
### Идентификация пользователей и борьба с фродом
### [Идентификация пользователей и борьба с фродом][api-product-antifraud]
В контексте работы с API мы говорим о двух видах пользователей системы:

View File

@ -1,4 +1,4 @@
### Технические способы борьбы с несанкционированным доступом к API
### [Технические способы борьбы с несанкционированным доступом к API][api-product-tos-violations]
Реализация парадигмы, описанной в предыдущей главе — централизованной борьбы с фродом, осуществляемым через клиентские API партнёра — на практике сталкивается с достаточно нетривиальными проблемами.

View File

@ -1,4 +1,4 @@
### Поддержка пользователей API
### [Поддержка пользователей API][api-product-customer-support]
Прежде всего сделаем важную оговорку: когда мы говорим о поддержке пользователей API, мы имеем в виду поддержку разработчиков и отчасти — бизнес-партнёров. Конечные пользователи, как правило, напрямую с API не взаимодействуют, за исключением некоторых нестандартных сценариев.
@ -24,7 +24,7 @@
2. Обратный сценарий — когда техподдержка предоставляется только на платной основе, и на вопросы отвечают непосредственно разработчики; пусть на качество и релевантность запросов такая модель не оказывает большого влияния (вашим API продолжают пользоваться, в основном, новички; вы лишь отсекаете тех из них, у кого нет денег на платную поддержку), но, по крайней мере, вы не будете испытывать проблем с наймом, поскольку сможете позволить себе роскошь поставить технического специалиста на первую линию поддержки.
3. Частично или полностью проблему с поддержкой новичков может снять развитое комьюнити (см. соответствующую главу). Как правило, члены комьюнити в состоянии ответить на вопросы новичков, особенно если им активно помогают модераторы.
3. Частично или полностью проблему с поддержкой новичков может снять развитое комьюнити (см. главу [«Взаимодействие с разработчиками»]()). Как правило, члены комьюнити в состоянии ответить на вопросы новичков, особенно если им активно помогают модераторы.
Важный момент заключается в том, что, какой вариант оказания техподдержки вы ни выберете, финально на вопросы пользователей придётся отвечать разработчикам API просто в силу того факта, что полноценно разобраться в коде партнёра может только программист. Из этого следует два важных вывода.

View File

@ -1,4 +1,4 @@
### Документация
### [Документация][api-product-documentation]
К сожалению, многие разработчики API уделяют справочной документации прискорбно мало внимания; между тем документация является ни много ни мало лицом продукта и точкой входа в него. Проблема усугубляется тем, что написать хотя бы удовлетворительную с точки зрения разработчиков документацию невероятно сложно.

View File

@ -1,4 +1,4 @@
### Тестовая среда
### [Тестовая среда][api-product-testing]
Если через ваш API исполняются операции, которые имеют последствия для пользователей или партнёров (в частности, стоят денег), то вам необходимо иметь тестовую версию этого API. В тестовом API реальные действия либо не происходят совсем (например, заказ создаётся, но никем не исполняется), либо симулируется дешёвыми способами (например, вместо отправки SMS на номер пользователя уходит электронное письмо на почту разработчика).

View File

@ -1,4 +1,4 @@
### Управление ожиданиями
### [Управление ожиданиями][api-product-expectations]
Наконец, последний аспект, который хотелось бы осветить в рамках данного раздела — это управление ожиданиями партнёров в отношении развития вашего API. С точки зрения коммуникации потребительских качеств API мало отличается от любого другого B2B программного обеспечения: и там, и там вам нужно как-то сформировать у разработчиков и бизнеса понимание о допустимом SLA, объёме функциональности, отзывчивости интерфейсов и прочих пользовательских характеристиках. Однако у API как продукта есть и специфические особенности.
@ -8,7 +8,7 @@
Автор этой книги формулирует для себя золотое правило выпуска новых версий API так: период времени, после которого партнеру потребуется переписать свой код, должен совпадать с жизненным циклом приложений в вашей предметной области. Любая программа рано или поздно устареет и будет переписана; если в рамках этого переписывания будет осуществлён и переход на свежую версию API, партнёр, скорее всего, отнесётся к этому с пониманием. Разумеется, в разных областях этот интервал различен, и зависит от скорости эволюции самой нижележащей платформы.
Помимо переключения *мажорных* версий API, рано или поздно встанет вопрос и о доступе к *минорным* версиям. Как мы упоминали в главе «О ватерлинии айсберга», даже исправление ошибок в коде может привести к неработоспособности какой-то интеграции. Соответственно, может потребоваться и сохранение возможности зафиксировать *минорную* версию API до момента обновления затронутого кода партнёром.
Помимо переключения *мажорных* версий API, рано или поздно встанет вопрос и о доступе к *минорным* версиям. Как мы упоминали в главе [«О ватерлинии айсберга»](#back-compat-iceberg-waterline), даже исправление ошибок в коде может привести к неработоспособности какой-то интеграции. Соответственно, может потребоваться и сохранение возможности зафиксировать *минорную* версию API до момента обновления затронутого кода партнёром.
В этом аспекте интеграция с крупными компаниями, имеющими собственный отдел разработки, существенно отличается от взаимодействия с одиночными разработчиками-любителями: первые, с одной стороны, с гораздо большей вероятностью найдут в вашем API недокументированные возможности и неисправленные ошибки; с другой стороны, в силу большей бюрократичности внутренних процессов, исправление проблем может затянуться на месяцы, а то и годы. Общая рекомендация здесь — поддерживать возможность подключения старых минорных версий API достаточно долго для того, чтобы самый забюрократизированный партнёр успел переключиться на новую версию.