🦉 Почему Owl ? 🦉

Общепринятая мудрость заключается в том, что не следует изобретать велосипед заново, так как это приведет к пустой трате усилий и ресурсов. И это верно в большинстве случаев. Фреймворк на javascript - это значительные инвестиции, поэтому вполне логично задать вопрос: почему Odoo решил создать OWL вместо использования стандартного/хорошо известного фреймворка, такого как React или Vue?

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

Это означает, например, что основные части Odoo до самого факта выполнения не знают о том, какие файлы будут загружены/выполнены или каково будет состояние пользовательского интерфейса. Из-за этого Odoo не может полагаться на стандартные инструменты сборки. Кроме того, это подразумевает, что основные части Odoo должны быть чрезвычайно общими. Другими словами, Odoo на самом деле не является приложением с пользовательским интерфейсом. Это приложение, которое генерирует динамический пользовательский интерфейс. И большинство фреймворков не справляются с этой задачей.

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

Стратегия

Это правда, что мы хотим сохранить контроль над нашей технологией так как мы не хотим зависеть от Facebook или Google, или любого другого крупного (или малого) вендора. Если они решат сменить свою лицензию или пойти в направлении, которое нам не подходит, это может стать проблемой. Более того Odoo - это не обычное приложение на javascript, и скорее всего наши потребности совершенно не похожи на большинство других приложений.

Компоненты на базе классов

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

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

Совместное использование кода между универсальными компонентами с наследованием - это то на чем построен веб-клиент Odoo И ясно, что наследование - это не корень всех зол. Часто это совершенно простое и подходящее решение. Самое главное - это архитектурные решения.

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

Использование React или Vue значительно усложнило бы обработку патчей компонентов, потому что большая часть состояния скрыта в их внутренностях.

Инструментарий

У React или Vue огромное сообщество, и в их инструментарий было вложено много усилий. Это замечательно, но в то же время - большая проблема для Odoo: поскольку ресурсы полностью динамичны (и могут меняться всякий раз, когда пользователь устанавливает или удаляет дополнение), нам нужно иметь весь этот инструментарий на продукшен серверах. И такой подход весьма далек от идеала.

Кроме того, это очень усложняет настройку инструментов Vue или React: код Odoo - это не простой файл, который импортирует другие файлы. Он постоянно меняется, ассеты объединяются по-разному и в разных контекстах. Все это и является причиной, по которой Odoo имеет свою собственную модульную систему, которая разрешается во время выполнения браузером. Динамическая природа Odoo означает, что нам часто приходится откладывать работу на как можно более поздний этам (другими словами, нам нужен пользовательский интерфейс JIT!)

Наш идеальный фреймворк имеет минимальный (обязательный) инструментарий, что упрощает его развертывание. Использование React без JSX или Vue без файла vue не очень привлекательно.

В то же время Owl предназначен для решения этой проблемы: он компилирует шаблоны браузером, для этого не требуется много кода, поскольку мы используем XML-анализатор, встроенный в каждый браузер. Owl может раотать как с дополнительными инструментами или без них. Он может использовать строки шаблона для написания компонентов из одного файла и легко интегрируется в любую html-страницу с помощью простого тега <script>.

Основан на шаблонах

Odoo хранит шаблоны в виде XML-документов в базе данных. Это очень мощно, поскольку позволяет использовать xpath для кастомизации других шаблонов. Это очень важная особенность odoo и один из ключей к модульности Odoo.

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

Итак, использование React или Vue означает, что нам нужно создать компилятор шаблонов. Для React это был бы компилятор, который взял бы шаблон QWeb и преобразовал его в фукнцию рендеринга React. Для Vue он преобразовал бы его в шаблон Vue. Затем нам также нужно объединить компилятор шаблонов vue.

Это было бы не только сложно (компиляция языка шаблонов в другой - непростая задача), но и негативно сказалось бы на работе разработчика. Написание компонентов Vue или React в виде шаблона QWeb, было бы неудобным и очень запутанным.

Опыт разработчиков

Это подводит нас к следующему пункту: опыт разработчика. Мы рассматриваем наш выбор как инвестицию в будущее, и мы хотим максимально упростить адаптацию разработчиков.

В то время как многие профессионалы javascript явно думают, что react/vue не сложен (что в некоторой степени верно), также верно и то, что многие специалисты, не являющиеся специалистами по js, перегружены миром фронтенда: функциональными компонентами, хуками и многими другими причудливыми словами. Кроме того, то, что понимание того что происходит в контексте компиляции, может быть затруднено, практически в каждом фреймворке происходит много черной магии. Vue каким-то образом объедините различные пространства имен в одно, под капотом, и добавьте различные внутренние ключи. Svelte преобразовывае код. React же в своюу очередь требует, чтобы преобразования состояний были глубокими, а не поверхностными.

Owl очень старается иметь простой и знакомый API. Он использует классы. Его система реактивности является явной, а не неявной. Правила определения области очевидны. В случае сомнений мы допускаем ошибку, не реализуя ту или иную функцию.

Это, безусловно, отличается от React или Vue, но в то же время отчасти знакомо опытным разработчикам.

JIT компиляция

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

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

Более того: Odoo должен иметь возможность генерировать (и компилировать) шаблоны во время выполнения. В настоящее время представления форм Odoo интерпретируют xml-описание. Но код представления формы тогда должен выполнять множество сложных операций. С помощью Owl мы сможем преобразовать описание представления в шаблон QWeb, затем скомпилировать его и немедленно использовать.

Реактивность

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

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

Конкурентное исполнение

Многие приложения рады просто отображать счетчик всякий раз, когда выполняется новое асинхронное действие, но Odoo хочет другого пользовательского интерфейса: большинство асинхронных изменений состояния не отображаются до готовности. Это иногда называют конкурентным режимом: пользовательский интерфейс отображается в памяти и отображается только тогда, когда он готов (и только если он не был отменен последующими действиями пользователя).

У React теперь есть экспериментальный конкурентный режим, но он не был готов, когда Owl запустился. У Vue на самом деле нет эквивалентного API (suspense - это не то, что нам нужно).

Кроме того, конкурентный режим React сложен в использовании. Параллелизм был одной из редких сильных сторон прежнего фреймворка Odoo js (виджеты), и мы считаем, что Owl теперь имеет очень сильный конкурентный режим, который одновременно прост и мощен.

Вывод

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

Однако мы чувствуем, что в мире фреймворков все еще есть место для чего-то другого. Для фреймворка, который делает его совместимым с Odoo.

И именно поэтому мы создали Owl 🦉.