Принципы

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

Примерами таких приложений являются CRUD-приложения, административный UI для веб-сайтов, инструменты автоматизации бизнеса, CRM-системы или системы класса ERP. Эти приложения часто предполагают управление десятками или сотнями взаимосвязанных объектов на сотнях или тысячах экранов, при этом в основном используются стандартные компоненты пользовательского интерфейса, такие как поля, формы и таблицы.

Чтобы эффективно создавать приложения такого рода, разработчикам нужен инструмент, позволяющий работать на более высоком уровне абстракции, чем тот, который обеспечивают базовые технологии, такие как Spring или Jakarta EE. Инструмент должен скрывать ненужные детали и избавлять от написания однообразного кода, поскольку такие приложения являются однообразными по своей природе: одни и те же сущности, атрибуты, поля пользовательского интерфейса, экраны и т.д. Но в то же время уровень абстракции не должен быть слишком высоким, чтобы позволить разработчикам описывать бизнес-логику на знакомом языке программирования и использовать современные мощные инструменты разработки - от IDE и VCS до фреймворков тестирования и CI/CD.

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

Фулл-стек разработка

Подход Jmix к фулл-стек разработке имеет два основных аспекта:

  1. Использование единого языка программирования и парадигмы разработки. Бэкенд-разработчик может реализовать бизнес-функциональность на всем стеке, от схемы базы данных до пользовательского интерфейса, при этом создавая простой синхронный Java (или Kotlin) код. Не нужно разбираться во фронтенд-технологиях, таких как асинхронный JavaScript и постоянно меняющаяся экосистема.

  2. Не обязательно создавать API. Веб-приложение на Jmix может отлично функционировать без реализации каких-либо API-эндпойнтов, привносящих дополнительную сложность и риски для безопасности.

Эти аспекты на самом деле следует приписать фреймворку Vaadin, который используется в Jmix под капотом. Vaadin предоставляет богатый набор UI-компонентов, каждый из которых имеет клиентскую и серверную части. Клиентская часть написана на JavaScript и работает в браузере, серверная часть написана на Java и работает на сервере. Пользователи взаимодействуют с клиентской частью компонентов, в то время как серверная часть напрямую работает с Java-кодом приложения:

principles full stack 1

Если вы не знакомы с этой концепцией, мы рекомендуем прочитать статью в нашем блоге: Простота и целесообразность серверной разработки веб-интерфейса. Здесь мы только кратко повторим выводы.

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

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

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

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

Таким образом, подход Jmix и Vaadin к фулл-стек разработке приносит максимальную пользу, если разработчики в основном удовлетворены функциональностью существующих UI-компонентов и нуждаются в глубокой кастомизации только в определенных частях пользовательского интерфейса приложения. Другое условие заключается в том, чтобы количество одновременно работающих с приложением пользователей было предсказуемым и не слишком большим (скажем, менее 100 тысяч). Оба условия обычно выполняются для B2B-приложений, для которых предназначен Jmix.

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

principles full stack 2

Jmix хорошо подходит для создания модульных монолитов любого размера. Концепция дополнений и поддержка композитных проектов в Studio обеспечивают гибкость при разделении кодовой базы. Дополнения OpenID Connect и Универсальный REST, а также тот факт, что Jmix полностью совместим с любым асинхронным коммуникационным решением, помогают интегрировать автономные прикладные сервисы в целостную информационную систему.

Единая модель данных

Jmix позволяет представлять данные из различных источников в единой унифицированной модели и использовать их напрямую в UI и бизнес-логике. Вам не нужно создавать слои объектов передачи данных (DTO) и мапперов из модели хранения и обратно.

Далее мы сравним традиционный архитектурный подход в разработке корпоративных Java-приложений с подходом Jmix и определим границы, в которых Jmix может принести наибольшую ценность.

Обычный подход в разработке современных корпоративных приложений заключается в том, чтобы иметь отдельные модели данных: одна для хранения, другая для представления и бизнес-логики. Иными словами, обычно у вас есть слой сущностей JPA, отображенных на таблицы базы данных, и отдельный слой объектов передачи данных (DTO) для передачи их во фронтенд и обратно через контроллеры REST (либо используя GraphQL или другие технологии API). В традиционном SPA-фронтенде на JavaScript также присутствуют те же DTO, представленные в формате JSON.

principles model 1

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

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

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

Как обсуждалось в предыдущем разделе, приложениям Jmix, благодаря Vaadin, не нужен API для создания пользовательского интерфейса. И вы можете легко ограничить доступ пользователей к данным: вы просто не создаете UI-компоненты для определенных атрибутов сущности, и эти атрибуты никогда не покидают серверную часть. Таким образом, аргумент безопасности в пользу наличия отдельных моделей также теряет свою силу.

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

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

Другой случай - когда вам нужно работать с источниками данных, отличными от реляционных баз данных. Тогда вы не можете использовать JPA и определяете модель с помощью простых Java-объектов (POJO), отображаемых на внешний API или нереляционную БД.

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

С помощью Jmix все эти требования (транзиентные атрибуты; POJO, отображающие внешние данные; POJO только для UI) могут быть реализованы в рамках единой модели данных. То есть, вместо того чтобы реализовывать различные модели одну над другой, вы можете расширить основную модель хранения JPA, добавив в нее элементы, отличные от JPA.

principles model 2

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

В разделе Модель данных и метаданные описывается, как Jmix предоставляет унифицированную модель данных, содержащую различные элементы, и какие возможности это дает.

Готовые компоненты

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

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

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

Использование мейнстрим-технологий

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

С точки зрения инструментария и практик разработки, вы можете использовать современные фреймворки тестирования, статический анализ кода, CI/CD и системы контроля версий.

Расширяемость

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

В разделе Модульность и расширение подробно описаны возможности расширения Jmix.