Игорь Шавловский, iOS-разработчик в neoviso, написал для Dev.by колонку о том, почему библиотеки не всегда полезны разработчику.
Я постоянно сталкиваюсь с тем, что нужно решать типовые задачи, которые отсутствуют в стандартных фреймворках. Одна из них встречается в 90% проектов — это боковое меню. У каждого разработчика есть любимый под (библиотека, включаемая в проект через CocoaPods) для решения такой задачи. Таких подов на просторах GitHub, наверное, уже больше сотни. Возникает проблема точного соответствия поведения меню и технического задания. Аспектов много: затемнение, взаимодействие с жестами главного контроллера, различное поведение на iPhone и iPad, правила открытия и скрытия меню, использование navigation controller внутри меню. Библиотека не охватит все задачи. Она может не поддерживать или, наоборот, иметь лишние неотключаемые анимации, не уметь синхронизироваться с другими операциями.
Зачем вообще использовать библиотеку, если базовое меню писать 20 минут, а расширенное, со всеми «свистелками» — три часа? И в этом меню не возникнут упомянутые выше проблемы.
1. Чужой код = чужие ошибки
Любой код содержит ошибки. Но если в своём коде их легко найти и исправить, чужой код править сложнее. Если ошибка не лежит на поверхности, а является следствием неправильного подхода к архитектуре, то даже если вы исправите её в своей копии библиотеки, придётся исправлять её после каждого обновления от разработчика. Внести предложение по исправлению библиотеки — опять же не решение. Ошибкая для вас — для другого просто неправильный случай использования кода, поскольку это ваши нужды и ваше техническое задание.
2. Нет исходного кода
Часто библиотеки распространяются с исходным кодом, но не всегда. Тогда у разработчика возникают проблемы с анализом происходящего «внутри» библиотеки. Он не может предсказать поведение и возможные проблемы, убедиться, что правильно подготовил данные. А в случае, когда библиотека написана в плохом стиле или без надлежащей спецификации, невозможно понять, какой из схожих методов надо использовать и в какой последовательности.
3. Нет гарантий поддержки
Любая, в том числе самая продвинутая библиотека, в какой-то момент теряет популярность. А проекты, построенные на ней, рискуют потерять даже минимальную возможность поддержки обновлённого SDK. Часто на гитхабе можно заметить, как хорошую библиотеку, на которую забил оригинальный разработчик, забирают себе под крыло другие. Иногда из этого вырастают мощные фреймворки, которые становятся стандартами разработки.
По закону подлости именно та библиотека, на которой вы завяжете большую часть своего кода, потеряет поддержку и не сможет перешагнуть на новую версию операционной системы.
4. Пределы каждой библиотеки
Часто библиотеки заточены под решение узкого круга задач и не стрессоустойчивы под большой параллельной нагрузкой или в нетипичных случаях. Простой пример — singleton-библиокеки, которые инициализируются единожды и не могут поменять параметры настройки в процессе выполнения. Или библиотека заточена под то, чтобы брать настройки из ресурсов приложения, а согласно вашей архитектуре настройки приходят с сервера при логине да ещё и могут меняться по какому-нибудь событию. Или библиотека запускает прекрасную анимацию, но не может начать её с середины, а вам позарез надо переложить превью на другой слой в процессе её выполнения. Этот список можно продолжать. У каждой библиотеки в Readme репозитория есть красивая гифка с примером работы и три строчки кода, рассказывающие, как легко её использовать. Но никто не ответит вам на вопрос «а что, если мне надо делать не так, а вот так?».
5. Зависимости
Чем больше библиотека, которую вы используете, тем больше шанс, что ей самой будут нужны поддерживающие её библиотеки. Здесь кроются одновременно две проблемы. Первая заключается в том, что сама библиотека страдает от описанных проблем. Вторая — зависимости могут пересекаться. Ваша программа и библиотека (или просто две библиотеки) могут использовать одну и ту же третью библиотеку, и только при счастливом стечении обстоятельств все они будут публично включать одну и ту же версию. В противном случае вы получите бесконечные ошибки линковки.
6. Утяжеление приложений
Иногда очень хочется подключить огромную библиотеку, чтобы использовать её небольшой кусочек. Это может привести к тому, что библиотека полностью влинкуется в конечный продукт, что значительно увеличит размер вашего приложения.
7. Тривиальность, необоснованная сложность, ограниченность
Конкретную библиотеку используют часто не потому что задача сложная, а потому, что разработчик ленив. Однажды мне попалась задача асинхронной обработки изображений на графическом процессоре. Я нашел отличную библиотеки, которая делала в точности то, что мне требовалось, но было несколько нюансов: она работала только в главном потоке, вызывалась с уровня view, а не model, имела сотни исходных файлов, в которых надо было отслеживать цикл работы. Вместо того, чтобы неделю перекраивать работающий код под свои нужды, я за день написал оболочку для чистого OpenGL и решил задачу двумя сотнями строчек кода. Притом код можно было использовать в любой момент работы программы примерно так же, как используют асинхронный сетевой запрос. На следующий день решение обросло кэшем и повторным использованием текстур для оптимизации более сложных операций — и вуаля! Я переписал библиотеку из многих тысяч строк кода и сделал её универсальной, расширяемой, читаемой и быстрой. На это у меня ушло меньше времени, чем я потратил изначально на запуск сторонней библиотеки. Хороший урок.
8. Дичь в рантайме
Библиотеки имеют такой же доступ ко всем возможностям SDK, как и разработчик, и используют по полной, никакой песочницы. А что если разработчик не хочет этого? Больше всего в «гадить там, где выполняешься» преуспели библиотеки аналитики. Если раньше разработчик передавал им все необходимые события, сейчас они берут их сами. В iOS это делается через механизм method swizzling: библиотека просто подменяет родные методы SDK своими собственными, перекраивая все механизмы в вашем приложении так, чтобы потоки данных проходили через неё.
Однажды я заметил, что простая пересортировка «вьюх» стала выполняться слишком долго. Я остановил программу в момент одного из таких подвисаний и увидел, что моя библиотека аналитики буквально залезла внутрь UIKit и при каждом изменении иерархии «вьюх» проводит кучу ненужных мне вычислений, пытаясь найти компоненты, которые она бы умела трекать автоматически. Не удивился, когда увидел, что это невозможно отключить настройками библиотеки. Пришлось лезть в исходный код, чтобы со всем разобраться. Если учесть, что современная версия библиотеки поставляется без исходного кода, я навсегда застрял с просроченной «либой», где костылём подпёр дверь, за которой находится монстр метод-свизлинга. И это не единственная проблема с данной библиотекой.
9. Они меняют интерфейсы
Со временем библиотека эволюционирует, разработчик правит имена методов, улучшает код, делает рефактор. Это полезно для его кода, но не для вашего. Ваш код ведь работает! Захотите получить свежую фичу или исправление старой ошибки, а библиотека полностью поменяла свои интерфейсы, и теперь вам придётся рефакторить свой код вслед за ней. Более того, отдельные методы могут пропасть. Выше упомянутая библиотека аналитики потеряла событие окончания отправки данных на сервер, в результате этого я не мог отправлять аналитику до начала работы программы, чтобы быть уверенным, что startup crash не помешает этому.
10. Они не посылают события
Часто разработчику надо знать, что происходит во время выполнения определённых длительных операций, но библиотеки почти никогда не дают такую информацию, ведь они написаны не под ваши нужды. Вот почему не всегда можно узнать о наступлении каких-то состояний и событий, которые могут быть важны для приложения.
Но невзирая на все «не», в той или иной степени, использование библиотек и фреймворков в нашей работе неизбежно. Во-первых, SDK и библиотек, включённых в стандарт разработки. Во-вторых, тех, что помогают решать сложные и/или трудоёмкие задачи: AR, построение графиков, реализация стандартов обработки данных, к примеру, парсеры, сетевые протоколы, базы данных.
В их использовании нет ничего плохого, но в следующий раз, начиная новый проект, задумайтесь, насколько вам нужен тот же jQuery, AFNetworking или что-то ещё. Возможно, будет полезней вместо слепого включения в проект изучить исходный код, подходы, которые использует та или иная библиотека, и написать свой код. Удобный, быстрый, универсальный, отказоустойчивый. Создавайте собственные готовые решения, собирайте качественный код и пишите свои библиотеки. Вероятно, когда-нибудь именно они войдут в чей-то стандарт разработки.
Релоцировались? Теперь вы можете комментировать без верификации аккаунта.