Зависимости кода - это дьявол.

Ваши зависимости будут сжигать вас каждый раз.
«Изменения - единственная постоянная…» - Гераклит (Философ)

Инструменты, библиотеки и платформы, которые мы используем для создания наших веб-приложений сегодня, кардинально отличаются от тех, которые мы использовали всего несколько лет назад.

Через несколько коротких лет большинство этих технологий снова сильно изменится. Тем не менее, многие из нас делают их центральной неотъемлемой частью наших приложений.

Мы импортируем, используем и наследуем от фреймворков «месяц-месяц», как если бы они были всегда и остаются неизменными навсегда. Ну, нет. И это проблема.

После 20 с лишним лет разработки, проектирования и разработки веб-приложений я осознал две важные истины:

  1. Внешние зависимости представляют большую угрозу для долгосрочной стабильности и жизнеспособности любого приложения.
  2. Становится все труднее - если не невозможно - создавать какие-либо нетривиальные приложения без использования внешних зависимостей.

Эта статья о том, как примирить эти две истины, чтобы наши приложения имели наибольшие шансы на долгосрочное выживание.

Кроличья нора действительно очень глубокая.

Если мы начнем думать обо всех вещах, от которых зависят наши веб-приложения, легко придумать дюжину или больше, прежде чем мы даже перейдем к коду:

  • Сила
  • связь
  • Межсетевой экран
  • DNS
  • Серверное оборудование (CPU, Disk, Ram,…)
  • Охлаждение
  • Платформа виртуализации
  • Контейнерная платформа
  • Операционная система
  • Платформа веб-сервера
  • Платформа сервера приложений
  • Веб-браузер

Как разработчики, хорошо знать об этих вещах, но зачастую мы мало что можем с ними поделать. Итак, давайте пока проигнорируем их и поговорим только о коде.

В коде есть три вида зависимостей:

1. Зависимости, которые мы контролируем

Это код, написанный и принадлежащий нам или нашей организации.

2. Зависимости, которые мы не контролируем

Это код, написанный сторонним поставщиком программного обеспечения или сообществом разработчиков программного обеспечения с открытым исходным кодом.

3. Зависимости после удаления

Это зависимости кода, от которых зависят сторонние зависимости кода. (Скажи это три раза быстро!)

Мы будем говорить в основном о зависимостях, которые мы не контролируем.

Зависимости, которые мы контролируем, и зависимости, однажды удаленные, могут по-прежнему вызывать головные боли, но в случае зависимостей, которые мы контролируем, мы должны иметь возможность напрямую вмешиваться и смягчать любые проблемы.

В случае удаления зависимостей, как правило, мы можем рассчитывать на то, что сторонние организации позаботятся об этом за нас, поскольку они тоже зависят от них.

Почему сторонние зависимости кода хороши

Большая часть вашего веб-приложения существует для решения общих проблем: аутентификация, авторизация, доступ к данным, обработка ошибок, навигация, ведение журналов, шифрование, отображение списка элементов, проверка входных данных форм и т. Д. ...

Независимо от того, какой технологический стек вы используете, существует большая вероятность того, что общие решения этих проблем существуют и доступны в виде библиотек, которые вы можете легко приобрести и подключить к своей базе кода. Написание любого из этих вещей полностью с нуля, как правило, пустая трата времени.

Вы хотите сосредоточиться на коде, который либо решает необычную проблему, либо решает распространенную проблему необычным способом. Вот что делает ваше приложение ценным: код, который реализует бизнес-правила, уникальные только для вашего приложения - «секретный соус».

Алгоритм поиска и ранжирования страниц Google, фильтрация временной шкалы Facebook, раздел «Рекомендуется для вас» Netflix и алгоритмы сжатия данных - код, стоящий за всеми этими функциями, - «секретный соус».

Сторонний код - в форме библиотек - позволяет вам быстро реализовать те коммодитизированные функции вашего приложения, чтобы вы могли сосредоточиться на своем «секретном соусе».

Почему сторонние зависимости кода плохие

Взгляните на любое нетривиальное веб-приложение, созданное за последние пару лет, и вы будете совершенно поражены количеством кода, который фактически поступает из сторонней библиотеки. Что если одна или несколько сторонних библиотек кардинально изменятся, исчезнут или сломаются?

Если это с открытым исходным кодом, возможно, вы можете исправить это самостоятельно. Но насколько хорошо вы понимаете весь код в этой библиотеке, которой вы не владеете? Основная причина, по которой вы используете библиотеку в первую очередь, заключается в том, чтобы получить преимущества кода, не беспокоясь о всех деталях. Но теперь ты застрял. Вы полностью связали свое состояние с этими зависимостями, которыми вы не владеете и не контролируете.

Не волнуйтесь, к концу этой статьи вы найдете новую надежду.

Возможно, вы думаете, что я преувеличиваю или говорю с чисто академической точки зрения. Позвольте мне заверить вас - у меня есть десятки примеров клиентов, которые полностью обманули себя, слишком плотно внедрив сторонний код в свое приложение. Вот только один недавний пример ...

Мой бывший клиент создал свое приложение, используя поставщика Backend-as-a-Service, принадлежащего Facebook, который называется Parse. Они использовали клиентскую библиотеку JavaScript, предоставленную Parse, для использования службы Parse. В процессе они тесно связали весь свой код, включая код «секретного соуса», с этой библиотекой.

Через три месяца после первого запуска продукта моего клиента - так же, как он начал набирать обороты с реальными, платящими клиентами - Parse объявил, что закрывается.

Теперь вместо того, чтобы сосредоточиться на итерации своего продукта и расширении клиентской базы, моему клиенту пришлось выяснить, как перейти на собственную версию Parse с открытым исходным кодом или полностью заменить Parse.

Нарушение, которое это вызвало для молодого, неоперившегося приложения, было настолько огромным, что мой клиент в итоге полностью удалил приложение.

Балансирование добра и зла

Несколько лет назад моим подходящим решением для преодоления рисков при сохранении преимуществ сторонних библиотек было их обертывание с использованием шаблона адаптера.

По сути, вы оборачиваете сторонний код в класс или модуль адаптера, который вы написали. Затем это работает, чтобы показать функции сторонних библиотек способом, которым вы управляете.

Используя этот шаблон, если сторонняя библиотека или инфраструктура изменяется или исчезает, вам нужно только исправить немного кода адаптера. Остальная часть вашего приложения остается неизменной.

Диаграмма шаблона адаптера от Dofactory.com

Это звучит хорошо на бумаге. Когда у вас есть автономные зависимости, которые предоставляют только несколько функций, это поможет. Но все может стать ужасно быстро.

Можете ли вы представить себе необходимость обернуть всю библиотеку React (включая JSX) перед использованием какой-либо из них? Как насчет упаковки jQuery, Angular или Spring в Java? Это быстро становится кошмаром.

В эти дни я рекомендую более нюансированный подход ...

Для каждой зависимости, которую вы хотите добавить в свою кодовую базу, оцените уровень риска, который она будет представлять, умножив два фактора:

  1. Вероятность того, что зависимость изменится материально.
  2. Количество ущерба, которое материальное изменение в зависимости может нанести вашему приложению.

Сторонняя библиотека или инфраструктура с меньшей вероятностью изменятся, если выполняются некоторые или все из следующих вещей:

  • Он существует уже несколько лет и выпустил несколько крупных релизов.
  • Он широко используется во многих коммерческих приложениях.
  • Он имеет активную поддержку крупной организации - предпочтительно, компании или учреждения с именем нарицательным.

Сторонние библиотеки или фреймворки будут наносить меньше вреда вашему приложению, если выполняются некоторые или все из следующих условий:

  • Он используется только небольшой частью вашего приложения, а не повсеместно.
  • Код, который зависит от него, не является частью того «секретного соуса», о котором я говорил ранее.
  • Удаление этого требует минимальных изменений в вашей кодовой базе.
  • Все ваше приложение очень маленькое и может быть быстро переписано. (Будьте осторожны с этим - это редко бывает так долго.)

Чем рискованнее что-то, тем больше у вас шансов обернуть это или вообще избежать.

Когда дело доходит до кода, который действительно является центральным для ценностного предложения вашего приложения - вашего «секретного соуса» - вы должны быть чрезвычайно осторожны с ним. Сделайте этот код максимально независимым. Если вам абсолютно необходимо использовать зависимость, рассмотрите возможность внедрения ее, а не прямой ссылки на нее. Даже тогда будьте осторожны.

Иногда это означает сказать «нет» сторонней библиотеке, которую вы считаете действительно крутой, или которую вы действительно хотите использовать по той или иной причине. Быть сильным. Поверь мне, это окупится. Спросите всех тех людей, которые вложили большие средства в самый первый выпуск Angular, или моего бывшего клиента, который использовал Parse везде. Это не весело. Поверь мне.

Говоря о веселье, взгляните на это ...

График зависимостей для TinyTag Explorer

Изображение выше представляет собой график зависимости для приложения под названием TinyTag Explorer.

Создание графа зависимостей для ваших существующих приложений - отличный способ понять уровень риска, который представляют ваши зависимости. Я собрал список бесплатных инструментов для генерации графиков, похожих на приведенные выше, на различных языках, включая JavaScript, C #, Java, PHP и Python. Вы можете получить его здесь.

Помоги мне помочь другим

Я хочу помочь как можно большему количеству разработчиков, поделившись с ними своими знаниями и опытом. Пожалуйста, помогите мне, нажав кнопку ❤ рекомендовать (зеленое сердце) ниже.

Наконец, не забудьте захватить свой список свободных генераторов графов зависимостей здесь.