# Бібліотека

## Що це таке

Бібліотека — це набір готових підпрограм, які програма позичає, замість того щоб писати їх сама:
хтось один раз розв'язав задачу, скажімо розбір дат, стиснення файлів чи побудову QR-коду, і виклав
розв'язок разом із набором іменованих точок входу, якими може скористатися будь-яка програма. Повна
назва — програмна бібліотека, англійською library. На Linux бібліотеки мовою C часто мають у назвах
префікс lib, у Windows спільну бібліотеку називають DLL, а в Rust кажуть «крейт» (crate), і книга
The Rust Programming Language зазначає, що це слово вживають як синонім бібліотеки. Більшість мов
постачається ще й зі стандартною бібліотекою — модулями, доступними в кожній інсталяції без жодних
додаткових кроків.

Бібліотека — різновид коду для повторного використання, і найпростіше пояснити її через сусідів.
Застосунок працює сам по собі й має користувача; бібліотека не має ні того, ні іншого і працює лише
всередині програми, яка її викликає. Ближче до неї стоїть фреймворк. Із бібліотекою керує код самої
програми: він звертається до бібліотеки, коли щось потрібно. Фреймворк керує сам і викликає код
програми в місцях, які для цього відвів. Нарешті, пакет — це коробка, у якій бібліотеку постачають,
з назвою, версією й переліком того, що їй потрібно, а бібліотека — це код усередині коробки.

Придатною до використання бібліотеку робить її інтерфейс: функції, типи й константи, які вона обіцяє
зберігати. На цій обіцянці тримається вся схема Semantic Versioning. Проєкт, що її дотримується,
мусить оголосити публічний API, а його мажорна версія зростає щоразу, коли цей API змінюється
несумісно з попереднім.

Program Library HOWTO поділяє бібліотеки на Linux за тим, коли вони потрапляють у програму. Статичну
бібліотеку копіюють у виконуваний файл під час збирання. Спільну завантажують під час запуску
програми, і нею користуються всі програми, яким вона потрібна, тож її можна оновити, не перезбираючи
їх. Динамічно завантажувану бібліотеку відкривають уже під час роботи програми — так зазвичай
працюють системи плагінів.

## Чому це важливо

Кожна бібліотека в проєкті — це рішення з трьома можливими відповідями: взяти наявну, написати код
самим або скопіювати невеликий, чітко окреслений фрагмент у репозиторій і відтоді володіти ним.
Останній варіант називають вендорингом (vendoring).

Взяти наявну бібліотеку зазвичай правильно. Її автори вже натрапили на крайові випадки, а інші
користувачі вже повідомили про помилки. Ціна приходить пізніше, і її легко не помітити: разом із
бібліотекою приходять її власні залежності, її бюлетені безпеки стають вашими, її графік випусків
задає темп ваших оновлень, а її ліцензія переходить у ваш продукт. Бібліотека, яку автор покинув,
лишається у збиранні, доки хтось її не замінить.

Власний код дає контроль і коштує всього, що бібліотека заощадила б: крайових випадків, тестів і
супроводу, поки код живе. Це правильний вибір, коли задача вузька й центральна, коли наявні
бібліотеки значно більші за потребу або коли проєкт має причину тримати кількість залежностей
низькою.

Важить і спосіб компонування. Програма, зібрана зі статичною бібліотекою, несе в собі фіксовану
копію, тож виправлення безпеки в бібліотеці дійде до користувачів лише тоді, коли програму
перезберуть і випустять знову. Спільну бібліотеку можна виправити один раз для всієї системи, але
тоді програма покладається на ту версію, яку надає система. Ліцензіям ця різниця байдужа: FAQ щодо
ліцензій GNU прямо каже, що статичне чи динамічне компонування твору під GPL з іншими модулями
створює комбінований твір, і умови GPL поширюються на всю комбінацію.

Для замовника програмного забезпечення практичні питання такі: від яких бібліотек залежить
результат, під якими ліцензіями і кому належать бібліотеки, які постачальник приносить із собою.

## Як це виглядає на практиці

Генератор документів мав ставити на кожен документ QR-код із посиланням на його онлайн-версію. Із
цим упоралася б будь-яка з наявних QR-бібліотек, але проєкт свідомо обмежився двома залежностями під
час виконання, шаблонізатором і рендерером PDF, щоб генератор і через багато років можна було
встановити без пригод. Тож проєкт отримав власний
[QR-енкодер на 522 рядки](/uk/portfolio/vendored-a-qr-encoder-in-522-lines-148/): кодування в
байтовому режимі, корекцію помилок кодом Ріда-Соломона над GF(256), пошукові, синхронізаційні й
вирівнювальні візерунки, відомості про формат і версію та всі вісім масок, оцінених за чотирма
штрафними правилами. Окремо написаний декодер під час кожного запуску зчитує кожен згенерований код
і перевіряє, що в результаті виходять ті самі вхідні дані. Сторінка обережна у твердженнях: енкодер
підтримує лише ті режими й версії, які потрібні документам, а виправдання йому — бюджет залежностей,
а не віра в те, що він кращий за зрілу бібліотеку.

Нативний клієнт для macOS викликає бібліотеку-ядро через її інтерфейс мовою C, і спершу цей
інтерфейс описував написаний вручну заголовний файл. Виклики трьох функцій, яких у ядрі вже не було,
компілювалися, компонувалися й падали під час виконання, бо компілятор і компонувальник бачили лише
рукописну заміну, а не справжні оголошення ядра. Виправленням став
[парсер, що перевіряє кожне місце виклику](/uk/portfolio/wrote-a-parser-that-verifies-every-ffi-call-site-157/)
за справжнім заголовним файлом на 7 308 рядків і 268 оголошень: збирання зупиняється на будь-якому
виклику чи константі переліку, яких цей файл не оголошує. Парсер перевіряє оголошення, тож функція,
яка зберегла сигнатуру, але змінила значення, проходить перевірку.

[Умови співпраці](/uk/terms/) прямо визначають, кому що належить. Код, написаний для замовника,
після повної оплати стає його власністю. Винятком є бібліотеки й інструменти загального призначення,
які компанія написала раніше або для себе: вони лишаються за компанією, а замовник отримує
безстрокову ліцензію, яку не можна відкликати, щоб користуватися ними в межах переданої роботи.
Сторонній відкритий код і далі підпорядковується ліцензіям, які обрали його автори, і замовникові
повідомляють, які саме з цих компонентів потрапили в результат.

## Де виникають проблеми

### Звичайне оновлення ламає збирання

Залежність переходить із 2.3 на 2.4, і код, який учора компілювався, падає або поводиться інакше.
Або бібліотека змінила публічний інтерфейс, не піднявши мажорної версії, або проєкт спирався на те,
чого бібліотека ніколи не обіцяла, як-от внутрішню функцію чи незадокументовану поведінку. Фіксуйте
точні версії в lock-файлі, оновлюйтеся свідомо, з відкритим журналом змін, і викликайте лише те, що
бібліотека документує як публічне.

### Програма довіряє опису бібліотеки

Збирання проходить без жодної помилки, а програма падає, щойно хтось уперше вмикає певну функцію.
Код компілювали проти заголовних файлів, заглушок типів чи прив'язок, написаних вручну, і вони
розійшлися з бібліотекою, яку насправді компонують. Генеруйте прив'язки з опублікованого інтерфейсу
самої бібліотеки або перевіряйте кожен виклик за ним під час збирання, щоб розбіжність зупиняла
збирання, а не проявлялася перед користувачем.

### Одна дрібна функція тягне за собою ціле дерево

Потрібна була одна функція, а бібліотека, яка її надає, принесла десятки власних залежностей, і
кожна з них — це ще бюлетені безпеки, ліцензії та оновлення. Перш ніж додавати бібліотеку,
подивіться, що вона тягне за собою, а не лише на її власний розмір. Коли потреба вузька й добре
описана, невеликий фрагмент власного коду з окремими тестами може виявитися дешевшим у володінні.

### Ліцензія приходить разом із кодом

Наприкінці проєкту хтось помічає, що бібліотека всередині закритого продукту має ліцензію, умови
якої поширюються на весь комбінований твір. Ліцензій ніхто не перевіряв, коли бібліотеку додавали, а
динамічне компонування нічого не змінило. Перевіряйте ліцензію кожної бібліотеки в момент додавання,
зберігайте перелік разом із випуском і просіть постачальників надати свій.

## Що почитати далі

- [Program Library HOWTO: Introduction](https://tldp.org/HOWTO/Program-Library-HOWTO/introduction.html)
  — що таке програмна бібліотека в Linux і чим різняться статичні, спільні та динамічно
  завантажувані бібліотеки.
- [The Rust Programming Language: Packages and Crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html)
  — бібліотечні й бінарні крейти та те, як їх містить пакет.
- [Semantic Versioning 2.0.0](https://semver.org/) — правила нумерації версій, що перетворюють
  публічний API бібліотеки на обіцянку.
- [The Python Standard Library](https://docs.python.org/3/library/index.html) — стандартна
  бібліотека в повному обсязі: усе, що входить до кожної інсталяції Python.
- [Frequently Asked Questions about the GNU Licenses](https://www.gnu.org/licenses/gpl-faq.html) —
  що означає GPL для програм, які компонують бібліотеку під цією ліцензією, статично чи динамічно.

<https://engineer.company/uk/glossary/library/>
