Виступ Джейсона Тёрнера на CppCon 2022 під назвою "Back to Basics: C++ API Design" містить кілька ключових рекомендацій для створення кращих API, на які варто звернути увагу при розробці програмного забезпечення.
Основною ідеєю є те, щоб API було складно використовувати неправильно. Тёрнер наголошує, що це має бути основною метою під час проектування API.
Одним з перших важливих аспектів є вибір правильних назв. Назви повинні бути чіткими і описовими, оскільки це значно полегшує роботу з API. Використання зрозумілих і точних імен дозволяє уникнути багатьох помилок і непорозумінь.
Наступний важливий момент — це використання атрибута [[nodiscard]]
. Цей атрибут повідомляє компілятору, що функція не повинна повертати значення, яке буде проігнороване. Зазначається, що його слід активно застосовувати для функцій, які не змінюють стан об'єкта, як-от гетери. Крім того, можна додавати пояснення, чому повертається значення важливе.
Іншим важливим інструментом є специфікатор noexcept
. Це дозволяє явно повідомити компілятору і користувачу, що функція не повинна кидати виключень. Якщо ж функція з noexcept
все ж таки викидає виключення, буде викликано std::terminate
. Це допомагає зробити код більш передбачуваним і безпечним.
Тёрнер також рекомендує уникати сирих вказівників, які можуть викликати плутанину щодо володіння і життєвого циклу об'єктів. Замість цього він радить використовувати розумні вказівники, як-от std::unique_ptr
чи std::shared_ptr
, щоб чітко вказати на володіння об'єктами. Повертати сирі вказівники не слід, оскільки це створює невизначеність щодо того, хто відповідає за видалення об'єкта.
Ще одна важлива рекомендація — це впровадження послідовної обробки помилок. Тёрнер радить використовувати виключення як основний метод обробки помилок, оскільки їх складно ігнорувати. Важливо уникати використання позаопераційних механізмів для обробки помилок (наприклад, через функцію отримання останньої помилки), адже це може призвести до проблем у багатопоточних програмах. Крім того, не рекомендується використовувати std::optional
для позначення помилок, оскільки це не надає достатньої інформації про причину помилки.
Тёрнер також підкреслює важливість використання сильних типів замість неявних перетворень. Неявні перетворення можуть призвести до багатьох прихованих помилок, тому потрібно робити конструктори і оператори перетворення явними. Також він радить обмежувати кількість можливих перетворень, видаляючи проблемні перевантаження.
Ще один важливий момент — це обмеження поверхні API. Простий API легше зрозуміти і з ним менше шансів зробити помилки. Тому потрібно намагатися створювати API, який є якомога простішим і чистішим.
Фаззинг — це потужний метод тестування, який дозволяє знаходити несподівані способи неправильного використання API, використовуючи псевдовипадкові введення. Цей метод допомагає виявити потенційні проблеми в API і зробити його більш надійним.
Щодо фабричних функцій, Тёрнер радить використовувати шаблони, якщо типи віджетів відомі на етапі компіляції, щоб забезпечити найбільшу безпеку на етапі компіляції. У прикладі з fopen
він вказує на історичні проблеми з його дизайном, такі як можливість легко змінювати параметри і використання рядкових параметрів для режиму відкриття файлу. Він радить використовувати більш сильні типи, такі як об'єкти шляху або перерахування, щоб зробити код більш типобезпечним.
На завершення Тёрнер підкреслює важливість того, щоб API було зрозумілим і типобезпечним, що допоможе уникнути типових помилок і направить користувачів до правильного використання.
Ви можете переглянути відео з виступом за посиланням.
Перекладено з: C++ API Design