Skip to content

guide coding conventions

devonfw-core edited this page Jul 22, 2021 · 1 revision

devon4quarkus coding conventions

This guide describe the conventions for naming and structure in a devon4quarkus application. In addition to the points mentioned here, the code should follow the general Java conventions (see Oracle Naming Conventions, Google Java Style, etc.).

Things to discuss

Structure

Packages

For a devon4quarkus-based application, we recommend using the following Java package scheme:

«root».«component».«layer»[.«detail»]*

See also existing devon4j packaging that we want to simplify and modernize here.

Table 1. Segments of package schema
Segment Description Example

«root»

The root package. Typically we suggest to use «group».«artifact» for «root». However, we will not enforce anything and let you the freedom of choice if the recommendation does not fit for you.

com.devonfw

«group»

Matches your maven groupId coordinate, basic name-space of the organization or IT project owning the code. Corresponds to domain name reversed.

com.devonfw

«artifact»

Matches your maven artifact coordinate, converted to java package conventions(e.g. - omitted). Can be further simplified if it does not cause disambiguity(e.g. presales-order-bffpobff)

orderservice, usermgmt..

«component»

Only used if the service serves multiple business components. Most microservices usually address a single business component/domain. In this case it is ommited(its already implied by the artifactid)

user, order

«layer»

The name of the technical layer (See technical architecture) which is one of the predefined layers (domain, rest, logic) or common for code not assigned to a technical layer (datatypes, cross-cutting concerns). Additional layers can be introduced if they have clear scope e.g. batch, process..

rest

«detail»

You will technically have the freedom of choice to define your sub-packages. Compared to devon4j we neither enforce nor recommend anymore to use the «scope» segment in your packaging. You are still free to do so if you like it. However, we now suggest the «type» segment for furhter classification within «detail».

dao

«type»

Further division based on common stereotypes based on type of component. Suggested stereotypes for rest layer are [controller, model, mapper, filter..] for domain layer: [model, dao]

dao

For a typical backend microservice that provides HTTP API and data persistence via JPA in the business domain serviceorder, the structure would be something like this:

«group».«artifact»
├──.domain
|  ├──.dao
|  |  ├──ServiceOrderDAO
|  |  └──ServiceOrderItemDAO
|  ├──.model
|  |  ├──ServiceOrderEntity
|  |  └──ServiceOrderItemEntity
├──.logic
|  ├──NewServiceOrderValidator
|  └──ServiceOrderEventsEmitter
└──.rest
   ├──.controller
   |  └──ServiceOrderRestController
   ├──.mapper
   |  └──ServiceOrderMapper
   └──.model
      ├──NewServiceOrderDTO
      ├──ServiceOrderPageResutltDTO
      └──ServiceOrderDTO

Layer

Data access layer

When using JPA/Hibernate for data persistence, please use the following subpackages under your domain package:

  • dao: For the Data Access Objects (DAOs). The naming should be always «entity»DAO

  • repo: For repositories, if you use Spring Data for data access

  • model: For all entities, views or other objects used to read and write to DB.

Logic layer

Use the layer to provide any microservice-specific business logic and add sub-packages as needed, depending on the type and number of classes required.

Before introducing a new service, check whether it is really needed or whether it can be replaced by a standard/framework solution (e.g. validators can be covered by the bean validation specification in 90% of cases by using annotations on models). Strive for clear naming, based on the scope of the class, instead of generic names. BAD: OrderService, EmailManagement, BETTER: OrderValidator, EmailSender

REST layer

Depending on the requirements of the project, a service may provide several APIs, e.g. a fixed version, a public API that must remain strictly backward compatible, and a separate non-public API used for internal functions or operations. Often the app needs to provide multiple public API versions. If this is the case, we suggest to introduce «version» as an intermediate package:

└──.rest
   ├──internal
   |  ├──.controller
   |  |  ├──AdminOperationsRestController
   |  |  └──EventRestController
   |  ├──.mapper
   |  |  └──AdminOperationMapper
   |  └──.model
   |     ├──EventDTO
   |     ├──AdminOperationDTO
   |     └──AdminOperationResultDTO
   ├──v1
   |  ├──.controller
   |  |  └──ServiceOrderRestController
   |  ├──.mapper
   |  |  └──ServiceOrderMapper
   |  └──.model
   |     ├──NewServiceOrderDTO
   |     ├──ServiceOrderPageResutltDTO
   |     └──ServiceOrderDTO
   └──v2
      ├──.controller
      |  ├──ServiceOrderItemRestController
      |  └──ServiceOrderRestController
      ├──.mapper
      |  └──ServiceOrderMapper
      ├──.filter
      |   └──CustomPayloadFilter
      └──.model
         ├──NewServiceOrderDTO
         ├──ServiceOrderItemDTO
         ├──ServiceOrderPageResutltDTO
         ├──ServiceOrderPatchRequestDTO
         └──ServiceOrderDTO

Comparison with devon4j

  • service.[api|impl].[rest|ws] simply becomes rest, ws (in case someone is still using legacy SOAP), grpc, etc. Technically we can still derive that this all implies the service layer.

  • dataaccess becomes domain. You are not forced to follow this and architcture validation such as our sonar-devon4j-plugin will in the future support both. However, new CobiGen templates for quarkus/cloud-native will use this new default and would need to adopt them if you want to change. We also suggest to put entities in the model sub-package (see «type»).

  • logic remains logic

Naming conventions

In addition to the general Java naming conventions, the following rules should be observed

  • Names should be descriptive and concise. Always use short but speaking names (for types, methods, fields, parameters, variables, constants, etc.).

  • Name should indicate the type of object it represents.

  • Strictly avoid special characters in technical names (for files, types, fields, methods, properties, variables, database tables, columns, constraints, etc.). In other words only use Latin alpahnumeric ASCII characters with the common allowed technical separators for the accordign context (e.g. underscore) for technical names (even excluding whitespaces).

  • For package segments and type names prefer singular forms (CustomerEntity instead of CustomersEntity). Only use plural forms when there is no singular or it is really semantically required (e.g. for a container that contains multiple of such objects).

  • Avoid having duplicate type names. The name of a class, interface, enum or annotation should be unique within your project unless this is intentionally desired in a special and reasonable situation.

  • All classes in single «type» package should have the same naming structure (e.g. dont mix EntityRepo and OtherEntityDAO inside dao package).

  • Avoid artificial naming constructs such as prefixes (I*) or suffixes (*IF) for interfaces.

  • Avoid property/field names where the second character is upper-case at all (e.g. 'aBc').

  • Names of Generics should be easy to understand. Where suitable follow the common rule E=Element, T=Type, K=Key, V=Value but feel free to use longer names for more specific cases such as ID, DTO or ENTITY. The capitalized naming helps to distinguish a generic type from a regular class.