CUBA development - a big step away from Spring?



    When you read the requirements for the next corporate web application for internal use, then usually (judging by experience) it is the same set: a relational database for storing data, often inherited from the previous version of the application, a large number of forms of different levels of complexity (but at the same time typical) for data entry, a variety of reporting forms, complex business logic, integration with other applications - from accounting to supply management, several thousand concurrent users. What usually comes to mind?

    “So, I’ll take a DBMS that I know and which will fit my data volume, screw Hibernate / JPA, write the application to Spring Boot, set the REST API and write the client on the JS framework, most likely Angular / React”.

    “Yeah, I have to screw Spring Security. And write a restriction on data access for different departments and roles - at the level of database lines or data objects. How to do it? Representations or VPD, it will be necessary to look ".

    “Uh, it will be necessary to write a bunch of DAO - they are done quickly, but there are many of them.”

    “And conversion from Entity to DTO - I will use ModelMapper ”.

    “The main thing is not to forget to remind the trainee about lazy attributes and joins, so that it would not be like last time.”

    “Fir-tree sticks, while you start business logic, you need to write as much official code ...”

    This article is for those who have written at least a couple of corporate applications from scratch on Spring / Spring Boot and now thinks that it would be nice to somehow speed up the development of such different, but at the same time similar applications. Next, we will look at how to get rid of “typical” tasks using the CUBA Platform .

    Another framework?




    Thought number one, when a developer is offered a new framework (and, in particular, CUBA), this is: “Why should I bother with this? I will take the familiar and familiar Spring Boot and I will sip it all on ”. And this is reasonable. A new framework is the study of new approaches to development, new pitfalls and limitations that you have learned to deftly avoid when developing in a familiar framework.

    But when I started developing at CUBA, I didn’t have to change much of my skills with Spring. Naturally, I had to spend some time understanding the platform, but it was not a fundamental breakdown of all habits, but rather a slight shift in development skills.
    As a result, the code for DTO, paginated data output, data filtering (analysis of parameters transmitted in the form and making queries) disappeared. At the same time, I almost did not have to poke around with the Spring Security settings and write the admin code, login forms, and logic for switching the user interface language.

    Let's start from the very beginning and see how development on CUBA relates to the usual way of developing on Spring and how, using your experience and studying a few new things, you can, ultimately, create applications faster.

    The main focus of the article is on the development of the server side in order not to lose focus and keep the amount of text at an acceptable level.

    Spring Application Architecture


    In 90% of cases, typing in Google “Spring Application Architecture” or “architecture of applications Spring”, you will see a similar picture. Classic three-layer application with modules common to some layers.



    Domain Model (Domain Model) - classes-entities domain (Entities), stored, as a rule, in the database. Classes are usually created manually, but you can build a structure automatically, based on the database schema.

    Repository Layer (Repository Layer)- a set of classes that provide work with the data warehouse. Typically, this layer uses various ORM frameworks and contains logic to perform CRUD operations. If we talk about Spring, then the repositories are quite compact, mainly due to JPA Query methods, but often you have to write the logic of the sample from the database and map to the domain model manually.

    Service Layer (Service Layer) - an application layer that contains the implementation of business logic, information processing algorithms that are specific to the subject area. This is useful in the case of complex processing algorithms, as well as for working with data from different sources (databases, external applications, services from the Internet, etc.).

    Web / Controllers Layer (Controller Layer)- classes responsible for the REST API. There are also page template files on this layer if we use a framework like Thymeleaf, Velocity, as well as classes that are responsible for drawing and handling user interface events, if something like GWT, Vaadin, Wicket, etc. is used. Usually, controllers work with DTO, and not with classes from the domain layer, so functionality is added to the application for converting DTO to Entity and back.
    If all of the above for you is obvious or even “next captaincy” - this is great. So you can start working with CUBA without problems.

    Reference Application - Pet Clinic


    Let's look at a specific example and write some code. For Spring there is a “reference” application - Pet Clinic on GitHub . This application is created in different versions using different tools - from classic Spring to Kotlin and Angular. Next we look at how you can make this application on CUBA. For those who are not familiar with the Spring-version, there is a good text here ; This article will use excerpts from it.

    Data model




    The ER diagram is shown in the figure above. The domain model replicates this structure, several classes with common fields have been added to it, and entity classes have already been inherited from them. UML can be found in the presentation I mentioned earlier.

    Repository layer


    Attached are four repositories that are responsible for working with the Owner (Owner), Pet (Pet), Visit (Visit) and Vet (Vet) entities. Repositories are written using Spring JPA and contain almost no code, only method declarations. However, a query has been added to the repository that works with the Owner entity, which allows extracting owners and their pets from the database in one sample.

    User interface


    Pet Clinic has nine pages that allow you to view the list of owners, their pets, and a list of veterinarians. The application provides simple CRUD functionality: you can edit some of the data - owners, pets, and you can add visits to the clinic. But, as already mentioned, we will not discuss in depth the user interface in this article.

    Additionally


    In addition to the code for simple manipulations with entities, the application has interesting functionality, which is designed to show the capabilities of Spring:

    • Caching - the list of veterinarians is selected from the database only once, then stored in the cache until the application server is restarted.
    • Check for required fields when entering information about a new pet.
    • Format the type of animal before displaying.
    • i18n - the application supports English and German.
    • Transaction Management - some transactions are marked as “read only”.

    Margin notes


    I really like this picture. It 100% reflects my feelings while working with frameworks. To effectively use the framework, it is necessary to understand how it is arranged inside there (no matter what anyone says). For example, how many of you wondered how many classes you need to make the JPA interface work?
    Even in such a small application as the Pet Clinic, there is a bit of Spring Boot magic:

    • There is no configuration for the cache (except for the annotation @Caсheable), but the Spring Boot “knows” how to start the necessary cache (EhCache in this case).
    • CRUD Repositories are not annotated @Transactional(and their parent class org.springframework.data.repository.Repositorytoo), but all methods save()work as they should.

    But despite all the “implicitness”, Spring Boot is very popular. Why? It is transparent and predictable. Good documentation and open source code allow you to understand the principles and, if necessary, delve into the details of implementation. It seems to me that everyone loves such frameworks, transparency and predictability - the key to the stability and support of the application.

    Pet Clinic on the CUBA platform


    Well, let's look at the Pet Clinic, which was done using CUBA, from the Spring Developer’s point of view and try to figure out where to save.

    The source code of the application can be found on GitHub . In addition, the CUBA Platform has very good documentation in Russian and English, which explains in detail how to properly develop on this platform. Many examples on GitHub , including several tutorials. In the article I will often refer to the documentation in order not to write twice the same thing.

    CUBA Application Architecture


    The CUBA application consists of the modules shown in the diagram.



    Global (global module) - contains entity classes, CUBA representations and service interfaces that are used in different modules.

    Core (services module) - here are placed the code of services that implement the business logic, as well as the code to work with the data warehouse. It should be noted that these classes are not available from other application modules; this is done in order to provide separate deployment for better scalability. In order to use services in other application modules, you need to use the interfaces declared in the global module.

    GUI, Web, Desktop, Portal- in these modules is placed the code of the classes related to the processing of user interface events, as well as additional REST controllers, if the built-in REST API CUBA is not enough.

    To save developer time, CUBA has a studio — a small graphical development environment that helps to do routine work, such as generating entities, writing services to configuration files, etc. using a graphical interface. To generate the interface of the developed application, there is (almost) a WYSIWYG editor.

    Thus, an application based on the CUBA Platform consists of two main modules - Core and GUI, which can be deployed separately, as well as a common module - Global. Let's consider the device of these modules in more detail.

    Global module


    Entity model


    Entity modeling in the CUBA application is no different from what Spring developers are used to. Domain classes are created and annotations are put on them @Table, @Entityetc. These classes are then registered in the file persistence.xml.

    When writing Pet Clinic, I just copied the classes from the original Spring application and changed them a bit. Here are a couple of small additions that you should know about if you write on the CUBA platform:

    1. CUBA introduces the concept of a “ namespace ” for each component of an application in order to eliminate duplication of table names in the database. That is why the “petclinic $” prefix was added to each entity.
    2. It is recommended to use annotation @NamePattern- an analogue of the method toString()for the readable display of entities in the user interface.

    A logical question: “What else does CUBA add except for prefixes and declarative ones toString()?” Here is a partial list of additional features:

    1. Base classes with autogeneration ID from Integer to UUIDs.
    2. Useful marker interfaces that provide additional features:
      • Versioned - to support versioning of entity instances.
      • SoftDelete - to support the “logical” deletion of records in the database.
      • Updatable - added fields to register the fact of updating the record, user name and time.
      • Creatable - added fields to register the creation of the record.

      More details about entity modeling can be found in the documentation .
    3. Scripts for creating and updating the database are generated automatically using CUBA Studio.

    Thus, the creation of a data model for the Pet Clinic has been reduced to copying classes of entities and adding to them the CUBA-specific things that I mentioned above.

    Representation


    The concept of “representations” in CUBA may seem somewhat unusual, but it is explained quite easily. A view is a declarative way of declaring attributes whose values ​​need to be retrieved from the data store.

    For example, you need to extract the owners and their pets from the database (or veterinarians and their professions) - a very common task when creating an interface, when you need to show dependent data on the same form as the main data. In Spring, this can be done through JPA join ...

    @Query("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id")
    public Owner findById(@Param("id")int id);

    ... or specify the EAGER / LAZY attributes to retrieve the collection of the main entity in the context of a single transaction.

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"), 
    inverseJoinColumns = @JoinColumn(name = "specialty_id"))
    private Set<Specialty> specialties;

    In CUBA, you can do this through EntityManager and JPQL (everyone knows how well) or through the view and DataManager:

    1. Create a presentation (can be done in CUBA Studio or manually in the configuration)

      <viewclass="com.haulmont.petclinic.entity.Vet"extends="_minimal"name="vet-specialities-view"><propertyname="specialities"view="_minimal"></property></view>
    2. And use DataManager to fetch:
      public Collection<Vet> findAll(){
         return dataManager.load(Vet.class)
                 .query("select v from cubapetclinic$Vet v")
                 .view("vet-specialities-view")
                 .list();
      }
      

    You can create different views for different tasks with the necessary set of attributes and nesting levels of entities. There is an excellent article about the presentation in the blog of Mario David.

    For the Pet Clinic app, six different submissions were made. Most of them were generated “semi-automatically” when creating the user interface, and the view described above was implemented for the data export service.

    Service Interfaces


    Since the global module is used by all other modules of the application, the interfaces of the services are declared in it, so that later it can be used in other modules through the dependency injection (DI) mechanism.

    Additionally, you need to register the services in a file web-spring.xmlin the Web module. During context initialization, CUBA will create proxy classes for serialization and deserialization of classes when interacting with services in the Core module. This just provides a separate deployment of modules Core and Web, while the developer does not need to make additional efforts, everything is done transparently.

    So: when creating entity classes in CUBA, the same amount of time is spent as in pure Spring (if you do not use CUBA Studio), but you don’t have to do base classes to generate primary keys. You also do not need to write code to support the entity version field, logical deletion, and auditing. Also, in my opinion, views can save some time on debugging JPA join and manipulating EAGER / LAZY samples.

    Core Module


    This module hosts the interface implementations declared in the global module. Each service in the CUBA application is annotated @Service; you can use other Spring annotations, but you need to consider the following:

    • If you want the service to be available in other modules, it is necessary to put an annotation @Service.
    • It is recommended to assign a name to the service to avoid duplication, if a component that implements the same interface appears in the application.
    • Data sampling is done a little differently than in Spring, about this in the next section.

    The rest of the Core module is plain Spring code. You can select data from the database, you can call external web services, in general, write code like you used to.

    Entity Manager and DataManager


    The CUBA platform uses its own EntityManager , which delegates some of the calls to the usual javax.persistence.EntityManager, but does not implement this interface. EntityManager provides mainly low-level operations and does not fully support the CUBA security model. The main class for working with data is DataManager which provides the following functionality:

    • Access control at the row and attribute level.
    • Using views when fetching data.
    • Dynamic attributes.

    More about DataManager and EntityManager is written in the documentation . There is no need to explicitly work with these classes to fetch data into user interface components (tables, etc.), the GUI uses data sources (Datasources) .

    If we talk about PetClinic, there is almost no code in the Core module, there is no complex business logic in this application.

    Additional functionality from Pet Clinic to CUBA


    In the previous section, additional functionality was considered in the reference application. Since CUBA uses Spring, the same functionality is available when developing on the basis of this platform, but we will have to do without some of the magic of Spring Boot. In addition to this, CUBA provides similar out-of-box functionality.

    Caching


    The CUBA platform has a cache of requests and an entity cache. They are described in detail in the documentation and can be considered as priority decisions if you want to use caching in the application. Embedded solutions support distributed application deployment and clustering. And, of course, you can use the annotation @Cacheable, as described in the documentation on Spring , if the built-in caching is not satisfied with something.

    Input Validation


    CUBA uses BeanValidation to validate entered data. If the built-in classes do not provide the necessary functionality, you can write your own validation logic . And, in addition to this, CUBA provides classes Validatorthat are described here .

    Output formatting


    The CUBA platform provides several formatters for user interface components; you can also make your own in addition to the standard ones. You can use annotation to represent entity instances as strings.@NamePattern

    i18n


    CUBA supports output in different languages using files message.properties, nothing new here. CUBA Studio allows you to create and edit such files quickly and easily.

    Transaction management


    The following types of transaction management are supported:

    • All familiar to Spring abstract @Transactional,
    • Interface (and class) Persistenceif you need transaction management at a low level.

    When I wrote Pet Clinic, I only needed transaction management in one place: when I was developing an input form that allowed editing several related entities on one screen. It was necessary to edit the owners and their pets, as well as add visits to the clinic. It was necessary to carefully save the data and update it on other screens.

    Pet Clinic for a few hours. Realistically


    I made a copy of the Pet Clinic with a standard CUBA interface for six hours. Not to say that I am an expert at CUBA (it took a couple of weeks since I started working at Haulmont), but I have experience with Spring, and he helped me a lot.

    Let's look at the CUBA application from the point of view of the classical architecture:

    The data model is the entity classes in the Global module. Creating a model is a well-known and familiar procedure. Thanks to the BaseIntegerIdEntity class for saving time, which is usually spent on fussing with ID generation.

    The repository layer is not needed. I created several submissions, and that's it. Of course, CUBA Studio saved me some time, I did not have to manually write XML files.

    Service layer- There are only two services in the application for exporting data to JSON and XML. In the current version of the application on Spring Boot, this feature was removed, by the way. Although it did not work for JSON. In the CUBA version, I declared the interfaces in the global module and placed the implementation in Core. Nothing new, except DataManager, but it took very little time to master it.

    Controller layer - there is only one REST controller in CUBA Pet Clinic, for export to JSON and XML. I put this controller in the Web module. Again, nothing special, the same annotations, the usual Spring controller.

    User interface- to make standard CRUD forms, and even with CUBA Studio, did not cause any difficulties. No need to write code to transfer data to the components, no parsing of data from the data filtering form, no messing with paginated output. There are components for all this. Time spent on making the interface look like the one made in the Spring Boot version. Vaadin is still not pure HTML, and it was harder to style it.

    Personal experience tabulated:
    Easy to understand easy to doNeed to read the documentation
    EntitiesCreating an object model
    Generating database scripts
    Base classes for entities
    Additional features for working with data
    RepositoriesEntityManager
    Views
    DataManager
    ServicesManage Beans
    Manage Transactions
    Manage Users
    Interface (and class) Persistence
    ControllersOwn REST controllers
    Standard REST URL
    Publication of services
    Interface
    Standard forms of working with data
    Own styles and components

    Of course, Pet Clinic does not use all the features of CUBA, a full list of platform features can be found on the site , and you can also find code examples for solving typical tasks that arise during the development of corporate applications.

    My personal opinion is that CUBA simplifies the development of the server-side of the application and helps save even more time on developing the user interface if you use standard user components and styling capabilities. But, even if you need some special user interface, it will still be a gain in time due to the standard server side.  

    Some advantages! Are there any cons?


    Of course, there are no perfect frameworks. They are not critical, but at first, when I first started working with CUBA, there was some discomfort. But the magnitude of WTF / m was not beyond.

    • For the CUBA platform, there is an IDE that simplifies the initial creation of a project. Switching between studio and IDEA is a bit annoying at first. The good news is that there is a beta version of CLI, you do not need to run a studio to generate the project structure, and the next version of CUBA Studio will be a Intellij IDEA plugin. No more switching.
    • There are more XML files in CUBA than in the average Spring Boot application, this is done because context initialization in CUBA is done in its own way. Now we are struggling to reduce the number of XML, go to the annotations, where possible.  
    • There are no “readable” URLs for user interface forms. It is possible to access forms through links to screens , but they are not very user friendly.
    • You need to use DataManager, views and EntityManager, not Spring JPA or JDBC to work with the data (but these APIs are also available if needed).
    • Best of all, CUBA works with relational databases as data storage. As for NoSQL, you will have to use the access libraries to these repositories and write your own repository layer. But this is the same amount of work as when developing an application without CUBA, in my opinion.

    Total


    If there is a task to develop an application that uses a relational database as a data warehouse and is focused on working with data in a tabular format, then CUBA may be a good choice because:

    1. CUBA is transparent. Source code is available, you can debug any method.
    2. CUBA is extensible (up to certain limits, naturally). You can inherit almost any service class and slip it to the platform, make your own REST API, use your favorite framework for the user interface. CUBA was created so that you can easily adapt solutions for any customer. There is a good article about the extensibility of the platform.
    3. CUBA is Spring. 80% of your server code is just a Spring application.
    4. Fast start. You will have a full-fledged application with admin panel after creating the first entity and the screen for working with it.
    5. Many routine tasks have already been solved in the platform.

    So, with CUBA, you can save time on writing monotonous "utility" code and focus on writing code to solve business problems. And yes, at Haulmont we use CUBA ourselves in the development of both boxed and custom products.  


    Also popular now: