Principles
Jmix is designed for creating web applications with extensive data models and complex UI primarily tailored for internal users of an organization.
Examples of such applications include a simple CRUD, an admin UI for a website, a business automation tool, a CRM or an ERP-class system. These applications typically involve managing dozens or hundreds of interconnected entities in hundreds or thousands of screens, while using mostly standard UI components like fields, forms and tables.
To effectively create applications of such kind, developers need a tool that enables them to operate on a higher level of abstraction than provided by mainstream technologies like Spring or Jakarta EE. The tool should hide the unnecessary details and save from writing repetitive code, since such applications usually contain a lot of repetitive elements: very similar to each other entities, attributes, UI fields, screens, etc. But the abstraction level must not be too high, to allow developers to express business logic in a familiar programming language and use modern powerful development tools from IDE and VCS to testing frameworks and CI/CD.
The Jmix goal is to provide adequate abstraction for the development of the aforementioned class of applications.
Below, we describe the principles that Jmix is based on.
Full-Stack Development
Jmix offers a full-stack development approach, which has two main aspects:
-
Using the single programming language and development paradigm. A backend developer can create a business feature on the full stack from the database schema to UI, while writing plain synchronous Java (or Kotlin) code. No need to have expertise in frontend technologies based on JavaScript.
-
The API is optional. A Jmix web application with the user interface can perfectly function without exposing any API endpoints that introduce complexity and security risks.
These aspects should actually be attributed to the Vaadin framework which is used by Jmix under the hood. Vaadin provides a rich set of UI components each of which has a client part and a server part. The client part is written in JavaScript and runs in the browser, the server part is written in Java and runs on the server. Users interact with the client part of the components, while the server part directly works with the application Java code.
So the application developers don’t need to create API for the frontend and don’t write the frontend code. They just interact with the server parts of Vaadin components.
If you are new to this concept, we recommend reading the article in our blog post: Simplicity & Focus Through Server-Driven Web UI Development.
A single programming language and development paradigm allow backend developers to create whole business features instead of just backend parts and APIs. This approach dramatically improves the productivity of a team and enables building a solution without the need for frontend development investments.
The fact that the UI can function without the need to create a special API saves a lot of time for designing, developing, documenting and maintaining the API endpoints. It is also inherently more secure, because the application sends to the browser only data that are really displayed on the user’s screen. There is no risk of extra data being inadvertently exposed to JavaScript in the browser, and there is much less surface area for security vulnerabilities.
The flip side of this approach is that the abstraction over the frontend makes it more difficult to customize UI or create own UI components. It’s of course possible, but generally harder than when using frontend frameworks directly. Also, with the Vaadin server-side state model, each user session requires a certain amount of memory on the server, which limits vertical scalability (however, the application can be scaled horizontally by adding more servers to the cluster).
So, the Jmix and Vaadin approach to full-stack development provides more value if the functionality of existing UI components is mostly sufficient for implementing a solution, and deep customizations are needed only in certain parts of the application UI. Another condition is that the number of concurrent (working at the same time) users is predictable and fits within the total memory available on the servers. Both conditions are usually true for enterprise applications that Jmix is targeted for.
In the context of full-stack development, it is also important to discuss the topic of monolithic and microservices architectures.
Solutions built on microservices often feature a frontend that is loosely coupled with the backend. This contrasts with the full-stack development approach, where the user interface directly interacts with the business logic.
But this doesn’t mean that full-stack development works only for monoliths. You can take the best of both worlds if you split a large application into a number of cooperating monoliths, each with its own database and UI.
Jmix is well suited for building modular monoliths of any granularity and size.
Modularity is achieved by creating custom add-ons and developing composite projects in Studio, which allows for flexibility in dividing the codebase.
Integration of self-contained application services into a complete information system is supported by the OpenID Connect and Generic REST add-ons, as well as by the fact that Jmix is fully compatible with any asynchronous communication solution.
Unified Data Model
Jmix allows developers to represent heterogeneous data in a single unified model and use it directly in the persistence, UI and business logic. There is no need to create layers of data transfer objects (DTOs) and mappers between the persistence and presentation models.
Below, we will compare the conventional architecture of Java enterprise applications with the unified data model approach and define the boundaries within which the latter is more appropriate.
The common approach in the modern enterprise applications development is to have separate data models for persistence and for presentation and business logic. In other words, you usually have a layer of JPA (Jakarta Persistence API) entities mapped to your database tables and a separate layer of Data Transfer Objects (DTOs) to pass them to/from the frontend through REST controllers (or using GraphQL or other API technologies). In the traditional JavaScript SPA frontend, you also have the same DTOs represented in JSON.
This architecture gives you great flexibility: you can change persistence and presentation models independently, you can convert data to the most convenient structure for storage and UI, and you can exclude certain data from exposure through the API for security reasons. The flip side is that you need to repeat a lot of classes and attributes, and write mappers from one model to another and back.
The separation of the persistence and presentation data models is certainly justified in an application with few entities and a fancy UI structured very differently from the ER-model of the stored data.
But in many enterprise applications the situation is quite opposite: data should be represented in UI in the same structure as they are stored in the database. Taking into account also the size of the data model in such applications (usually tens or hundreds of entities), the separation of models in this case may be unreasonably expensive.
The above-mentioned security reasons for creating separate models are irrelevant to Jmix applications, because the API is not required for building the user interface. And you can easily restrict data exposed to users: you just don’t create UI controls for certain entity attributes and these attributes never leave the backend.
So the basic approach in Jmix applications is to work with the single data model in all layers: persistence, business logic and UI. For most cases it means using JPA entities and their attributes mapped to database fields. But Jmix doesn’t limit you with just the persistence model and supports also the following scenarios:
-
Using calculated values implemented by transient attributes of JPA entities.
-
Working with data sources different from relational databases. In this case, the model is defined by Plain Old Java Objects (POJOs) mapped to external APIs or non-relational databases.
-
For sophisticated parts of UI, using presentation POJOs that are structured differently from the persistence model.
With Jmix, all these requirements can be implemented within the single data model. That is, instead of stacking different models on top of each other, you can expand the main JPA persistence model by adding non-JPA items to it.
In applications that display data mostly in the same structure as they are stored, this approach brings obvious benefits: you don’t duplicate the whole model on different layers and don’t write boilerplate code for maintaining this duplication. Instead, you can extend the underlying persistence model with required elements only when they are needed.
To better understand how Jmix provides a unified data model containing different elements, and what you can do with this model, refer to the Data Model and Metadata section.
Ready-Made Solutions
Jmix provides ready-made solutions to common tasks in enterprise applications. They range from sophisticated UI components for working with data to full-stack features like report generation and business process management.
This category also includes high-level abstractions and declarative approach for UI building, data access and security. You can find an overview of these features in the next section.
Jmix is focused on a specific area of development - enterprise applications, and compared to general-purpose frameworks such as Spring or Django, it provides more suitable ready-made solutions for this class of applications.
These solutions, practices and presets serve as starting points, lower the entry barrier and speed up the development of applications.
Using Mainstream Technologies
Jmix is built on top of mainstream technologies (Java, Spring, JPA) and tends to not reinvent the wheel. It applies a particular opinionated structure and pre-configuration to the underlying technologies, while remaining fundamentally open.
There are no restrictions on bypassing Jmix abstractions and working directly with underlying technologies when needed.
From the tooling and methodology perspective, developers can use industry best practices such as testing frameworks, static code analysis, CI/CD and version control systems.
Extensibility
Jmix is built with extensibility in mind. If something in the framework doesn’t meet your requirements, it can be extended or replaced by a custom solution.
Also, the extensibility features built into the Jmix framework allow for creating products that can be customized for a particular industry or customer without modification of the original product.
The Modularity and Extension section describes the Jmix extensibility features in detail.