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

Змея питона, не связанная с языком программирования Python.

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

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

Создание индивидуального программного обеспечения для бизнеса - это не новость. Программная индустрия начала с этого в 60-х годах, а затем развилась в 80-х годах в сторону доминирующей модели упаковки, которую мы знаем сегодня. Как правило, индивидуальное программное обеспечение имеет много нежелательных свойств по сравнению с упакованным: более высокие первоначальные инвестиции, длительные настройки, более высокие затраты на обслуживание, большие риски и т. д.

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

Исчерпав все, что казалось возможным, мы пришли к выводу, что создание индивидуальных приложений - это единственный путь. Однако, масштабируемость; как доставлять множество приложений, и поддерживаемость; как держать затраты на обслуживание под контролем, были двумя основными проблемами. Сначала нам нужно было выбрать язык программирования. В то время мы рассматривали множество вариантов: R, Python, JavaScript, Lua, C#, … и разработку собственного предметно-ориентированного языка программирования (DSL), который позже стал известен как Envision. Обсуждение плюсов и минусов всех этих вариантов было бы несколько утомительным[^утомительным], поэтому ради ясности обсуждение должно было ограничиться выбором между Python и Envision; при этом Python был самым сильным конкурентом для разработки собственного DSL.

Python был привлекателен своей простотой и всем его богатым экосистемой сторонних библиотек, особенно в области машинного обучения[^экосистемы]. Кроме того, это был низкозатратный вариант для Lokad: поскольку Python и практически все его популярные библиотеки являются открытым исходным кодом, нам бы просто пришлось упаковать узкий набор Python, разрешив только несколько десятков отобранных пакетов, и все. Большая часть работы для Lokad была бы связана с созданием опыта PaaS вокруг Python, насколько это возможно, с учетом вызовов цепочки поставок.

Однако здесь есть проверка на прочность, которую мы рассматривали: разумно ли ожидать, что бизнес-аналитик - позже известный как специалист по цепочкам поставок - работающий 1 день в неделю в течение 6 месяцев сможет создать приложение производственного уровня для решения критической задачи цепочки поставок, например, пополнение запасов, для компании стоимостью $10 млн? При рассмотрении варианта Python было ясно, что мы никогда не сможем даже приблизиться к такому уровню операционной эффективности.

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

Таким образом, мы создали Envision как язык, чтобы устранить целые классы технических проблем, которые неизбежны при использовании Python. Например:

  • Объекты могут быть null, даты могут быть абсурдно далеко в прошлом или будущем, NaN может счастливо распространяться через вашу конвейер данных, строки могут становиться абсурдно большими… В цепочке поставок эти “функции” - это только проблемы, которые ждут своего часа.
  • Объектно-ориентированные элементы (т.е. классы) гарантированно будут использоваться неправильно[^неправильно], и то же самое можно сказать о пользовательских исключениях или регулярных выражениях. Присутствие этих элементов, в лучшем случае, является нездоровым отвлечением.
  • Несколько базовых операций, таких как разбор разнородных табличных файлов (включая электронные таблицы Excel), не являются частью языка и требуют работу с множеством разнородных пакетов, каждый из которых имеет свои собственные технические тонкости.

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

Подумайте о последний раз, когда вам пришлось выполнять вычисления с помощью электронной таблицы Excel, и представьте себе, что вы диктуете все изменения, которые вы внесли в эту таблицу Excel по телефону, не имея возможности видеть саму таблицу Excel. Вот как выглядит инициатива по оптимизации цепочки поставок, управляемая практикующими специалистами, но реализованная программными инженерами (не специалистами по цепочке поставок). Бизнес тратит огромное количество времени на то, чтобы передать то, что он хочет, IT; и IT тратит огромное количество времени, пытаясь понять, чего хочет бизнес. После десятилетия опыта в Lokad я наблюдаю, что полагаться на разработчиков программного обеспечения, которые не являются специалистами по цепочке поставок, для реализации инициативы по оптимизации количественной цепочки поставок увеличивает затраты как минимум в 5 раз, независимо от того, насколько гибкой и талантливой может быть команда разработчиков программного обеспечения.

Во-вторых, затраты на обслуживание спешных прототипов на Python выходят за пределы разумного. Вне сферы программного обеспечения немногие понимают, что программная инженерия[^инженерия] в основном связана с контролем затрат на обслуживание. Однако решение проблем оптимизации цепочки поставок - это хаотичный процесс: данные из множества (плохо) надежных систем должны быть надежно переданы, несовершенные и постоянно меняющиеся процессы должны быть задокументированы и моделированы, метрики оптимизации отражают бизнес-стратегию в постоянном состоянии изменения и т. д. В результате любой программный продукт, написанный для реализации оптимизации цепочки поставок, всегда содержит огромное количество специфической для отрасли сложности, просто справляясь с тем, что мир бросает нам.

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

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

Таким образом, единственный практический способ сохранить производство в здравом уме - написать прототип с использованием языка программирования, который обеспечивает высокую степень корректности по дизайну. Например, в отличие от Python, Envision обеспечивает:

  • Конечное время выполнения, гарантированное на этапе компиляции: при обработке нескольких терабайтов данных становится очень утомительно ждать несколько часов, чтобы понять, что вычисление просто никогда не завершится.
  • Ограниченное потребление памяти, гарантированное на этапе компиляции: борьба с ошибками нехватки памяти в ночной пакетной обработке производства - это все, кроме веселья, и на практике серьезно нарушает работу.
  • Атомарное чтение и запись: Envision предотвращает, по своему дизайну, одновременное чтение и запись в файловой системе, даже когда файлы передаются через FTP во время выполнения скриптов. Файловая система, поддерживающая Envision, по сути, является Git, специально разработанным для гигантских плоских файлов. Без правильной версионирования данных многие ошибки превращаются в хейзенбаги: к тому времени, когда кто-то вникает в проблему, данные уже обновлены, и проблему больше нельзя воспроизвести.
  • Амбиентное масштабирование выполнения программы на облачном вычислительном ресурсе, устраняющее все проблемы параллелизации, которые неизбежны, как только объем данных превышает несколько десятков гигабайт.

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

Вот еще несколько областей, в которых Envision сияет таким образом, который просто недоступен для Python:

Защита в глубину: Как только кто-то начинает писать код в вашей организации, если не предпринимаются очень специальные меры3, их код сразу становится непосредственной угрозой с точки зрения информационной безопасности. Через Python практически возможно сделать все на машине, на которой выполняется скрипт Python. Правильное ограничение возможностей Python на практике является чрезвычайно сложной проблемой. В частности, любая строка, созданная скриптом Python, является потенциальным вектором инъекции. В то время как SQL-инъекции известны, (слишком) мало людей понимают, что даже обычные текстовые файлы, такие как CSV, уязвимы для инъекционных атак. Envision обеспечивает уровень безопасности, который просто невозможно воспроизвести с помощью Python. Утечки данных становятся все более распространенными, и разбрасывание кусочков Python повсюду не принесет никакой пользы для информационной безопасности.

Прозрачная производительность: Если программа слишком медленно выполняется, то эта программа не должна компилироваться вообще4. Если программа становится на одну строку короче, то она должна выполняться быстрее. Если изменяется только одна строка, то пересчитываться должна только эта строка5, при повторном запуске программы на тех же данных. При компиляции компилятор должен нацеливаться не на конкретную машину, а на облачный вычислительный ресурс, обеспечивая автоматическую параллелизацию на основе данных. Envision идет далеко в достижении всех этих свойств по умолчанию без каких-либо усилий по кодированию. В отличие от этого, для того чтобы хотя бы начать приближаться к таким свойствам в Python, требуется массовое использование специализированных библиотек.

Прозрачное обновление: Состояние искусства - это постоянно движущаяся цель в отношении программного обеспечения. В 2010 году лучшим инструментом машинного обучения был SciPy (возможно). В 2013 году это был scikit. В 2016 году это был Tensorflow. В 2017 году это был Keras. В 2019 году это был PyTorch. В программной инженерии есть поговорка, что год создания любого данного программного проекта можно определить, посмотрев на его стек программного обеспечения и его зависимости. Действительно, как только вы запускаете свои собственные скрипты на Python, вы будете использовать несколько зависимостей, которые могут устареть. В отличие от этого, с помощью Envision мы широко используем автоматическую перезапись кода6, чтобы держать “устаревшие” скрипты в актуальном состоянии с постоянно меняющимся языком.

Упакованный стек: Скрипты на Python не могут существовать в вакууме7. Код должен быть версионирован (например, с помощью Git) с учетом прав доступа (например, GitHub). Они нуждаются в среде выполнения, которая не является вашей машиной (например, виртуальная машина Linux в облаке). Необходим планировщик для оркестрации потока данных (например, AirFlow). Для подготовки данных требуется распределенное колоночное хранилище (например, Spark). Для аналитики прогнозирования требуется инструментарий машинного обучения (например, TensorFlow). Для решения комбинаторных проблем цепочки поставок требуется инструментарий оптимизации (например, GLPK). Сырые результаты должны быть доступны где-то для последующего использования (например, на SFTP-сервере). Практикующим специалистам по цепочке поставок должна быть доступна возможность отслеживать происходящее (например, веб-интерфейс). Необходимо обеспечить соблюдение прав доступа (.e.g. Active Directory) и т.д. Envision упрощает все это в единую мета-приложение, снимая бремя сборки десятков программных компонентов для создания даже самого базового приложения.

Затем, хотя это и отличный язык, Python не без недостатков:

  • Производительность вычислений плохая, и это борьба с течением времени, чтобы направить каждый расчет через правильную библиотеку (например, NumPy), чтобы избежать катастрофически плохой производительности при обработке данных. Кроме того, использование нескольких библиотек часто создает много трения, когда данные должны быть перемещены из одной в другую.
  • Производительность памяти также плохая, и в частности, сборка мусора с подсчетом ссылок в Python устарела, и все более новые языки программирования, такие как Java, C# или JavaScript, используют трассировку. При работе с памятью, требующей больших ресурсов, это наносит ущерб.
  • Управление пакетами в Python было беспорядком в течение длительного времени, и для его правильной работы требуется специалист по пакетам. Кроме того, эту проблему усугубляют сложные обновления языка.
  • Большинство (немногих) проверок на корректность происходят только в время выполнения, когда программа выполняется, что является источником бесконечного разочарования при обработке данных. Очевидные проблемы проявляют себя только после нескольких минут выполнения, что снижает производительность.

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

Разработка Envision, языка программирования, посвященного предиктивной оптимизации цепочки поставок, не была нашим первым выбором. Это даже не был наш 10-й выбор. Это было больше похоже на единственное рабочее решение, которое у нас было после исчерпания длинного списка более традиционных альтернатив в течение пяти лет. Семь лет спустя и многие клиентские компании позже, каждый новый клиент все равно удивляет нас, одним образом или другим, еще одним поворотом в своей цепочке поставок, с которым мы никогда не смогли бы справиться с помощью классического подхода к предприятию. Была необходима программирование, но Python не был тем решением, которое нам было нужно.


  1. Вернувшись в 2013 год, я все еще был уверен, что возможно создать удовлетворительное приложение для оптимизации цепочки поставок. На самом деле, столкновение с проблемами ценообразования каким-то образом заставило нас идти вперед и направить Lokad по пути создания собственного языка предметной области. Изначально этот язык предназначался только для оптимизации ценообразования, но вскоре мы поняли, что такой подход также идеально подходит для оптимизации цепочки поставок. ↩︎

  2. Идея о том, что достижение превосходной точности прогнозирования само по себе приведет к превосходной производительности цепочки поставок, вероятно, была одним из самых больших заблуждений, которые я имел, основывая Lokad. Посмотрите этот эпизод Lokad TV для более здравой перспективы по этому вопросу. ↩︎

  3. К сожалению, в вопросах безопасности кода мало или нет замены систематическому рецензированию кода. ↩︎

  4. Из-за проблемы остановки внимательный читатель может заключить, что Envision не является языком полного Тьюринга. Действительно, Envision им не является. ↩︎

  5. Envision полагается на разницу между вычислительными графами и старается минимизировать количество повторных вычислений при инкрементальных изменениях, чтобы обеспечить очень быстрое прототипирование на больших наборах данных. Однако, в зависимости от ситуации, изменение одной строки может потребовать пересчета всего скрипта. ↩︎

  6. Автоматическая перезапись кода чрезвычайно сложна для общего языка программирования. Если язык программирования и его стандартная библиотека не были точно разработаны с учетом этого требования, автоматические инструменты обновления практически бесполезны. Проектируя Envision, мы знали, что сделаем много ошибок (и сделали), и поэтому уделили большое внимание тому, чтобы язык был особенно подходящим для автоматической перезаписи. На сегодняшний день мы выполнили более 100 инкрементальных перезаписей с момента создания Envision. ↩︎

  7. Иронично, “Batteries Included” - одно из девизов Python. Однако, огромное количество “клея”, необходимого для объединения всех элементов, необходимых для создания приложения, предназначенного для оптимизации предиктивной цепочки поставок, является пугающим. ↩︎