Как выбрать open source библиотеку
Когда я получаю новую задачу, то первым делом стараюсь найти готовое решение в интернете. Потому что нет желания изобретать велосипед и есть вероятность, что в готовом решении уже найдены все подводные камни. В этой статье я постараюсь описать, как выбрать “хорошую” библиотеку среди подобных и как внести свой вклад в развитие Open Source.
Поиск… 🔍
Чаще всего мне приходится искать JS библиотеки, поэтому, не задумываясь, я начинаю свой запрос с “node ...” или “npm ...”. И уже автоматически пролистываю до сайта https://www.npmjs.com или https://github.com. Уверен, те, кто уже работал с node js, знают о менеджере управления пакетами NPM, ведь это главный ресурс открытых решений для JS. В случае PHP это был бы packagist, в случае .NET - nuget, Python - pip, Ruby - gem и т.д. Именно на сайте менеджера пакетов можно быстро прочитать о том, что это за библиотека, как ею пользоваться и как ее установить.
Но менеджер пакетов - это скорее справочник библиотек, исходный код чаще всего хранится в каком-нибудь открытом репозитории кода. На сегодняшний день самым популярным хостингом для хранения открытого исходного кода является github.com, независимо от языка программирования. И именно туда я перехожу, если хочу узнать про библиотеку детальнее: посмотреть исходный код, пролистать известные issues, изучить документацию подробнее.
Иногда библиотека имеет свой собственный сайт с интерактивной документацией, например async или lodash, но это не всегда так, и в таких случаях github - единственный источник.
Как выбрать? 🧐
При поиске часто бывает, что есть несколько альтернатив одного и того же решения, и тут нужно отобрать наиболее надежную.
Лично для меня идеальным кандидатом является та библиотека, у которой много звезд, минимум зависимостей, множество закрытых issues и отсутствие открытых. Но так не бывает… Поэтому приходится смотреть на каждый показатель в отдельности.
Количество звезд отражает популярность библиотеки. Предположение состоит в том, что чем библиотека популярнее, тем больше людей с ней работало и использовало различными способами. Соответственно, библиотека с большим количеством звезд вызывает больше доверия. Понятное дело, что разница в 50 звезд существенной роли не играет, но когда в одной библиотеке 5 звезд, а в другой 300, то прежде всего я обращаю внимание на вторую.
Открытые issues - это не обязательно плохо, а скорее даже наоборот, так как это означает, что часть проблем уже найдена, и их осталось только решить. Но если проблем много, и библиотеку никто не обновляет уже долгий период времени, то это уже плохо.
К примеру могу привести библиотеку flat, которая трансформирует вложенный объект в плоский. На момент написания статьи она имела 954 звезды, 23 открытых issues и одну зависимость, что является достаточно хорошим показателем. Но последний коммит был год назад, и сейчас открыто 16 пулл реквестов. Когда я ее выбирал для решения своей задачи, меня это не смутило, но спустя некоторое время обнаружился баг - когда объект трансформируется обратно во вложенный, порядок ключей теряется. Для нашего проекта это критично, так как мы работаем с моделированием данных. Учитывая, что изменения в библиотеку не вносились уже больше года, то крайне маленькая вероятность, что баг будет исправлен в ближайшее время. Поэтому было принято решение форкнуть репозиторий и пофиксить проблему. Судя по количеству форков, еще 128 разработчиков пошли на такой же шаг. Поэтому дата последнего коммита также может сыграть свою роль при выборе готового решения.
Зависимости библиотеки - это не критичный показатель, но иногда стоит и на них обращать свое внимание. Некоторые зависимости могут быть неоправданны для данного решения, в результате чего ваш bundle вырастет в размерах на пару мегабайт. Или, к примеру, некоторые библиотеки необходимо билдить из C++ модулей, и это может накладывать особые ограничения. Это особенно проявляется в кросс-платформенных приложениях под разные операционные системы (например, написанных на electron).
Итого, когда я сравниваю идентичные библиотеки, то на мой выбор влияют такие показатели как количество звезд, дата последнего коммита, количество открытых issues и зависимости. А также, с недавних пор, github добавил новую метрику с количеством проектов, которые используют текущую библиотеку.
Как с этим работать? 😕
После того, как я выбрал библиотеку, я разбираюсь, как она работает. Чаще всего в корне репозитория есть файл readme, который и содержит краткий “how to use”, а иногда и инструкцию целиком. Если инструкция достаточно большая, то файлы документации складывают в директорию docs, или иногда ее можно найти на вкладке wiki на github’е.
Наилучший способ научиться пользоваться библиотекой - это посмотреть, как она работает. Если повезет, то она будет содержать директории examples или samples, но часто их не бывает. Поэтому на помощь приходят тесты, которые обычно находятся в папке tests. Таким образом, тесты выполняют не только функцию поддержания качества кода, но и описания использования библиотеки. Например, посмотрим на функцию ary библиотеки lodash, она принимает функцию и количество параметров, которое ей будет передано:
Сложно представить себе сегодня популярную библиотеку, не покрытую тестами. А если их нет, то стоит подумать, а нужно ли использовать ее?
Если нужно или хочется узнать детали реализации, то следует обратиться к исходному коду, который часто находится в директории src или lib. К счастью, хорошо написанный код самодокументированный, и иногда авторы пишут комментарии к методам, что упрощает работу. В исходный код также полезно смотреть, когда необходимо узнать, какие параметры можно передать в ту или иную функцию, и что она возвращает.
Но иногда приходится смотреть, что происходит внутри, из-за того, что именно библиотека является причиной багов в приложении. Например, у нас используется библиотека jayschema, которая валидирует данные по JSON Schema. Библиотека больше не поддерживается, но в приложении она у нас используется повсеместно, в том числе и для валидации моделей, сохраненных в файл. Работает она хорошо, как мы думали, но 31 марта 2019 года наш заказчик заметил серьезный баг. Модель, сохраненную в этот день, невозможно открыть, потому что мы валидируем дату редактирования модели, но валидатор внутри библиотеки считает, что 31.03.2019 не существует. Изучив детально реализацию валидатора даты, мы выяснили, что для определения количества дней автор берет следующий месяц и вычитает 24 часа в миллисекундах (ссылка). Загвоздка в том, что 24 часа назад после первого апреля время было еще зимнее, и соответственно результат был 30.03.2019 23:00:00, а не то, которое ожидается.
Этот случай показывает, что баги могут быть не только в твоем коде, но и в библиотечном, поэтому, добавляя к себе в проект решение, вы берете на себя ответственность за его работоспособность. Но тем не менее такой случай очень сложно протестировать и учесть, ведь это случается только два раза в году. Если посмотреть pull request’ы , то видно, что эту проблему нашли и решили еще 4 года назад (ссылка). Просто библиотека больше не поддерживается, и изменения так и не попали в релиз.
Кстати, к нашему счастью, время переводят с субботы на воскресенье, поэтому в этот день мало кто пользовался приложением.
Вклад в Open-Source 🎩
Но что делать, когда нашел баг в библиотеке? На самом деле, не стоит сразу же форкать ее себе и посылать pull request.
Возможно, кто-то уже столкнулся с такой трудностью, и тогда нужно проверить это в открытых и закрытых issues. Возможно, используется старая версия, и в новой этот баг уже пофиксили. Тогда можно посмотреть изменения между версиями на странице “releases”.
Или часто в репозитории можно найти файл changelog’а, который содержит изменения от версии к версии и может помочь в поиске проблемы. Этот файл называется по-разному: CHANGELOG, CHANGES, HISTORY, но его суть одна и та же.
Когда уже точно убедился, что проблема существует, то можно посмотреть в файл contributing, если он присутствует. Этот файл содержит в себе правила внесения изменений в библиотеку, как оформлять пулл реквест, правила написания кода, составления коммитов и так далее. Например, файл contributing.md из репозитория js mongodb драйвера содержит краткое описание, как стать их контрибьютором.
И уже после этого следует форкать себе репозиторий и вносить изменения. После изменений обязательно нужно прогнать тесты, чтобы убедиться, что существующая логика не повреждена. И главное - не забыть покрыть тестами решенную проблему.
После всего этого можно посылать pull request и ждать feedback от автора.
Если уж такой библиотеки, которую искал(а), нет, и хочется поделиться с комьюнити своим решением, то можно опубликовать свой модуль. Единственное, на что я хотел бы обратить внимание при публикации, - это лицензия, под которой он будет распространяться. Лицензия определяет правила распространения программного продукта и защищает авторские права. Так как Open Source лицензий достаточно много, знать их все совершенно не обязательно. Наиболее часто встречающиеся - это Apache-2.0, BSD, GNU и MIT. Но если не хочется разбираться с формальностями, то для этого случая команда github разработала сайт, который может помочь с выбором. Чаще всего лицензию можно найти в файле LICENSE в корне проекта.
Итого, структура файлов типичной open source библиотеки выглядит следующим образом:
lib/
docs/
tests/
examples/
readme.md
LICENSE
CHANGELOG
contributing.md
И вендорный файл с зависимостями и мета информацией (имя автора, название библиотеки и т.д.), в зависимости от языка.
Итог 📝
В заключении хочу сказать, что не под каждую задачу нужно искать готовое решение, как разработчику, вам не должно составлять труда решать задачи любой сложности, единственное, что может этому препятствовать, - время. Знание библиотек помогает его компенсировать, а также создавать более оптимизированный софт. Ведь Open Source предоставляет нам неограниченное множество готовых решений, качество которых не уступает коммерческим. Удобство использования и высокая отказоустойчивость - это не заслуга самого термина Open Source, а того, что им пользуются сотни тысяч умов. Самое время подключать свой 😉