🔖 Почему ваша библиотека никто не использует, хотя она работает?
Вы написали библиотеку, которая решает проблему, но она сложная в использовании и никто не хочет её применять. Проблема не в функциональности, а в проектировании. Хорошая библиотека предоставляет точки расширения, не навязывает свой контекст и остаётся простой. Плохая — заставляет пользователя прыгать через обручи.
// Плохо - функция навязывает свой контекст, нет гибкости
void sort(int& container) {
// Компаратор зафиксирован, нельзя поменять
// Способ свопинга элементов фиксирован
}
// Хорошо - точки расширения встроены в интерфейс
template <class R, class C = DefaultCompare, class S = DefaultSwap>
void sort(R&& range, C compare = C(), S swap = S()) {
// Пользователь может передать свой компаратор
// Пользователь может передать свой своп
// По умолчанию работает стандартно
}
📎 Основные проблемы плохих библиотек:
🔸 Отсутствие точек расширения — невозможно кастомизировать
🔸 Сложная архитектура — нужно понимать всю библиотеку, чтобы использовать часть
🔸 Конкретные типы вместо обобщений — работает только для одного случая
🔸 Навязанный контекст — вынуждает пользователя следовать вашему стилю
Хорошая библиотека предполагает точку зрения пользователя, а не разработчика. Она не предполагает, что пользователь сделает. Вместо этого она предоставляет инструменты и ступеньки, позволяя каждому использовать её по-своему.
Три столпа проектирования:
// 1. МОДУЛЬНОСТЬ - компоненты независимы
// Контейнеры отделены от алгоритмов, но работают вместе
std::vector<int> v = {3, 1, 2};
std::sort(v.begin(), v.end()); // Работает с любым контейнером
// 2. МНОГОРАЗОВОСТЬ - работает для многих типов
template <class T>
class Maybe {
T value; // Работает с любым типом T
};
// 3. РАСШИРЯЕМОСТЬ - встроены точки для кастомизации
std::sort(v.begin(), v.end(), [](int a, int b) {
return a > b; // Пользовательский компаратор
});
✅ Проектируйте библиотеку так, чтобы:
- Компоненты были независимы и использовались отдельно
- Работала с разными типами, не только одним конкретным
- Предоставляла точки расширения (callback, custom comparator, plugin)
- Была легка в понимании — минимум контекста для начала использования
❌ Не делайте:
- Сложные архитектуры, когда вся библиотека зависит друг от друга
- Конкретные типы (int, string) вместо шаблонов и обобщений
- Фиксированное поведение без возможности кастомизации
- Навязывание дизайн-решений пользователям
Пример хорошей библиотеки — C++ STL: контейнеры работают с алгоритмами, всё обобщено через шаблоны, есть кастомные компараторы и аллокаторы. Пример плохой — фреймворк, где всё зависит от всего.
Полезная библиотека думает о том, кто её будет использовать, и делает это легко.
📎 Статья
🎙 Новости
📝 База вопросов
