This site uses cookies. By continuing to browse the site you are agreeing to our use of cookies.
X

Easy start for powerful MicroServices

I've been always interested in software architecture which enables continuous delivery and deployment of large, complex applications.

The age of monolithic applications has ceased. Modern software development organizations work in autonomous teams, to deliver and run multiple independent / decoupled applications in parallel. These may be developed using different coding approaches or programming languages and Technology stacks. MicroServices certainly are not a panacea, but they’re a scalable solution if you have the right problem.

One of the strongest advantages of developing MicroServices is the time required to implement the first working prototype. Time is always crucial for commercial software development, that is why both sides of this process - developers and managers - highly appreciate it. In the Technology industry speed of development and delivery of new applications and components is a differentiating factor between you and your competitors. For the last 5 years, I've been working on financial software development where milliseconds matter. That is why I am used to double-checking everything that is supposed to go into production.

When I joined the E&V Technology team I started my new journey into the world of microservices and distributed architectures.

If the amount of microservices is increasing, developers need something which will allow them to focus primarily on the domain and business logic instead of inventing the same code again and again.

We have developed a so-called "quick start" for every new Java-based backend service.

The solution is based on the Maven Archetype workflow. In just a few simple steps it will generate a cloud-ready application with many useful features described below.

The start-up set for each microservices consists of:

  • SpringBoot support

  • JPA entities and repositories

  • basic CRUD services

  • ready for use JAX-RS endpoints which are tightly connected with repositories (or SpringMVC)

  • self-describing REST endpoint with Swagger

  • powerful data revisions based on Hibernate Envers

  • Protobuf support

  • Docker support

  • Jenkins CI/CD support

  • Kubernetes deployment support

The following example command does the whole trick:

mvn archetype:generate \

-DserviceName="Some Cool Service" \

-DgroupId=de.ev.microservices \

-DartifactId=some-cool-service \

-Dversion=1.0-SNAPSHOT \

-DpackageName=de.ev.microservices \

-DarchetypeGroupId=de.ev.archetypes \

-DarchetypeArtifactId=MicroServiceSpringBootStack \

-DarchetypeVersion=1.0-SNAPSHOT \

-Dentities=User,Shop \

-DdatabaseInstanceName=gcp-main-dev:europe-west1:sql---main---postgres01-temp

and the output will be ready Gradle project which you can run immediately on the local machine or deploy the application directly to Kubernetes cluster from command line.

Let's see what hides behind the scene. Our Java MicroService archetype has 10 important features. Actually, they form a very good start for new solid MicroService among others in our ecosystem.

1. SpringBoot stack

This popular framework in Spring ecosystem is a backbone of our application. SpringBoot allows creating a production-ready application from scratch. It also has a brilliant support of multilayer architecture which is easy to test and support - an indispensable feature during the whole lifecycle of a MicroService.

2. Basic Hibernate DAO layer

For all provided entities JPA classes are generated:

@Audited
@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "SHOP")
@JsonInclude(NON_NULL)
public class Shop extends BaseEntity {

}

with the common mapped superclass

@MappedSuperclass
@Data
@NoArgsConstructor
@EqualsAndHashCode(of = {"id", "name"})
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class BaseEntity {

    @Id
    @GeneratedValue(generator = "uuid2")
    @GenericGenerator(name = "uuid2", strategy = "uuid2")
    @Column(name = "id")
    protected UUID id;

    @Column(name = "name")
    protected String name;

}

3. Spring data repositories

Also, we generate CRUD repositories for every specified entity. It's pretty enough to get started with basic persistence.

import de.ev.microservice.entities.Shop;

public interface ShopDao extends EntityRepository<Shop> {
}

4. Business level

How often did you face the situation when you need to write basic CRUD operation or even repositories once more? To cater for this, all of our new Java-MicroServices already have all the minimal business logic, letting the developer concentrate on the domain.

@Service
public class ShopService {

    private final ShopDao shopDao;

    @Inject
    public ShopService(ShopDao shopDao) {
        this.shopDao = shopDao;
    }

    public UUID createShop(Shop example) {
        shopDao.save(example);
        return example.getId();
    }

    public void deleteShop(UUID id) {
        shopDao.deleteById(id);
    }

    public void updateShop(Shop example, UUID id) {
        Shop entity = shopDao.findOneOrThrow(id);
        entity.setName(example.getName());
        shopDao.save(entity);
    }

    public Stream<Shop> listShops() {
        return StreamSupport.stream(shopDao.findAll().spliterator(), false);
    }

    public Shop getShop(UUID uuid) {
        return shopDao.findOneOrThrow(uuid);
    }

    public void deleteAll() {
        shopDao.deleteAll();
    }

}

5. JAX-RS and Jersey

The minimal boilerplate code needed for configuring and setting up resources and filters.

6. Swagger definitions for self-documenting and more transparent testing

    @GET
    @Operation(
            tags = {"Shop", "Get one"},
            summary = "Get shop",
            parameters = {
                    @Parameter(
                            name = "id",
                            in = "path",
                            description = "The ID of required Shop",
                            required = true
                    )
            },
            responses = {
                    @ApiResponse(
                            description = "Shop with specified ID",
                            responseCode = "200",
                            content = {@Content(mediaType = "application/json")}
                    ),
                    @ApiResponse(
                            description = "Entity ID should not be null",
                            responseCode = "400",
                            content = {@Content(mediaType = "text/plain")}
                    ),
                    @ApiResponse(
                            description = "Not found for ID",
                            responseCode = "404",
                            content = {@Content(mediaType = "text/plain")}
                    )
            }
    )
    @Path("{id}")
    @Produces(APPLICATION_JSON)
    public Shop getShop(@PathParam("id") String id) {
        return shopService.getShop(orNull(id));
    }

7. Out-of-box data revisions and auditing with Hibernate Envers

You'll never miss data by spontaneous deletion. In general, direct data deletion is not a recommended practice. Moreover, it can cause serious problems for integrity in the distributed systems. Using the comprehensive auditing feature will log who changed what and when. We provide each generated entity with the corresponding documented endpoint for testing and future use.

    @GET

    @Operation(

            tags = {"Shop", "Revisions"},

            summary = "List revisions of given Shop",

            description = "Find Shop's revisions based on it's ID and/or date. If just ID specified, the result will contain revisions for all dates.",

            parameters = {

                    @Parameter(

                            name = "id",

                            in = "path",

                            description = "The ID of required Shop",

                            required = true

                    ),

                    @Parameter(

                            name = "date",

                            in = "query",

                            description = "Date in format yyyy-MM-dd"

                    ),

                    @Parameter(

                            name = "includeDeleted",

                            in = "query",

                            description = "Show deleted Shops or not in search"

                    )

            },

            responses = {

                    @ApiResponse(

                            description = "The list of shop's revisions",

                            responseCode = "200",

                            content = {@Content(mediaType = "application/json")}

                    )

            }

    )

    @Path("{id}")

    @Produces(APPLICATION_JSON)

    public List<EntityRevision<? extends BaseEntity>> listShopRevisions(@PathParam("id") String id,

                                                                        @QueryParam("date") String date,

                                                                        @QueryParam("deleted") boolean includeDeleted) {

        return revisionsService

                .findRevisions(Shop.class,

                        UUIDUtils.orNull(id),

                        DateUtils.parseDate(date, true),

                        includeDeleted)

                .collect(toList());

    }

8. Basic Protobuf messages and Java-stubs generation support

The generated project already contains the minimum  of required messages like:

package protobuf;

option java_package = "de.ev.microservice.protobuf";
option java_outer_classname = "EntityProto";


message User {
    required string id = 1;
    required string name = 2;
}

message Shop {
    required string id = 1;
    required string name = 2;
}

which are eligible for use in the code.

9.  Docker-ready application

The project is also supplied with a Docker file which takes the built application and provides all the necessary environment variables and entry points.

10. Basic Kubernetes deployment description

Last but not least the project comes with an initial deployment description file. It contains the mandatory properties for the container. Some of the information is being generated from properties you have specified with the Maven Archetype command.

Conclusion

The importance of having such quick-start guides is hard to overestimate. Modern backend applications should be properly configured to fit the company standards. The final goal is to solve all the issues arriving at an early stage of new projects.

There are some additional features planned for the future, like Kubernetes service discovery initial codebase to give an ability for services to connect smoothly. Or whether it is reasonable to have only gRPC definitions and generate REST directly from them. However, this is more specific to a team’s situation and should therefore be discussed and decided case by case.

As you may have noticed, the archetype output is more than just a draft version of an upcoming MicroService - it also makes it possible to define and support a unified development culture across the team. I am firmly convinced that such arrangements help to build a strong and reliable "backbone" of the whole MicroServices ecosystem in the company.

Contact us now

Engel & Völkers Sintra
Email
Back
Contact
Enter your contact details here
Thank you for your request. We will contact you shortly.

Your Engel & Völkers Team
Salutation
  • Mr.
  • Mrs.

Privacy Policy​

Send now

We know the true value of your property

Do you know how much your property is currently worth? No matter if you just want to inform yourself about the current market-price, or if you wish to sell your property for the best price: our experienced marketing experts are happy to assist you with a free and non-binding valuation.
Send now
Back
Contact
Enter your contact details here
Thank you for your request. We will contact you shortly.

Your Engel & Völkers Team
Salutation
  • Mr.
  • Mrs.
Please enter the property information.

Privacy Policy​

Send now

Follow us on social media



Array
(
    [EUNDV] => Array
        (
            [67d842e2b887a402186a2820b1713d693dd854a5_csrf_offer-form] => MTM5MjE5NzU3NkJ4d29xancwTDVhZWFIRzEycXAxcW9SdElHdVBqMTdV
            [67d842e2b887a402186a2820b1713d693dd854a5_csrf_contact-form] => MTM5MjE5NzU3NnlHcUR0Y2VlTXVPUndLMHZkMW9zMnRmRlgxaUcwaFVG
        )

)