<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yegor Voronianskii</title>
    <description>The latest articles on DEV Community by Yegor Voronianskii (@vrnsky).</description>
    <link>https://dev.to/vrnsky</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F92763%2Fb1a3f692-70b1-4cc8-b6b2-97016d738d6e.jpeg</url>
      <title>DEV Community: Yegor Voronianskii</title>
      <link>https://dev.to/vrnsky</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vrnsky"/>
    <language>en</language>
    <item>
      <title>Spring Boot &amp; JOOQ | Getting started</title>
      <dc:creator>Yegor Voronianskii</dc:creator>
      <pubDate>Wed, 03 Jan 2024 11:37:31 +0000</pubDate>
      <link>https://dev.to/vrnsky/spring-boot-jooq-getting-started-2oho</link>
      <guid>https://dev.to/vrnsky/spring-boot-jooq-getting-started-2oho</guid>
      <description>&lt;p&gt;This article will show how to use jOOQ in your spring boot projects.&lt;/p&gt;

&lt;p&gt;Why do we need jOOQ? &lt;br&gt;
There is a lot of pain using JPA and Hibernate. That is why we have something jOOQ.&lt;/p&gt;

&lt;p&gt;First, we need to create a database schema. In this article, we will develop a simple CRUD (create, read, update, and delete) application to manage goods.&lt;/p&gt;

&lt;p&gt;The first step is to design our database. The application will contain only one table — goods. The table looks like below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwshgtydl1tse8126d45.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwshgtydl1tse8126d45.png" alt="ERD of database" width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This code of ERD above, I have created within Mermaid.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;erDiagram
    GOODS {
        id uuid pk "ID"
        name string "The name of good"
        price numeric "The price of good"
        total_count int "The total count of good"
        sold_count int "The sold count of good"
        deleted bool "The flag indicated that good was deleted"
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The next step is to create a Spring Boot Maven Project, but you can choose Gradle; it is up to you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjteqyxokiotzhy9tp17p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjteqyxokiotzhy9tp17p.png" alt="Creation of the project in IDE" width="798" height="713"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs8gjpvpf77nye93q27yq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs8gjpvpf77nye93q27yq.png" alt="List of all dependencies" width="790" height="705"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s create a migration to the init schema of our database. I will use YAML syntax, but with Liquibase, you can choose between plain SQL, JSON, and YAML.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;databaseChangeLog:
  - changeSet:
      id: init-schema
      author: Egor Voronianskii
      changes:
        - createTable:
            tableName: GOODS
            columns:
              - column:
                  name: id
                  type: UUID
                  constraints:
                    primaryKey: true
                    nullable: false
              - column:
                  name: name
                  type: VARCHAR(255)
                  constraints:
                    nullable: false
              - column:
                  name: price
                  type: numeric
              - column:
                  name: total_count
                  type: integer
              - column:
                  name: sold_count
                  type: integer
              - column:
                  name: deleted
                  type: boolean
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I have the following structure in the project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztn0s6kj5c7lzq54qec8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztn0s6kj5c7lzq54qec8.png" alt="Project structure" width="467" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have the following structure in the project. There are two folders — one for data definition language and the second for data management language.&lt;/p&gt;

&lt;p&gt;Inside the changelog.yml, I specified where the migrations folder is located.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;databaseChangeLog:
  - includeAll:
      path: db/migrations/ddl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let’s configure our application to use the right changelog.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/goods_db
    username: postgres
    password: 55555
  liquibase:
    change-log: classpath:db/changelog.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Before starting the app, ensure you have created a database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhlxd9z5ylsqr26lj86au.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhlxd9z5ylsqr26lj86au.png" alt="Tables created by Liquibase" width="800" height="259"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next step is to add a jOOQ plugin to generate code from the database. Here is my updated build section of pom.xml.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;build&amp;gt;
        &amp;lt;plugins&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;org.jooq&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;jooq-codegen-maven&amp;lt;/artifactId&amp;gt;
                &amp;lt;dependencies&amp;gt;
                    &amp;lt;dependency&amp;gt;
                        &amp;lt;groupId&amp;gt;org.postgresql&amp;lt;/groupId&amp;gt;
                        &amp;lt;artifactId&amp;gt;postgresql&amp;lt;/artifactId&amp;gt;
                        &amp;lt;version&amp;gt;42.6.0&amp;lt;/version&amp;gt;
                    &amp;lt;/dependency&amp;gt;
                &amp;lt;/dependencies&amp;gt;
                &amp;lt;configuration&amp;gt;
                    &amp;lt;jdbc&amp;gt;
                        &amp;lt;driver&amp;gt;org.postgresql.Driver&amp;lt;/driver&amp;gt;
                        &amp;lt;url&amp;gt;jdbc:postgresql://localhost:5432/goods_db&amp;lt;/url&amp;gt;
                        &amp;lt;user&amp;gt;postgres&amp;lt;/user&amp;gt;
                        &amp;lt;password&amp;gt;55555&amp;lt;/password&amp;gt;
                    &amp;lt;/jdbc&amp;gt;
                    &amp;lt;generator&amp;gt;
                        &amp;lt;name&amp;gt;org.jooq.codegen.JavaGenerator&amp;lt;/name&amp;gt;
                        &amp;lt;database&amp;gt;
                            &amp;lt;excludes&amp;gt;databasechangelog|databasechangeloglock&amp;lt;/excludes&amp;gt;
                        &amp;lt;/database&amp;gt;
                    &amp;lt;/generator&amp;gt;
                &amp;lt;/configuration&amp;gt;
            &amp;lt;/plugin&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;spring-boot-maven-plugin&amp;lt;/artifactId&amp;gt;
                &amp;lt;configuration&amp;gt;
                    &amp;lt;excludes&amp;gt;
                        &amp;lt;exclude&amp;gt;
                            &amp;lt;groupId&amp;gt;org.projectlombok&amp;lt;/groupId&amp;gt;
                            &amp;lt;artifactId&amp;gt;lombok&amp;lt;/artifactId&amp;gt;
                        &amp;lt;/exclude&amp;gt;
                    &amp;lt;/excludes&amp;gt;
                &amp;lt;/configuration&amp;gt;
            &amp;lt;/plugin&amp;gt;
        &amp;lt;/plugins&amp;gt;
    &amp;lt;/build&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As you may see, I must configure the database connection again and exclude tables Liquibase creates.&lt;/p&gt;

&lt;p&gt;Now, run the plugin; you can do it from the terminal or the IDE.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdaxtfyjapurxjgypppar.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdaxtfyjapurxjgypppar.png" alt="IDEA Maven Plugins" width="800" height="819"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After successfully running the plugin, you should see the generated classes in the target folder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi7xsbyuazeqnfzje7tvx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi7xsbyuazeqnfzje7tvx.png" alt="Target folder with generated classes" width="704" height="922"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the start of the article, I forgot to add the Spring Boot Web starter; let’s add it to pom.xml.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
        &amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We must create a data transfer object before moving to the write service and controller layer. You may agree or disagree with me. However, having a different object unrelated to the database entity is better.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.jooqdemo.dto;

import java.math.BigDecimal;
import java.util.UUID;

public record Goods(
        UUID id,
        String name,
        BigDecimal price,
        Integer totalCount,
        Integer soldCount,
        boolean deleted
) {
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The next step is to implement the service layer of our app.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.jooqdemo.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jooq.DSLContext;
import org.jooq.generated.public_.tables.Goods;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.UUID;

@Slf4j
@Service
@RequiredArgsConstructor
public class GoodsService {

    private final DSLContext dslContext;

    public io.vrnsky.jooqdemo.dto.Goods create(io.vrnsky.jooqdemo.dto.Goods goods) {
        var id = UUID.randomUUID();
        var result = dslContext.insertInto(Goods.GOODS)
                .values(id, goods.name(), goods.price(), goods.totalCount(), goods.soldCount(), goods.deleted())
                .execute();
        log.info("Inserted with result: {}", result);
        return getById(id);
    }

    public io.vrnsky.jooqdemo.dto.Goods update(io.vrnsky.jooqdemo.dto.Goods goods) {
        var updated = dslContext.update(Goods.GOODS)
                .set(Goods.GOODS.ID, goods.id())
                .set(Goods.GOODS.NAME, goods.name())
                .set(Goods.GOODS.PRICE, goods.price())
                .set(Goods.GOODS.SOLD_COUNT, goods.soldCount())
                .set(Goods.GOODS.TOTAL_COUNT, goods.totalCount())
                .set(Goods.GOODS.DELETED, goods.deleted())
                .execute();
        log.info("Successfully updated {} rows", updated);
        return this.getById(goods.id());
    }

    public io.vrnsky.jooqdemo.dto.Goods getById(UUID id) {
        final var fetchedRecord = dslContext.select(
                        Goods.GOODS.ID, Goods.GOODS.NAME, Goods.GOODS.PRICE,
                        Goods.GOODS.SOLD_COUNT, Goods.GOODS.TOTAL_COUNT, Goods.GOODS.DELETED
                )
                .from(Goods.GOODS)
                .where(Goods.GOODS.ID.eq(id))
                .fetchOne();
        Assert.notNull(fetchedRecord, "Record with id = " + id + " is not exists");
        return new io.vrnsky.jooqdemo.dto.Goods(
                fetchedRecord.get(Goods.GOODS.ID),
                fetchedRecord.get(Goods.GOODS.NAME),
                fetchedRecord.get(Goods.GOODS.PRICE),
                fetchedRecord.get(Goods.GOODS.SOLD_COUNT),
                fetchedRecord.get(Goods.GOODS.TOTAL_COUNT),
                fetchedRecord.get(Goods.GOODS.DELETED)
        );
    }

    public void delete(UUID id) {
        dslContext.update(Goods.GOODS).
                set(Goods.GOODS.DELETED, true)
                .where(Goods.GOODS.ID.eq(id))
                .execute();

        log.info("Successfully deleted the good with id = [" + id + "]");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It is time to create a controller layer to test our application.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.jooqdemo;

import io.vrnsky.jooqdemo.dto.Goods;
import io.vrnsky.jooqdemo.service.GoodsService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@RestController
@RequiredArgsConstructor
public class GoodsController {

    private final GoodsService goodsService;

    @PostMapping("/create")
    public Goods create(@RequestBody Goods goods) {
        goodsService.create(goods);
    }

    @GetMapping("/{id}")
    public Goods getById(@PathVariable UUID id) {
        goodsService.getById(id);
    }

    @PutMapping("/update")
    public Goods update(@RequestBody Goods goods) {
        goodsService.update(goods);
    }

    @DeleteMapping("/delete/{id}")
    public void delete(@PathVariable UUID id) {
        goodsService.delete(id);
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I will add Spring Doc dependencies and document controller methods to make the testing process more accessible. This type of testing is manual and the better approach to writing unit tests.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   &amp;lt;dependency&amp;gt;
      &amp;lt;groupId&amp;gt;org.springdoc&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;springdoc-openapi-starter-webmvc-ui&amp;lt;/artifactId&amp;gt;
      &amp;lt;version&amp;gt;2.3.0&amp;lt;/version&amp;gt;
   &amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here is the updated version of the controller class.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.jooqdemo;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.vrnsky.jooqdemo.dto.Goods;
import io.vrnsky.jooqdemo.service.GoodsService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@RestController
@RequiredArgsConstructor
@Tag(name = "GoodsController", description = "Operations with goods")
public class GoodsController {

    private final GoodsService goodsService;

    @Operation(summary = "Creation of goods")
    @PostMapping("/create")
    public Goods create(@RequestBody Goods goods) {
        return goodsService.create(goods);
    }

    @Operation(summary = "Get goods by id")
    @GetMapping("/{id}")
    public Goods getById(@PathVariable UUID id) {
        return goodsService.getById(id);
    }

    @Operation(summary = "Update goods")
    @PutMapping("/update")
    public Goods update(@RequestBody Goods goods) {
        return goodsService.update(goods);
    }

    @Operation(summary = "Delete by id")
    @DeleteMapping("/delete/{id}")
    public void delete(@PathVariable UUID id) {
        goodsService.delete(id);
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, we can run the application and try to perform CRUD operations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5rjioa40pxoxteln50hu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5rjioa40pxoxteln50hu.png" width="800" height="553"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjjo6l2ipqvb0dvhi1fam.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjjo6l2ipqvb0dvhi1fam.png" alt="Swagger UI and creation of goods" width="800" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It is my first time using a jOOQ; I cannot say that I’m going to use it at this moment at my job. My experience with jOOQ is relatively tiny. In my honest opinion, jOOQ would be a better approach if the application business logic requires very complex SQL queries. Meanwhile, the Spring JPA and Hibernate simplify the work with the database. So, choose carefully the tool that you would like to use. Compare the pros and cons of each tool before starting to use it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One more thing:&lt;/strong&gt; You may raise an opinion that Goods is terrible naming, and I agree with you, but at the moment, I have been struggling to choose a domain field for this article.&lt;/p&gt;

&lt;p&gt;Please feel free to give any comments if you have any. Share your experience with jOOQ in the comments.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.spring.io/spring-boot/docs/1.3.5.RELEASE/reference/html/boot-features-jooq.html" rel="noopener noreferrer"&gt;Spring Boot jOOQ Documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.jooq.org/doc/latest/manual/" rel="noopener noreferrer"&gt;jOOQ Documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.liquibase.com/" rel="noopener noreferrer"&gt;Liquibase Documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://springdoc.org/" rel="noopener noreferrer"&gt;SpringDoc Documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>springboot</category>
      <category>jooq</category>
      <category>liquibase</category>
      <category>springdoc</category>
    </item>
    <item>
      <title>JUnit 5 | How to write more tests with less code</title>
      <dc:creator>Yegor Voronianskii</dc:creator>
      <pubDate>Sun, 31 Dec 2023 09:57:54 +0000</pubDate>
      <link>https://dev.to/vrnsky/junit-5-how-to-write-more-tests-with-less-code-3l6m</link>
      <guid>https://dev.to/vrnsky/junit-5-how-to-write-more-tests-with-less-code-3l6m</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this article, I will show and explain how you can write more tests with relatively small changes in your code.&lt;/p&gt;

&lt;p&gt;Recently, one of my colleagues wrote a massive test with repetitive code. The difference between test cases was only data that was submitted to the service. I will use JUnit 5 in this article, but feel free to check the library docs you use for writing tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Let’s imagine the following situation: we have a service that accepts the following data and returns the following response.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "operationType": "+",
  "operands": [
    1,
    2,
    3,
    4,
    5
  ]
}

{
  "result": 15
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Of course, we can write many tests to cover each aspect, but there is a better solution. Let me introduce to you TestFactory from JUnit 5. You may argue that artificial cases use a test factory, and I agree with you, but the article is designed to give you an idea of how you can achieve more tests without writing more code.&lt;/p&gt;

&lt;p&gt;Let’s implement our data transfer object first.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.testfactorydemo.dto;

import java.util.List;

public record Request(
        String operationType,
        List&amp;lt;Integer&amp;gt; operands
) {
}

package io.vrnsky.testfactorydemo.dto;

public record Response(
        Integer result
) {
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The next step is to implement service and controller layers.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.testfactorydemo.service;

import io.vrnsky.testfactorydemo.dto.Request;
import io.vrnsky.testfactorydemo.dto.Response;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class CalculationService {

    public Response calculate(Request request) {
        return switch (request.operationType()) {
            case "+" -&amp;gt; new Response(sum(request.operands()));
            case "*" -&amp;gt; new Response(multiply(request.operands()));
            default -&amp;gt; throw new IllegalArgumentException("Invalid operation: " + request.operationType());
        };
    }

    private int sum(List&amp;lt;Integer&amp;gt; operands) {
        if (operands == null || operands.isEmpty()) {
            return 0;
        }
        return operands.stream().mapToInt(i -&amp;gt; i).sum();
    }

    private int multiply(List&amp;lt;Integer&amp;gt; operands) {
        if (operands == null || operands.isEmpty()) {
            return 0;
        }
        int result = 1;
        for (Integer operand : operands) {
            result *= operand;
        }
        return result;
    }

}

package io.vrnsky.testfactorydemo.controller;

import io.vrnsky.testfactorydemo.dto.Request;
import io.vrnsky.testfactorydemo.dto.Response;
import io.vrnsky.testfactorydemo.service.CalculationService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CalculateController {

    private final CalculationService calculationService;

    public CalculateController(CalculationService calculationService) {
        this.calculationService = calculationService;
    }

    @PostMapping("/calculate")
    public Response calculate(@RequestBody Request request) {
        return calculationService.calculate(request);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The controller is not required; we can test only the service layer. I have implemented a controller to test manually that the application is working. Manual testing is a bad thing because it cannot be automated.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X POST "http://localhost:8080/calculate" -H "Content-type:application/json" -d '{"operationType": "+", "operands": [1, 2, 3]}' 
{"result":6}%

curl -X POST "http://localhost:8080/calculate" -H "Content-type:application/json" -d '{"operationType": "+", "operands": []}'        
{"result":0}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Okay, now it is what you have been waiting for — let’s write a unit test with TestFactory. But before implementing, let’s create two folders inside the test resource directory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvy5s0nd15z07bygn5i1u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvy5s0nd15z07bygn5i1u.png" alt="Folder structure" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the files, I have a request and response as follows.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"operationType": "+", "operands": [1, 2, 3]}

{"result":6}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The next step is to implement a test factory within the unit test.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.testfactorydemo.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.vrnsky.testfactorydemo.dto.Request;
import io.vrnsky.testfactorydemo.dto.Response;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;

class CalculationServiceTest {

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final CalculationService CALCULATION_SERVICE = new CalculationService();

    @TestFactory
    Stream&amp;lt;DynamicTest&amp;gt; testCalculateService() {
        int counter = 0;
        List&amp;lt;Stream&amp;lt;DynamicTest&amp;gt;&amp;gt; test = Collections.singletonList(generateTest("(+)", counter++, "request/1.json", "response/1.json"));
        return test
                .stream()
                .flatMap(stream -&amp;gt; stream);
    }

    private Stream&amp;lt;DynamicTest&amp;gt; generateTest(String tag, int counter, String requestPath, String responsePath) {
        return Stream.of(createTest(tag, counter, requestPath, responsePath));
    }

    private DynamicTest createTest(String tag, int counter, String requestPath, String responsePath) {
        return DynamicTest.dynamicTest(tag + " | Calculation test case #" + counter, () -&amp;gt; {
            var request = this.getRequest(requestPath);
            var expected = this.getResponse(responsePath);
            var actual = CALCULATION_SERVICE.calculate(request);
            Assertions.assertEquals(expected.result(), actual.result());
        });
    }

    private Request getRequest(String path) {
        try {
            byte[] content = Files.readAllBytes(Paths.get(CalculationServiceTest.class.getClassLoader().getResource(path).getPath()));
            return OBJECT_MAPPER.readValue(new String(content, StandardCharsets.UTF_8), Request.class);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private Response getResponse(String path) {
        try {
            byte[] content = Files.readAllBytes(Paths.get(CalculationServiceTest.class.getClassLoader().getResource(path).getPath()));
            return OBJECT_MAPPER.readValue(new String(content, StandardCharsets.UTF_8), Response.class);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let me explain what is going on inside this class.&lt;/p&gt;

&lt;p&gt;First, we have a public method annotated with TestFactory annotation, which the testing framework will run. The other parts of the helper method achieve the following things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Read requests from the test resource folder&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Read the expected response from the test resource folder&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creation of dynamic test&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For now, I have created files for only one unit test. You can add your own if you would like. &lt;br&gt;
I have added two more files to test other inputs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffvkdgqvq8h53mdjfmbqc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffvkdgqvq8h53mdjfmbqc.png" alt="New requests and responses" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The article’s title tells you that you can write less code and achieve more test coverage. It is true, but you still need to change something. You need to add a new request-response pair.&lt;/p&gt;

&lt;p&gt;Here is an updated version of the method annotated by the TestFactory annotation.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    @TestFactory
    Stream&amp;lt;DynamicTest&amp;gt; testCalculateService() {
        int counter = 0;
        List&amp;lt;Stream&amp;lt;DynamicTest&amp;gt;&amp;gt; test = Arrays.asList(
                generateTest("(+)", counter++, "request/1.json", "response/1.json"),
                generateTest("(+)", counter++, "request/2.json", "response/2.json"),
                generateTest("(+)", counter++, "request/3.json", "response/3.json")
        );
        return test
                .stream()
                .flatMap(stream -&amp;gt; stream);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, you can run your tests and will see something similar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9e6jmx7db3k42leyh1wx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9e6jmx7db3k42leyh1wx.png" alt="Unit tests from TestFactory" width="800" height="188"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code could be better. There is always a place to improve something. For example, one thing you do is to read all files in the directory instead of hard-coding it. By doing this, you can achieve a minimal change in code only by adding files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You may disagree with my point of view, but less code means fewer bugs in the code. Sometimes, using TestFactory is not a good choice, but it is a good choice when you have something to test, and the logic of the service is complex. The other reason behind choosing TestFactory is a lot of parameters that impact the results of something. Recently, I faced a request with a lot of parameters. The response is hard depending on the request data, so I have stuck with the test factory choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://junit.org/junit5/docs/current/user-guide/" rel="noopener noreferrer"&gt;JUnit 5 docs&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>java</category>
      <category>junit5</category>
      <category>springboot</category>
    </item>
    <item>
      <title>Spring Cloud Functions, Kafka | How to interact asynchronous</title>
      <dc:creator>Yegor Voronianskii</dc:creator>
      <pubDate>Sun, 24 Dec 2023 10:10:51 +0000</pubDate>
      <link>https://dev.to/vrnsky/spring-cloud-functions-kafka-how-to-interact-asynchronous-2c6o</link>
      <guid>https://dev.to/vrnsky/spring-cloud-functions-kafka-how-to-interact-asynchronous-2c6o</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This article will show how to use the Spring Cloud Functions projects. The Spring Cloud Functions is the best approach to implementing a straightforward business logic.&lt;br&gt;
Nowadays, the usage of message brokers such as Kafka has increased.&lt;br&gt;
I will implement a simple system in this article, as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7onaoxvzwdmdk8m6837l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7onaoxvzwdmdk8m6837l.png" alt="Diagram of developing system" width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;I will start with a simple example of a cloud function, which is the same as a rest endpoint in the classical spring boot web application. You can create a project from your favorite IDE or from &lt;a href="https://start.spring.io/" rel="noopener noreferrer"&gt;Spring Initliazr.&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"&amp;gt;
    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
    &amp;lt;parent&amp;gt;
        &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;spring-boot-starter-parent&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;3.2.1&amp;lt;/version&amp;gt;
        &amp;lt;relativePath/&amp;gt; &amp;lt;!-- lookup parent from repository --&amp;gt;
    &amp;lt;/parent&amp;gt;
    &amp;lt;groupId&amp;gt;io.vrnsky&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;cloud-function-push&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;0.0.1-SNAPSHOT&amp;lt;/version&amp;gt;
    &amp;lt;name&amp;gt;cloud-function-push&amp;lt;/name&amp;gt;
    &amp;lt;description&amp;gt;cloud-function-push&amp;lt;/description&amp;gt;
    &amp;lt;properties&amp;gt;
        &amp;lt;java.version&amp;gt;17&amp;lt;/java.version&amp;gt;
        &amp;lt;spring-cloud.version&amp;gt;2023.0.0&amp;lt;/spring-cloud.version&amp;gt;
    &amp;lt;/properties&amp;gt;
    &amp;lt;dependencies&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-cloud-function-context&amp;lt;/artifactId&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-cloud-starter-function-web&amp;lt;/artifactId&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-boot-starter-test&amp;lt;/artifactId&amp;gt;
            &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
        &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
    &amp;lt;dependencyManagement&amp;gt;
        &amp;lt;dependencies&amp;gt;
            &amp;lt;dependency&amp;gt;
                &amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;spring-cloud-dependencies&amp;lt;/artifactId&amp;gt;
                &amp;lt;version&amp;gt;${spring-cloud.version}&amp;lt;/version&amp;gt;
                &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
                &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
            &amp;lt;/dependency&amp;gt;
        &amp;lt;/dependencies&amp;gt;
    &amp;lt;/dependencyManagement&amp;gt;

    &amp;lt;build&amp;gt;
        &amp;lt;plugins&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;spring-boot-maven-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;/plugin&amp;gt;
        &amp;lt;/plugins&amp;gt;
    &amp;lt;/build&amp;gt;

&amp;lt;/project&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Your pom.xml file or build.gradle should like this.&lt;/p&gt;

&lt;p&gt;The first step is to describe events related to service. I will stick with the following definition of an event.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.cloudfunctionpush.domain;

import java.util.List;

public record PullRequestAccepted(
        String author,
        List&amp;lt;String&amp;gt; reviewers,

        boolean havePassedAllChecks
) {
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The first step is to describe events related to service. I will stick with the following definition of an event.&lt;br&gt;
The second step is to create a configuration class within the bean function creation inside it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.cloudfunctionpush.config;

import io.vrnsky.cloudfunctionpush.domain.PullRequestAccepted;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.function.Function;


@Configuration
public class FunctionConfig {

    @Bean
    public Function&amp;lt;PullRequestAccepted, String&amp;gt; pullRequestAccepted() {
        return value -&amp;gt; """
                Pull request from %s has been reviewed by %s. Have passed all checks: %b
                """
                .formatted(value.author(), value.reviewers().size(), value.havePassedAllChecks());
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It’s time to start our cloud function push service and check that it works correctly.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://localhost:8080/pullRequestAccepted -H "Content-type:application/json" -d '{"author":"Yegor Voronianskii","reviewers":[],"havePassedAllChecks":true}'
Pull request from Yegor Voronianskii has been reviewed by 0. Have passed all checks: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To achieve that, we must add the following dependencies to pom.xml or build.gradle&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.apache.kafka&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;kafka-streams&amp;lt;/artifactId&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-cloud-stream&amp;lt;/artifactId&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-cloud-stream-binder-kafka&amp;lt;/artifactId&amp;gt;
        &amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Before starting the service, it is required to start Kafka and Zookeeper. Here is a docker-compose file to start both.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: "3"
services:
  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
    ports:
      - "22181:2181"

  kafka:
    image: confluentinc/cp-kafka:latest
    depends_on:
      - zookeeper
    environment:
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092,EXTERNAL://localhost:29092
      KAFKA_LISTENERS: PLAINTEXT://:9092,EXTERNAL://:29092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
    ports:
      - "9092:9092"
      - "29092:29092"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can start Kafka and Zookeeper by following the command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The next step it to configure our application and add some code. Here, you can see the updated version of the FunctionConfig class, where an instance of the stream bridge is injected. You can use Lombok for brevity. It is up to you.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.cloudfunctionpush.config;

import io.vrnsky.cloudfunctionpush.domain.PullRequestAccepted;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.function.Function;


@Configuration
public class FunctionConfig {

    private final StreamBridge streamBridge;

    public FunctionConfig(StreamBridge streamBridge) {
        this.streamBridge = streamBridge;
    }

    @Bean
    public Function&amp;lt;PullRequestAccepted, String&amp;gt; pullRequestAccepted() {
        return value -&amp;gt; {
            streamBridge.send("pullRequestAccepted-out-0", value);
            return "Message have been sent";
        };
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Below is the updated application configuration, where I specify the broker URL and other required settings.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring:
  kafka:
    bootstrap-servers:
      - http://localhost:29092
  cloud:
    stream:
      kafka:
        binder:
          brokers:
            - http://localhost:29092
      output-bindings: pullRequestAccepted-out-0

logging:
  level:
    org.springframework.cloud.stream: TRACE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, we can check that the message has been sent to the broker.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://localhost:8080/pullRequestAccepted -H "Content-type:application/json" -d '{"author":"Yegor Voronianskii","reviewers":[],"havePassedAllChecks":true}'
Message have been sent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In the cloud function push service, you should see something like this.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--- [nio-8080-exec-1] o.s.c.s.binder.DefaultBinderFactory      : Retrieving cached binder: kafka
--- [nio-8080-exec-1] o.s.c.s.m.DirectWithAttributesChannel    : preSend on channel 'bean 'pullRequestAccepted-out-0'', message: GenericMessage [payload=byte[73], headers={id=7c176f51-1a1a-63d9-b0ed-20cc1ce71fc8, contentType=application/json, target-protocol=kafka, timestamp=1703409370932}]
--- [nio-8080-exec-1] tractMessageChannelBinder$SendingHandler : org.springframework.cloud.stream.binder.AbstractMessageChannelBinder$SendingHandler@7d99be9b received message: GenericMessage [payload=byte[73], headers={id=7c176f51-1a1a-63d9-b0ed-20cc1ce71fc8, contentType=application/json, target-protocol=kafka, timestamp=1703409370932}]
--- [nio-8080-exec-1] nder$ProducerConfigurationMessageHandler : org.springframework.cloud.stream.binder.kafka.KafkaMessageChannelBinder$ProducerConfigurationMessageHandler@d36ee78 received message: GenericMessage [payload=byte[73], headers={id=d9ab9d27-fdf6-53a7-9db6-ae98e6130272, contentType=application/json, target-protocol=kafka, timestamp=1703409370933}]
--- [nio-8080-exec-1] nder$ProducerConfigurationMessageHandler : handler 'org.springframework.cloud.stream.binder.kafka.KafkaMessageChannelBinder$ProducerConfigurationMessageHandler@d36ee78' produced no reply for request Message: GenericMessage [payload=byte[73], headers={id=d9ab9d27-fdf6-53a7-9db6-ae98e6130272, contentType=application/json, target-protocol=kafka, timestamp=1703409370933}]
--- [nio-8080-exec-1] o.s.c.s.m.DirectWithAttributesChannel    : postSend (sent=true) on channel 'bean 'pullRequestAccepted-out-0'', message: GenericMessage [payload=byte[73], headers={id=7c176f51-1a1a-63d9-b0ed-20cc1ce71fc8, contentType=application/json, target-protocol=kafka, timestamp=1703409370932}]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The next step is implementing Spring Cloud Function to consume events from the message broker. The creation project’s steps are similar to those of the cloud push service. To configure our cloud pull service, we should have an application.properties or application.yml file with the following settings.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring:
  kafka:
    bootstrap-servers:
      - http://localhost:29092
  cloud:
    function:
      definition: pullRequestAccepted
    stream:
      kafka:
        binder:
          brokers:
            - http://localhost:29092
      input-bindings: pullRequestAccepted-in-0
      bindings:
        pullRequestAccepted-in-0:
          destination: pullRequestAccepted-out-0
          group: myGroup
logging:
  level:
    org.springframework.cloud.stream: TRACE
server:
  port: 9090
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To handle incoming messages, we have to define the consumer of this message. I stick with a simple solution that prints the message into standard output.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.example.cloudfunctionpull.config;

import com.example.cloudfunctionpull.domain.PullRequestAccepted;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.Message;

import java.util.function.Consumer;

@Configuration
public class FunctionsConfig {

    @Bean
    public Consumer&amp;lt;Message&amp;lt;PullRequestAccepted&amp;gt;&amp;gt; pullRequestAccepted() {
        return message -&amp;gt; {
            PullRequestAccepted payload = message.getPayload();
            System.out.println("Received message: " + payload);
        };
    }

    @Bean
    public Consumer&amp;lt;Message&amp;lt;?&amp;gt;&amp;gt; myErrorHandler() {
        return errorMessage -&amp;gt; {
            System.out.println("Handling error message " + errorMessage);
        };
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After a successful start of consuming the service, we can again push the message to the message broker and check that the message was consumed to pull the service.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kafka_consumer=org.springframework.kafka.core.DefaultKafkaConsumerFactory$ExtendedKafkaConsumer@1721c358, deliveryAttempt=1, kafka_timestampType=CREATE_TIME, kafka_receivedPartitionId=0, contentType=application/json, kafka_receivedTopic=pullRequestAccepted-out-0, kafka_receivedTimestamp=1703411981591, kafka_groupId=myGroup, target-protocol=kafka}]&lt;br&gt;
Received message: PullRequestAccepted[author=Yegor Voronianskii, reviewers=[], havePassedAllChecks=true]&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Conclusion&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;In my honest opinion, the Spring Cloud Function is a great tool for small, short-lived microservices. The Spring Cloud Stream is an excellent tool for building event-driven microservices architecture. But there are pros; of course, this project’s complexity can bring a lot of pain in terms of maintenance and understanding new paradigms.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.spring.io/spring-cloud-stream/docs/current/reference/html/" rel="noopener noreferrer"&gt;Spring Cloud Stream Documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://cloud.spring.io/spring-cloud-function/reference/html/" rel="noopener noreferrer"&gt;Spring Cloud Functions Documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://kafka.apache.org/documentation/" rel="noopener noreferrer"&gt;Kafka Documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>springcloudstream</category>
      <category>springcloudfunctions</category>
      <category>kafka</category>
      <category>java</category>
    </item>
    <item>
      <title>Spring Boot Mutation testing with JUnit 5, Testcontainiers, and PIT</title>
      <dc:creator>Yegor Voronianskii</dc:creator>
      <pubDate>Sat, 23 Dec 2023 10:58:44 +0000</pubDate>
      <link>https://dev.to/vrnsky/spring-boot-mutation-testing-with-junit-5-testcontainiers-and-pit-261m</link>
      <guid>https://dev.to/vrnsky/spring-boot-mutation-testing-with-junit-5-testcontainiers-and-pit-261m</guid>
      <description>&lt;h2&gt;
  
  
  What is mutation testing?
&lt;/h2&gt;

&lt;p&gt;Mutation testing is a type of testing that validates new and existing tests. More formal definition from &lt;a href="https://en.wikipedia.org/wiki/Mutation_testing" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Mutation testing&lt;/strong&gt; (or &lt;em&gt;mutation analysis&lt;/em&gt; or &lt;em&gt;program mutation&lt;/em&gt;) is used to design new software tests and evaluate the quality of existing software tests.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why do we need mutation testing?
&lt;/h2&gt;

&lt;p&gt;The problem that solves mutation testing is checking the validity of the existing and new tests. I often have met invalid unit tests that have covered only the happy path and no other paths.&lt;/p&gt;

&lt;h2&gt;
  
  
  When does it make sense for mutation testing?
&lt;/h2&gt;

&lt;p&gt;So, if overall coverage is below 80%, you can skip mutation testing. You can return to mutation testing once you reach a threshold of 80% coverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  How is mutation testing working?
&lt;/h2&gt;

&lt;p&gt;The mutation testing itself is a form of white box testing. More or less mutation testing, trying to mutate or change your code and check that unit tests will fail.&lt;/p&gt;

&lt;p&gt;The process of changing your code is called mutation. The mutation can be killed or survived during the test phase. The killed mutation is a good sign, notifying us that the unit tests caught the mutation and failed the unit test; on the other hand, if the mutation survived, that is a bad sign that the unit test did not die with code changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation of mutation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frdu6q7idi4e1onsfts4s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frdu6q7idi4e1onsfts4s.png" alt="Project creation" width="800" height="623"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, we should add the following dependency on TestContainer for PostgreSQL.&lt;/p&gt;

&lt;p&gt;In your pom.xml add following dependency.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  &amp;lt;dependency&amp;gt;
   &amp;lt;groupId&amp;gt;org.testcontainers&amp;lt;/groupId&amp;gt;
   &amp;lt;artifactId&amp;gt;postgresql&amp;lt;/artifactId&amp;gt;
   &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
  &amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The next step is to add a basic class test, which will be responsible for creating a PostgreSQL test container.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.mutationdemo;

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

@Testcontainers
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@DirtiesContext
public class DatabaseIntegrationTest {

    @Container
    public static PostgreSQLContainer&amp;lt;?&amp;gt; postgreSQLContainer = new PostgreSQLContainer&amp;lt;&amp;gt;()
            .withPassword("inmemory")
            .withUsername("inmemory");

    @DynamicPropertySource
    static void postgresqlProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl);
        registry.add("spring.datasource.password", postgreSQLContainer::getPassword);
        registry.add("spring.datasource.username", postgreSQLContainer::getUsername);
        registry.add("spring.datasource.platform", () -&amp;gt; PostgreSQLContainer.NAME);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let’s implement some basic functionality — the basic CRUD application.&lt;br&gt;
The project will be to manage the book entity.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.mutationdemo.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDate;
import java.util.UUID;

@Data
@Table(name = "BOOK")
@Entity
@AllArgsConstructor
@NoArgsConstructor
public class Book {

    @Id
    @GeneratedValue
    @Column(name = "ID")
    private UUID id;

    @Column(name = "AUTHOR")
    private String author;

    @Column(name = "ISBN")
    private String isbn;

    @Column(name = "PUBLISHED_DATE")
    private LocalDate publishedDate;

    @Column(name = "DELETED")
    private boolean deleted;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To manage an entity, you need to create an interface that extends the JPA Repository interface.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.mutationdemo.repository;

import io.vrnsky.mutationdemo.entity.Book;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.UUID;

public interface BookRepository extends JpaRepository&amp;lt;Book, UUID&amp;gt; {
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;According to the most used structure of spring boot services, we need two more layers — service and controller. Let’s implement that&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.mutationdemo.service;

import io.vrnsky.mutationdemo.entity.Book;
import io.vrnsky.mutationdemo.repository.BookRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.UUID;

@Slf4j
@Service
@RequiredArgsConstructor
public class BookService {

    private final BookRepository bookRepository;

    public Book create(Book book) {
        return bookRepository.save(book);
    }

    public Book getById(UUID bookId) {
        var book = bookRepository.findById(bookId);
        if (book.isEmpty()) {
            throw new RuntimeException();
        }
        return book.get();
    }

    public Book update(Book book) {
        var existingBook = bookRepository.findById(book.getId());
        if (existingBook.isEmpty()) {
            throw new RuntimeException();
        }
        return bookRepository.save(book);
    }

    public void delete(UUID bookId) {
        var existingBook = bookRepository.findById(bookId);
        if (existingBook.isEmpty()) {
            throw new RuntimeException();
        }

        existingBook.get().setDeleted(true);
        bookRepository.save(existingBook.get());
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As you can see, for now, we are using RuntimeException. It is a terrible practice. Sonar Qube also agrees with me. We will fix it later with custom runtime exceptions and controller advice.&lt;/p&gt;

&lt;p&gt;BookController.java&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.mutationdemo.controller;

import io.vrnsky.mutationdemo.entity.Book;
import io.vrnsky.mutationdemo.service.BookService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@RestController
@RequiredArgsConstructor
public class BookController {

    private final BookService bookService;

    @PostMapping("/book")
    public Book create(@RequestBody Book book) {
        return bookService.create(book);
    }

    @GetMapping("/book/{bookId}")
    public Book getById(@PathVariable UUID bookId) {
        return bookService.getById(bookId);
    }

    @PutMapping("/book/{bookId}")
    public Book update(@RequestBody Book book) {
        return bookService.update(book);
    }

    @DeleteMapping("/{bookId}")
    public void delete(@PathVariable UUID bookId) {
        bookService.delete(bookId);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There is one more thing that we also need to improve, which is added documentation to our controllers. We will do it later, and I will use SpringDoc for that.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.mutationdemo.controller;

import io.vrnsky.mutationdemo.entity.Book;
import io.vrnsky.mutationdemo.service.BookService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@RestController
@RequiredArgsConstructor
public class BookController {

    private final BookService bookService;

    @PostMapping("/book")
    public Book create(@RequestBody Book book) {
        return bookService.create(book);
    }

    @GetMapping("/book/{bookId}")
    public Book getById(@PathVariable UUID bookId) {
        return bookService.getById(bookId);
    }

    @PutMapping("/book/{bookId}")
    public Book update(@RequestBody Book book) {
        return bookService.update(book);
    }

    @DeleteMapping("/{bookId}")
    public void delete(@PathVariable UUID bookId) {
        bookService.delete(bookId);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It’s time to move on to write the unit test.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.mutationdemo.service;

import io.vrnsky.mutationdemo.DatabaseIntegrationTest;
import io.vrnsky.mutationdemo.entity.Book;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.LocalDate;
import java.util.UUID;

class BookServiceTest extends DatabaseIntegrationTest {

    @Autowired
    private BookService bookService;

    @Test
    @DisplayName("Test case: Creation of book")
    @Tag("Positive")
    void testThatCreationOfBookWorksCorrectly() {
        var book = new Book(null, "John Doe", "123", LocalDate.now(), false);
        var createdBook = bookService.create(book);
        Assertions.assertNotNull(createdBook.getId());
        Assertions.assertEquals(createdBook.getAuthor(), book.getAuthor());
        Assertions.assertEquals(createdBook.getIsbn(), book.getIsbn());
        Assertions.assertEquals(createdBook.getPublishedDate(), book.getPublishedDate());
        Assertions.assertFalse(createdBook.isDeleted());
    }

    @Test
    @DisplayName("Test case: Update book")
    @Tag("positive")
    void testThatUpdateOfBookWorksCorrectly() {
        var book = new Book(null, "John Doe", "123", LocalDate.now(), false);
        var createdBook = bookService.create(book);
        createdBook.setDeleted(true);
        var updatedBook = bookService.update(createdBook);
        Assertions.assertTrue(updatedBook.isDeleted());
    }

    @Test
    @DisplayName("Test case: Get book by id")
    @Tag("Positive")
    void testThatGetBookByIdWorksCorrectly() {
        var book = new Book(null, "John Doe", "123", LocalDate.now(), false);
        var createdBook = bookService.create(book);
        var existingBook = bookService.getById(createdBook.getId());
        Assertions.assertNotNull(existingBook);
    }

    @Test
    @DisplayName("Test case: Delete book")
    @Tag("Positive")
    void testThatDeleteBookWorksCorrectly() {
        var book = new Book(null, "John Doe", "123", LocalDate.now(), false);
        var createdBook = bookService.create(book);
        bookService.delete(createdBook.getId());
        var deletedBook = bookService.getById(createdBook.getId());
        Assertions.assertTrue(deletedBook.isDeleted());
    }

    @Test
    @DisplayName("Test case: Update not existing book")
    @Tag("Negative")
    void testThatUpdateOfNotExistingBookThrowsException() {
        var book = new Book(null, "John Doe", "123", LocalDate.now(), false);
        Assertions.assertThrows(RuntimeException.class, () -&amp;gt; bookService.update(book));
    }

    @Test
    @DisplayName("Test case: Get by id not existing book")
    @Tag("Negative")
    void testThatGetByIdOfNotExistingBookThrowException() {
        var book = new Book(null, "John Doe", "123", LocalDate.now(), false);
        Assertions.assertThrows(RuntimeException.class, () -&amp;gt; bookService.update(book));
    }

    @Test
    @DisplayName("Test case: Deleting not existing book")
    void testThatDeletionOfNotExistingBookThrowsException() {
        Assertions.assertThrows(RuntimeException.class, () -&amp;gt; bookService.delete(UUID.randomUUID()));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, let’s move to the controller layer.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.mutationdemo.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.vrnsky.mutationdemo.DatabaseIntegrationTest;
import io.vrnsky.mutationdemo.entity.Book;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

import java.time.LocalDate;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@AutoConfigureMockMvc
class BookControllerTest extends DatabaseIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @Test
    @DisplayName("Test case: Creating a book")
    @Tag("Positive")
    void testThatCreateBookCorrectlyCreateBook() throws Exception {
        var book = new Book(null, "John Doe", "123", LocalDate.now(), false);
        mockMvc.perform(post("/book")
                .content(objectMapper.writeValueAsString(book))
                .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").isNotEmpty())
                .andDo(print());
    }

    @Test
    @DisplayName("Test case: Updating existing book")
    @Tag("Positive")
    void testThatUpdatingExistingBookWorksCorrectly() throws Exception {
        var book = new Book(null, "John Doe", "123", LocalDate.now(), false);
        var mvcResponse = mockMvc.perform(post("/book")
                        .content(objectMapper.writeValueAsString(book))
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").isNotEmpty())
                .andReturn();

        var createdBook = objectMapper.readValue(mvcResponse.getResponse().getContentAsString(), Book.class);
        createdBook.setAuthor("Yegor");
        mockMvc.perform(put("/book/" + createdBook.getId())
                .content(objectMapper.writeValueAsString(createdBook))
                .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.author").value("Yegor"));
    }

    @Test
    @DisplayName("Test case: Get existing book by id")
    @Tag("Positive")
    void testThatGetExistingBookByIdWorksCorrectly() throws Exception {
        var book = new Book(null, "John Doe", "123", LocalDate.now(), false);
        var mvcResponse = mockMvc.perform(post("/book")
                        .content(objectMapper.writeValueAsString(book))
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").isNotEmpty())
                .andReturn();

        var createdBook = objectMapper.readValue(mvcResponse.getResponse().getContentAsString(), Book.class);
        createdBook.setAuthor("Yegor");
        mockMvc.perform(get("/book/" + createdBook.getId())
                        .content(objectMapper.writeValueAsString(createdBook))
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").value(createdBook.getId().toString()))
                .andExpect(jsonPath("$.author").value("John Doe"));
    }

    @Test
    @DisplayName("Test case: Deletion of existing book works correctly")
    @Tag("Positive")
    void testThatDeletionOfWorkBookWorksCorrectly() throws Exception {
        var book = new Book(null, "John Doe", "123", LocalDate.now(), false);
        var mvcResponse = mockMvc.perform(post("/book")
                        .content(objectMapper.writeValueAsString(book))
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").isNotEmpty())
                .andReturn();

        var createdBook = objectMapper.readValue(mvcResponse.getResponse().getContentAsString(), Book.class);
        createdBook.setAuthor("Yegor");
        mockMvc.perform(delete("/" + createdBook.getId())
                        .content(objectMapper.writeValueAsString(createdBook))
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk());

        mockMvc.perform(get("/book/" + createdBook.getId())
                        .content(objectMapper.writeValueAsString(createdBook))
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id").value(createdBook.getId().toString()))
                .andExpect(jsonPath("$.deleted").value(true));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The next step is to add the Pit plugin to perform mutation testing. By default, the plugin will try to mutate all code, so be precise about what you want to test.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   &amp;lt;plugin&amp;gt;
    &amp;lt;groupId&amp;gt;org.pitest&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;pitest-maven&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.15.3&amp;lt;/version&amp;gt;
    &amp;lt;dependencies&amp;gt;
     &amp;lt;dependency&amp;gt;
      &amp;lt;groupId&amp;gt;org.pitest&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;pitest-junit5-plugin&amp;lt;/artifactId&amp;gt;
      &amp;lt;version&amp;gt;1.2.1&amp;lt;/version&amp;gt;
     &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
    &amp;lt;configuration&amp;gt;
     &amp;lt;timeoutConstant&amp;gt;15000&amp;lt;/timeoutConstant&amp;gt;
     &amp;lt;verbose&amp;gt;true&amp;lt;/verbose&amp;gt;
     &amp;lt;targetClasses&amp;gt;
      &amp;lt;param&amp;gt;io.vrnsky.mutationdemo.service.*&amp;lt;/param&amp;gt;
      &amp;lt;param&amp;gt;io.vrnsky.mutationdemo.controller.*&amp;lt;/param&amp;gt;
     &amp;lt;/targetClasses&amp;gt;
     &amp;lt;targetTests&amp;gt;
      &amp;lt;param&amp;gt;io.vrnsky.mutationdemo.service.*&amp;lt;/param&amp;gt;
      &amp;lt;param&amp;gt;io.vrnsky.mutationdemo.controler.*&amp;lt;/param&amp;gt;
     &amp;lt;/targetTests&amp;gt;
     &amp;lt;features&amp;gt;
      &amp;lt;feature&amp;gt;+auto_threads&amp;lt;/feature&amp;gt;
     &amp;lt;/features&amp;gt;
    &amp;lt;/configuration&amp;gt;
   &amp;lt;/plugin&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There is one more thing: Pitest is running in single-thread mode until you explicitly configure the auto threads feature.. As you can see, I have set verbose to true. It helps get more detailed information on what is going on.&lt;/p&gt;

&lt;p&gt;Now, we can run mutation testing by following the command.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mvn org.pitest:pitest-maven:1.15.3:mutationCoverage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After completion, we can go to the target/pit-report folder and check the detailed report about mutation testing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjnchaic2q07hh7hgw2hc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjnchaic2q07hh7hgw2hc.png" alt="Project Report Summary" width="800" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1i3r67l1vw5smplawej0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1i3r67l1vw5smplawej0.png" alt="Detailed report BookController" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fegjftnwjujyburnze3ko.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fegjftnwjujyburnze3ko.png" alt="Detailed report BookService" width="800" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Mutation_testing" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://start.spring.io/" rel="noopener noreferrer"&gt;Spring Boot Initializr&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://testcontainers.com/" rel="noopener noreferrer"&gt;TestContainers&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://junit.org/junit5/" rel="noopener noreferrer"&gt;JUnit 5&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.manning.com/books/100-java-mistakes-and-how-to-avoid-them?ar=false&amp;amp;lpse=B" rel="noopener noreferrer"&gt;100 Java Mistakes and how to avoid them&lt;/a&gt;, Tagir Valeev&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>springboot</category>
      <category>mutationtesting</category>
      <category>pit</category>
    </item>
    <item>
      <title>Spring Cloud Config, Spring Cloud Bus &amp; Kafka | How to set up automatic updates of your configuration</title>
      <dc:creator>Yegor Voronianskii</dc:creator>
      <pubDate>Sat, 23 Dec 2023 10:56:55 +0000</pubDate>
      <link>https://dev.to/vrnsky/spring-cloud-config-spring-cloud-bus-kafka-how-to-set-up-automatic-updates-of-your-configuration-5d09</link>
      <guid>https://dev.to/vrnsky/spring-cloud-config-spring-cloud-bus-kafka-how-to-set-up-automatic-updates-of-your-configuration-5d09</guid>
      <description>&lt;p&gt;In this article, I will show you how to achieve automatic updates with Spring Cloud Bus and Kafka&lt;/p&gt;

&lt;p&gt;The Spring Cloud Bus, according to documentation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Spring Cloud Bus links nodes of a distributed system with a lightweight message broker. This can then broadcast state changes (e.g., configuration changes) or other management instructions. AMQP and Kafka broker implementations are included in the project. Alternatively, any &lt;a href="https://spring.io/projects/spring-cloud-stream" rel="noopener noreferrer"&gt;Spring Cloud Stream&lt;/a&gt; binder on the classpath will work out of the box as a transport.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I will start from common practice nowadays without a message broker.&lt;/p&gt;

&lt;p&gt;First, we need to create a repository with your app’s configuration. There is no rocket science to create a new repository. After that, we can edit with web IDE, clone, add, commit, and push the app’s configuration to the remote repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewqium0m14suc4zbbkfy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewqium0m14suc4zbbkfy.png" alt="Example of repository" width="800" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Example of configuration in repository&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo:
  message:
    text: 'Hello, world!'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The second part is to create a cloud config server and set up the correct configuration for this server. We must set up a remote repository and credentials to make the configuration accessible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkikvaoflsf193fasg3tv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkikvaoflsf193fasg3tv.png" alt="The creation of Spring Cloud Config Service Intellij IDEA" width="800" height="806"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fds7wzfswg6j95ke77yqb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fds7wzfswg6j95ke77yqb.png" alt="We only need Spring Config Server dependency for now" width="800" height="807"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before developing a service that will be consuming configuration, we need to add an annotation that enables the config server and provides configuration.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.cloudconfigservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class CloudConfigServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(CloudConfigServiceApplication.class, args);
    }

}

server:
  port: 8888
spring:
  cloud:
    config:
      enabled: true
      server:
        git:
          uri: https://github.com/vrnsky/medium-config
          username: vrnsky
          password: your_github_personal_access_token here
          try-master-branch: false
          clone-on-start: true
          search-paths:
            - medium-service
logging:
  level:
    org.springframework.cloud: DEBUG
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After a successful start, we can check if the configuration is available.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GitCredentialsProviderFactory : Constructing UsernamePasswordCredentialsProvider for URI https://github.com/vrnsky/medium-config

curl "http://localhost:8888/medium-service/main"
{"name":"medium-service","profiles":["main"],"label":null,"version":"f3c546784ab421046174a4119f2ca250184e740b","state":null,"propertySources":[{"name":"https://github.com/vrnsky/medium-config/medium-service/application.yml","source":{"echo.message.text":"Hello, world!"}}]}%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi2iz7zxb2obinecx2q8f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi2iz7zxb2obinecx2q8f.png" alt="Creation of service, which will be" width="800" height="716"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz79ldzhegzkh63i3obi8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz79ldzhegzkh63i3obi8.png" alt="Dependecies of medium service" width="800" height="712"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s configure our service to interact with the cloud-config server. I will configure the application to use the config server application running on my machine.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring:
  application:
    name: medium-service
  cloud:
    config:
      enabled: true
      uri: http://localhost:8888
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The next part is to create configuration properties of the medium service.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.mediumservice.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Data
@Configuration
@ConfigurationProperties(prefix = "echo.message")
public class MediumServiceConfig {

    private String text;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, let’s create a controller that will return the message value from the configuration.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.vrnsky.mediumservice.controller;

import io.vrnsky.mediumservice.config.MediumServiceConfig;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class MediumController {

    private final MediumServiceConfig config;

    @GetMapping("/sayHello")
    public String getMessage() {
        return config.getText();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let’s check if the property has been read from the cloud config server.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl http://localhost:8080/sayHello
Hello, world!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After successfully managing to run both the service and cloud config server, we are ready to move with adding Spring Cloud Bus integration.&lt;/p&gt;

&lt;p&gt;First, we need to bootstrap with docker-compose Kafka and Zookeeper.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: "3"
services:
  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
    ports:
      - "22181:2181"

  kafka:
    image: confluentinc/cp-kafka:latest
    depends_on:
      - zookeeper
    environment:
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092,EXTERNAL://localhost:29092
      KAFKA_LISTENERS: PLAINTEXT://:9092,EXTERNAL://:29092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
    ports:
      - "9092:9092"
      - "29092:29092"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Start Kafka and Zookeeper with the following command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The next thing we will add is to configure our Cloud Config Server and our service to push and consume events from the message broker.&lt;/p&gt;

&lt;p&gt;In your cloud config server, pom.xml add the following dependencies:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-cloud-config-monitor&amp;lt;/artifactId&amp;gt;
        &amp;lt;/dependency&amp;gt;

        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;spring-cloud-starter-stream-kafka&amp;lt;/artifactId&amp;gt;
        &amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The next step is to add properties in application.yml inside the resources folder of the config server.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring:
  kafka:
    bootstrap-servers:
      - http://localhost:29092
  cloud:
    bus:
      enabled: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, try to run the cloud config server and check if it succeeded in connecting with the message broker. You will see similar log messages if the connection has been established successfully.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.7c65c8b8-caaa-45e1-b5bb-2f9c8eb3b137-2, groupId=anonymous.7c65c8b8-caaa-45e1-b5bb-2f9c8eb3b137] Adding newly assigned partitions: springCloudBus-0
2023-12-21T13:31:23.119+08:00  INFO 7578 --- [container-0-C-1] o.a.k.c.c.internals.ConsumerCoordinator  : [Consumer clientId=consumer-anonymous.7c65c8b8-caaa-45e1-b5bb-2f9c8eb3b137-2, groupId=anonymous.7c65c8b8-caaa-45e1-b5bb-2f9c8eb3b137] Found no committed offset for partition springCloudBus-0
2023-12-21T13:31:23.123+08:00  INFO 7578 --- [container-0-C-1] o.a.k.c.c.internals.ConsumerCoordinator  : [Consumer clientId=consumer-anonymous.7c65c8b8-caaa-45e1-b5bb-2f9c8eb3b137-2, groupId=anonymous.7c65c8b8-caaa-45e1-b5bb-2f9c8eb3b137] Found no committed offset for partition springCloudBus-0
2023-12-21T13:31:23.133+08:00  INFO 7578 --- [container-0-C-1] o.a.k.c.c.internals.SubscriptionState    : [Consumer clientId=consumer-anonymous.7c65c8b8-caaa-45e1-b5bb-2f9c8eb3b137-2, groupId=anonymous.7c65c8b8-caaa-45e1-b5bb-2f9c8eb3b137] Resetting offset for partition springCloudBus-0 to position FetchPosition{offset=3, offsetEpoch=Optional.empty, currentLeader=LeaderAndEpoch{leader=Optional[localhost:29092 (id: 1001 rack: null)], epoch=
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, move on to the service side; in the pom.xml of service, add the following dependency:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; &amp;lt;dependency&amp;gt;
   &amp;lt;groupId&amp;gt;org.springframework.cloud&amp;lt;/groupId&amp;gt;
   &amp;lt;artifactId&amp;gt;spring-cloud-starter-bus-kafka&amp;lt;/artifactId&amp;gt;
 &amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The next step is configuring the service to listen to messages from the message broker.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring:
  config:
    import: optional:configserver:http://localhost:8888
  application:
    name: medium-service
  cloud:
    config:
      enabled: true
      uri: http://localhost:8888
    stream:
      kafka:
        binder:
          brokers:
            - http://localhost:29092
    bus:
      trace:
        enabled: true
      refresh:
        enabled: true
      env:
        enabled: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, we can start our config server and server. Please ensure that Kafka and Zookeeper have been created before bootstrapping the cloud config server and service.&lt;/p&gt;

&lt;p&gt;The automatic updates use webhooks from version control system platforms such as GitHub and GitLab. In this article, for correct working, the services should be deployed somewhere, like Cloud Platform Providers, but to keep things simple, we will do it on a local machine. &lt;br&gt;
You can create a webhook inside the repository’s settings section and get an idea of what information can be obtained from the webhook payload. I have used &lt;a href="https://webhook.site" rel="noopener noreferrer"&gt;https://webhook.site&lt;/a&gt; to get webhooks from the medium-config repository.&lt;/p&gt;

&lt;p&gt;Let’s change our property in a repository and manually trigger the configuration update.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo:
  message:
    text: 'Hello, Medium'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You may see &lt;a href="https://webhook.site" rel="noopener noreferrer"&gt;https://webhook.site&lt;/a&gt;, which has successfully caught the webhook. Copy the payload of the webhook we are going to use for the update configuration.&lt;/p&gt;

&lt;p&gt;It’s time to trigger the update by following the command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; curl -X POST 'http://localhost:8888/monitor?path=medium-service" -d '{webhook_payload}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You should see something similar in the logs of the cloud-config server. The logs tell us the message has been sent to the broker.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; o.s.c.s.m.DirectWithAttributesChannel    : postSend (sent=true) on channel 'bean 'springCloudBusInput'', message: GenericMessage [payload=byte[370], headers={kafka_offset=5, scst_nativeHeadersPresent=true, kafka_consumer=org.springframework.kafka.core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In logs of service, you should see the following logs:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2023-12-21T13:47:55.412+08:00  INFO 4389 --- [medium-service] [container-0-C-1] o.s.c.c.c.ConfigServerConfigDataLoader   : Located environment: name=medium-service, profiles=[default], label=null, version=a4ea5778de48d08b36e6a8ee310cf2e76ebde68f, state=null
2023-12-21T13:47:55.438+08:00  INFO 4389 --- [medium-service] [container-0-C-1] o.s.cloud.bus.event.RefreshListener      : Keys refreshed [config.client.version, echo.message.text]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To check that the configuration was updated, we can again curl the sayHello method of the medium service.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl &lt;a href="http://localhost:8080/sayHello" rel="noopener noreferrer"&gt;http://localhost:8080/sayHello&lt;/a&gt;&lt;br&gt;
Hello, Medium&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  References&lt;br&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://spring.io/projects/spring-cloud-bus/" rel="noopener noreferrer"&gt;Spring Cloud Bus Documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.spring.io/spring-cloud-config/docs/current/reference/html/" rel="noopener noreferrer"&gt;Spring Cloud Config Documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>springboot</category>
      <category>springcloud</category>
      <category>kafka</category>
    </item>
    <item>
      <title>Write Spring MVC Logger for log request and response</title>
      <dc:creator>Yegor Voronianskii</dc:creator>
      <pubDate>Mon, 18 Jan 2021 04:56:09 +0000</pubDate>
      <link>https://dev.to/vrnsky/write-spring-mvc-logger-for-log-request-and-response-5c9m</link>
      <guid>https://dev.to/vrnsky/write-spring-mvc-logger-for-log-request-and-response-5c9m</guid>
      <description>&lt;p&gt;Hello! In this article, I will explain how to write a logger for logging requests and responses. It would seem that there is nothing complicated about this, but if you look at the documentation, you can see the following&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flduixkiq5inayjgkmfyj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flduixkiq5inayjgkmfyj.png" alt="Alt Text" width="800" height="161"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Which tells us that we can read data only once and by calling either the getReader method or the getInputStream method. In order to get around this limitation, two special classes were invented &lt;a href="http://contentcachingrequetwrapper.java" rel="noopener noreferrer"&gt;ContentCachingRequetWrapper.java&lt;/a&gt; and ContentCachingResponseWrapper.java, which are just needed so that we can log the request data. In order to polish the data about requests and responses, we will implement a filter that will extend the OncePerRequestFilter.java class Let's call this our movie LoggingFilter and start writing it. First, let's declare an instance of our logger&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we declare all the MIME types that we want to log&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private static final List&amp;lt;MediaType&amp;gt; VISIBLE_TYPES = Arrays.asList(
      MediaType.valueOf("text/*"),
      MediaType.APPLICATION_FORM_URLENCODED,
      MediaType.APPLICATION_JSON,
      MediaType.APPLICATION_XML,
      MediaType.valueOf("application/*+json"),
      MediaType.valueOf("application/*+xml"),
      MediaType.MULTIPART_FORM_DATA
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we override the methods from the parent class&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest,
                                HttpServletResponse httpServletResponse,
                                FilterChain filterChain) 
                                throws ServletException, IOException {
  if (isAsyncDispatch(httpServletRequest)) {
      filterChain.doFilter(httpServletRequest, httpServletResponse);
  } else {
     doFilterWrapped(wrapRequest(httpServletRequest),
                     wrapResponse(httpServletResponse,
                     filterChain);
 }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, we check whether the call is asynchronous, and in this case we do not try to polish it, if the call is synchronous, then we try to wrap the logging Implementing the doFilterWrapped method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protected void doFilterWrapped(ContentCachingRequestWrapper contentCachingRequestWrapper, ContentCachingResponseWrapper contentCachingResponseWrapper, FilterChain filterChain) throws IOException, ServletException {
        try {
            beforeRequest(contentCachingRequestWrapper);
            filterChain.doFilter(contentCachingRequestWrapper, contentCachingResponseWrapper);
        } finally {
            afterRequest(contentCachingRequestWrapper, contentCachingResponseWrapper);
            contentCachingResponseWrapper.copyBodyToResponse();
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this method, we already receive a cached request and response and perform processing and post-processing of the request, and also copy the response data Let's write the request processing code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protected void beforeRequest(ContentCachingRequestWrapper request) {
    if (logger.isInfoEnabled()) {
        logRequestHeader(request, request.getRemoteAddr() + "|&amp;gt;");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We check the logging level and if it is equal to the INFO level, then we also log the request headers&lt;/p&gt;

&lt;p&gt;Let's write a post-processing method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protected void afterRequest(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response) {
        if (logger.isInfoEnabled()) {
            logRequestBody(request, request.getRemoteAddr() + "|&amp;gt;");
            logResponse(response, request.getRemoteAddr() + "|&amp;gt;");
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, we also check that the logging level is set to INFO before polishing the request and response. And finally, the most interesting thing, we write logging of headers, as well as requests and responses&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private static void logRequestHeader(ContentCachingRequestWrapper request, String prefix) {
        String queryString = request.getQueryString();
        if (queryString == null) {
            logger.info("{} {} {}", prefix, request.getMethod(), request.getRequestURI());
        } else {
            logger.info("{} {} {}?{}", prefix, request.getMethod(), request.getRequestURI(), queryString);
        }
        Collections.list(request.getHeaderNames()).forEach(headerName -&amp;gt;
                Collections.list(request.getHeaders(headerName)).forEach(headerValue -&amp;gt; logger.info("{} {} {}", prefix, headerName, headerValue)));
        logger.info("{}", prefix);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the logRequestHeader method, the following happens - from the request we get a string, check whether it is null and if null, then we code the HTTP method and the URL to which such a request came, otherwise the HTTP method is also logged, the URL to which the request came, and also all request headers Next, we need to write the code to log the request body&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private static void logRequestBody(ContentCachingRequestWrapper request, String prefix) {
    byte[] content = request.getContentAsByteArray();
    if (content.length &amp;gt; 0) {
        logContent(content, request.getContentType(), request.getCharacterEncoding(), prefix);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We receive data from the request as an array of bytes, and in the event that the size of the array is greater than zero, we pass the data to the logContent method, which we will write a little later.&lt;/p&gt;

&lt;p&gt;Now is the time to write the code for logging responses from the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private static void logResponse(ContentCachingResponseWrapper response, String prefix) {
    int status = response.getStatus();
    logger.info("{} {} {}", prefix, status, HttpStatus.valueOf(status).getReasonPhrase());
    response.getHeaderNames().forEach(header -&amp;gt; response.getHeaders(header).forEach(headerValue -&amp;gt; logger.info("{} {} {}", prefix, header, headerValue)));
    logger.info("{}", prefix);
    byte[] content = response.getContentAsByteArray();
    if (content.length &amp;gt; 0) {
        logContent(content, response.getContentType(), response.getCharacterEncoding(), prefix);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's figure out what exactly is happening here - with the first line we get the HTTP response code of our application and then log data about it. Next, we go through the response headers and log them in the same way. Further, the logic is quite similar to what we have seen before - we receive data from the response as an array of bytes and then pass it to the logContent method, which will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private static void logContent(byte[] content, String contentType, String contentEncoding, String prefix) {
        MediaType mediaType = MediaType.valueOf(contentType);
        boolean visible = VISIBLE_TYPES.stream().anyMatch(visibleType -&amp;gt; visibleType.includes(mediaType));
        if (visible) {
            try {
                String contentString = new String(content, contentEncoding);
                Stream.of(contentString.split("\r\n|\r\n")).forEach(line -&amp;gt; logger.info("{} {}", prefix, line));
            } catch (UnsupportedEncodingException e) {
                logger.info("{}, [{} bytes content]", prefix, content.length);
            }
        } else {
            logger.info("{}, [{} bytes content]", prefix, content.length);
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's going on here? First, we check if the type of the transmitted data is supported for doping, if not, then we simply display the size of the data array. If yes, then we get create a line from the data with the specified encoding in the request, and separate each line using carriage return and newline characters. If the encoding is not supported, then, as in the case of an unsupported data type, we simply log the size of the data that we received in the request or response&lt;/p&gt;

&lt;p&gt;And the final touch in our code is the two methods that are actually needed to wrap our HttpServletRequest and HttpServletResponse in ContentCachingRequestWrapper and ContentCachingResponseWrapper&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private static ContentCachingRequestWrapper wrapRequest(HttpServletRequest httpServletRequest) {
        if (httpServletRequest instanceof ContentCachingRequestWrapper) {
            return (ContentCachingRequestWrapper) httpServletRequest;
        } else {
            return new ContentCachingRequestWrapper(httpServletRequest);
        }
    }

    private static ContentCachingResponseWrapper wrapResponse(HttpServletResponse httpServletResponse) {
        if (httpServletResponse instanceof ContentCachingResponseWrapper) {
            return (ContentCachingResponseWrapper) httpServletResponse;
        } else {
            return new ContentCachingResponseWrapper(httpServletResponse);
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you need to register our filter in the deployment descriptor&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;filter&amp;gt;
    &amp;lt;filter-name&amp;gt;Filter&amp;lt;/filter-name&amp;gt;
    &amp;lt;filter-class&amp;gt;ru.skillfactory.filter.LoggingFilter&amp;lt;/filter-class&amp;gt;
&amp;lt;/filter&amp;gt;

&amp;lt;filter-mapping&amp;gt;
    &amp;lt;filter-name&amp;gt;Filter&amp;lt;/filter-name&amp;gt;
    &amp;lt;url-pattern&amp;gt;*&amp;lt;/url-pattern&amp;gt;
&amp;lt;/filter-mapping&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, make sure our filter is working properly&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2021-01-18 12:25:24 DEBUG RequestResponseBodyMethodProcessor:91 - Read "application/json;charset=ISO-8859-1" to [StudentData(firstName=John, lastName=Doe, grade=5)]
2021-01-18 12:25:24 DEBUG RequestResponseBodyMethodProcessor:265 - Using 'text/plain', given [*/*] and supported [text/plain, */*, application/json, application/*+json]
2021-01-18 12:25:24 DEBUG RequestResponseBodyMethodProcessor:91 - Writing ["You are great with your grade 5"]
2021-01-18 12:25:24 DEBUG DispatcherServlet:1131 - Completed 200 OK
2021-01-18 12:25:24 INFO  LoggingFilter:104 - 0:0:0:0:0:0:0:1|&amp;gt; {
    "firstName": "John",
    "lastName": "Doe",
    "grade": 5
}
2021-01-18 12:25:24 INFO  LoggingFilter:89 - 0:0:0:0:0:0:0:1|&amp;gt; 200 OK
2021-01-18 12:25:24 INFO  LoggingFilter:91 - 0:0:0:0:0:0:0:1|&amp;gt;
2021-01-18 12:25:24 INFO  LoggingFilter:104 - 0:0:0:0:0:0:0:1|&amp;gt; You are great with your grade 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full code of LoggingFilter.java&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;

public class LoggingFilter extends OncePerRequestFilter {

    private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
    private static final List&amp;lt;MediaType&amp;gt; VISIBLE_TYPES = Arrays.asList(
            MediaType.valueOf("text/*"),
            MediaType.APPLICATION_FORM_URLENCODED,
            MediaType.APPLICATION_JSON,
            MediaType.APPLICATION_XML,
            MediaType.valueOf("application/*+json"),
            MediaType.valueOf("application/*+xml"),
            MediaType.MULTIPART_FORM_DATA
    );

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        if (isAsyncDispatch(httpServletRequest)) {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
        } else {
            doFilterWrapped(wrapRequest(httpServletRequest), wrapResponse(httpServletResponse), filterChain);
        }
    }

    protected void doFilterWrapped(ContentCachingRequestWrapper contentCachingRequestWrapper, ContentCachingResponseWrapper contentCachingResponseWrapper, FilterChain filterChain) throws IOException, ServletException {
        try {
            beforeRequest(contentCachingRequestWrapper);
            filterChain.doFilter(contentCachingRequestWrapper, contentCachingResponseWrapper);
        } finally {
            afterRequest(contentCachingRequestWrapper, contentCachingResponseWrapper);
            contentCachingResponseWrapper.copyBodyToResponse();
        }
    }

    protected void beforeRequest(ContentCachingRequestWrapper request) {
        if (logger.isInfoEnabled()) {
            logRequestHeader(request, request.getRemoteAddr() + "|&amp;gt;");
        }
    }

    protected void afterRequest(ContentCachingRequestWrapper request, ContentCachingResponseWrapper response) {
        if (logger.isInfoEnabled()) {
            logRequestBody(request, request.getRemoteAddr() + "|&amp;gt;");
            logResponse(response, request.getRemoteAddr() + "|&amp;gt;");
        }
    }

    private static void logRequestHeader(ContentCachingRequestWrapper request, String prefix) {
        String queryString = request.getQueryString();
        if (queryString == null) {
            logger.info("{} {} {}", prefix, request.getMethod(), request.getRequestURI());
        } else {
            logger.info("{} {} {}?{}", prefix, request.getMethod(), request.getRequestURI(), queryString);
        }
        Collections.list(request.getHeaderNames()).forEach(headerName -&amp;gt;
                Collections.list(request.getHeaders(headerName)).forEach(headerValue -&amp;gt; logger.info("{} {} {}", prefix, headerName, headerValue)));
        logger.info("{}", prefix);
    }

    private static void logRequestBody(ContentCachingRequestWrapper request, String prefix) {
        byte[] content = request.getContentAsByteArray();
        if (content.length &amp;gt; 0) {
            logContent(content, request.getContentType(), request.getCharacterEncoding(), prefix);
        }
    }

    private static void logResponse(ContentCachingResponseWrapper response, String prefix) {
        int status = response.getStatus();
        logger.info("{} {} {}", prefix, status, HttpStatus.valueOf(status).getReasonPhrase());
        response.getHeaderNames().forEach(header -&amp;gt; response.getHeaders(header).forEach(headerValue -&amp;gt; logger.info("{} {} {}", prefix, header, headerValue)));
        logger.info("{}", prefix);
        byte[] content = response.getContentAsByteArray();
        if (content.length &amp;gt; 0) {
            logContent(content, response.getContentType(), response.getCharacterEncoding(), prefix);
        }
    }

    private static void logContent(byte[] content, String contentType, String contentEncoding, String prefix) {
        MediaType mediaType = MediaType.valueOf(contentType);
        boolean visible = VISIBLE_TYPES.stream().anyMatch(visibleType -&amp;gt; visibleType.includes(mediaType));
        if (visible) {
            try {
                String contentString = new String(content, contentEncoding);
                Stream.of(contentString.split("\r\n|\r\n")).forEach(line -&amp;gt; logger.info("{} {}", prefix, line));
            } catch (UnsupportedEncodingException e) {
                logger.info("{}, [{} bytes content]", prefix, content.length);
            }
        } else {
            logger.info("{}, [{} bytes content]", prefix, content.length);
        }
    }

    private static ContentCachingRequestWrapper wrapRequest(HttpServletRequest httpServletRequest) {
        if (httpServletRequest instanceof ContentCachingRequestWrapper) {
            return (ContentCachingRequestWrapper) httpServletRequest;
        } else {
            return new ContentCachingRequestWrapper(httpServletRequest);
        }
    }

    private static ContentCachingResponseWrapper wrapResponse(HttpServletResponse httpServletResponse) {
        if (httpServletResponse instanceof ContentCachingResponseWrapper) {
            return (ContentCachingResponseWrapper) httpServletResponse;
        } else {
            return new ContentCachingResponseWrapper(httpServletResponse);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you liked the article, then subscribe and share with your friends!&lt;br&gt;
Thanks for attention&lt;/p&gt;

</description>
      <category>spring</category>
      <category>java</category>
      <category>logging</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Write Simple Spring Boot for get currency rate</title>
      <dc:creator>Yegor Voronianskii</dc:creator>
      <pubDate>Tue, 08 Dec 2020 00:42:03 +0000</pubDate>
      <link>https://dev.to/vrnsky/write-simple-spring-boot-for-get-currency-rate-2hhh</link>
      <guid>https://dev.to/vrnsky/write-simple-spring-boot-for-get-currency-rate-2hhh</guid>
      <description>&lt;p&gt;Within the framework of this article, we will develop an application for receiving exchange rates from the central bank of Russia. The main technologies we will be using will be Java, Spring Boot, Docker, Vue&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Let's start by choosing the required method in the API of the central bank, which is allowed to get the current rates &lt;/li&gt;
&lt;li&gt;Next, let's add WSDL processing to the application so that we don't have to do it by hand &lt;/li&gt;
&lt;li&gt;We use Spring WebServices so that our application can skillfully request data from the API &lt;/li&gt;
&lt;li&gt;Add Swagger to the application &lt;/li&gt;
&lt;li&gt;Add some Vue frontend &lt;/li&gt;
&lt;li&gt;Connect Docker 
The first thing we need is, of course, to create an application - this can be done using the Spring Initializr or through IntelliJ IDEA.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The API method we'll be using from the central bank is called GetCursOnDateXML. Below you can see its description.&lt;/p&gt;

&lt;p&gt;In order not to describe the structure of requests and responses from the API ourselves, we will use plugins that will help turn WSDL into POJO. Listing pom.xml&lt;br&gt;
Let's check that the plugin really works and the classes we need are created - screen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;plugin&amp;gt; 
  &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;jaxws-maven-plugin&amp;lt;/artifactId&amp;gt;
  &amp;lt;version&amp;gt;2.6&amp;lt;/version&amp;gt;
  &amp;lt;executions&amp;gt;
    &amp;lt;execution&amp;gt;
      &amp;lt;id&amp;gt;generatewsdl&amp;lt;/id&amp;gt;
      &amp;lt;goals&amp;gt;
        &amp;lt;goal&amp;gt;wsimport&amp;lt;/goal&amp;gt;
     &amp;lt;/goals&amp;gt;
     &amp;lt;configuration&amp;gt;
        &amp;lt;vmArgs&amp;gt;
          &amp;lt;vmArg&amp;gt;-Djavax.xml.accessExternalSchema=all&amp;lt;/vmArg&amp;gt;
          &amp;lt;vmArg&amp;gt;-Djavax.xml.accessExternalDTD=all&amp;lt;/vmArg&amp;gt;
        &amp;lt;/vmArgs&amp;gt; &amp;lt;wsdlDirectory&amp;gt;${basedir}/src/main/resources/&amp;lt;/wsdlDirectory&amp;gt;  
    &amp;lt;args&amp;gt;
       &amp;lt;arg&amp;gt;-b&amp;lt;/arg&amp;gt;
       &amp;lt;arg&amp;gt;https://www.w3.org/2001/XMLSchema.xsd&amp;lt;/arg&amp;gt; 
    &amp;lt;/args&amp;gt;
 &amp;lt;wsdlFiles&amp;gt; &amp;lt;wsdlFile&amp;gt;${basedir}/src/main/resources/dailyinfo.wsdl&amp;lt;/wsdlFile&amp;gt;     &amp;lt;/wsdlFiles&amp;gt; 
        &amp;lt;/configuration&amp;gt; 
      &amp;lt;/execution&amp;gt; 
  &amp;lt;/executions&amp;gt;
&amp;lt;/plugin&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's add a web service that will be responsible for executing the request and response. Listing of creating a web service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Service
public class CBRService extends WebServiceTemplate {

     @Value("${cbr.url}")
     private String cbrApiUrl;     


     public List&amp;lt;ValuteCursOnDate&amp;gt; getCurrenciesFromCbr() throws DatatypeConfigurationException {
        final GetCursOnDateXML getCursOnDateXML = new GetCursOnDateXML();
        GregorianCalendar cal = new GregorianCalendar(); 
        cal.setTime(new Date());
        XMLGregorianCalendar xmlGregCal =  DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
        getCursOnDateXML.setOnDate(xmlGregCal);
        GetCursOnDateXmlResponse response = (GetCursOnDateXmlResponse) marshalSendAndReceive(cbrApiUrl, getCursOnDateXML);
        if (response == null) {   
          throw new IllegalStateException("Could not get response from CBR Service");        
        }
        final List&amp;lt;ValuteCursOnDate&amp;gt; courses = response.getGetCursOnDateXmlResult().getValuteData();
        courses.forEach(course -&amp;gt; course.setName(course.getName().trim()));
        return courses;    
}
    public ValuteCursOnDate getCurrencyFromCbr(String currencyCode) throws DatatypeConfigurationException {
        return getCurrenciesFromCbr()
             .stream()
             .filter(currency -&amp;gt; currencyCode.equals(currency.getChCode()))
             .findFirst().orElseThrow(() -&amp;gt; new RuntimeException("Could not find currency"));    
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, the MVP of the application is almost complete. Now let's add REST controllers so that we can send the received data from the third-party API outside. We will have one controller and two entry points - receiving all currencies, and receiving a specific currency at the moment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RestController
@RequestMapping(value = "/api")
@RequiredArgsConstructor
public class CurrencyController {
     private final CurrencyService currencyService;
     private final CBRService cbrService;

     @PostMapping(value = "/getCurrencyFromCbr")
     public List&amp;lt;ValuteCursOnDate&amp;gt; crbCurrencies() throws DatatypeConfigurationException {
        return cbrService.getCurrenciesFromCbr();
    }     
     @PostMapping(value = "/getCurrencyFromCbr/{currency}")     public ValuteCursOnDate crbOn(@PathVariable String currency) throws DatatypeConfigurationException {
        return cbrService.getCurrencyFromCbr(currency);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's add Swagger to our application so that all consumers of our API know the contracts for interacting with the system.In order to add Swagger, you need to add one dependency and write the configuration code. Let's check that Swagger actually works. However, we need a complete UI. To do this, let's add another dependency and make sure that everything worked correctly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
  &amp;lt;groupId&amp;gt;io.springfox&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;springfox-swagger2&amp;lt;/artifactId&amp;gt; 
  &amp;lt;version&amp;gt;2.6.1&amp;lt;/version&amp;gt;
  &amp;lt;scope&amp;gt;compile&amp;lt;/scope&amp;gt; 
&amp;lt;/dependency&amp;gt; 
&amp;lt;dependency&amp;gt; 
 &amp;lt;groupId&amp;gt;io.springfox&amp;lt;/groupId&amp;gt; 
 &amp;lt;artifactId&amp;gt;springfox-swagger-ui&amp;lt;/artifactId&amp;gt; 
 &amp;lt;version&amp;gt;2.6.1&amp;lt;/version&amp;gt; 
 &amp;lt;scope&amp;gt;compile&amp;lt;/scope&amp;gt;        
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have an API, but at the moment we can display currencies only in JSON form. Let's add a little frontend in Vue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div class="container"&amp;gt;
    &amp;lt;div class="row"&amp;gt;
      &amp;lt;div class="col-2"&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class="col-8"&amp;gt;
        &amp;lt;h1&amp;gt;Currency Rate&amp;lt;/h1&amp;gt;
        &amp;lt;span&amp;gt;на {{ today }}&amp;lt;/span&amp;gt;
        &amp;lt;table class="table"&amp;gt;
          &amp;lt;thead class="table-striped table-bordered"&amp;gt;
            &amp;lt;tr&amp;gt;
              &amp;lt;th scope="col"&amp;gt;Name&amp;lt;/th&amp;gt;
              &amp;lt;th scope="col"&amp;gt;Nominal&amp;lt;/th&amp;gt;
              &amp;lt;th scope="col"&amp;gt;Rate&amp;lt;/th&amp;gt;
              &amp;lt;th scope="col"&amp;gt;Digital code&amp;lt;/th&amp;gt;
              &amp;lt;th scope="col"&amp;gt;Alphabet code&amp;lt;/th&amp;gt;
            &amp;lt;/tr&amp;gt;
          &amp;lt;/thead&amp;gt;
          &amp;lt;tbody&amp;gt;
            &amp;lt;tr v-for="currency in currencies" :key="currency.name"&amp;gt;
              &amp;lt;td scope="row"&amp;gt;{{ currency.name }}&amp;lt;/td&amp;gt;
              &amp;lt;td scope="row"&amp;gt;{{ currency.nominal }}&amp;lt;/td&amp;gt;
              &amp;lt;td scope="row"&amp;gt;{{ currency.course }}&amp;lt;/td&amp;gt;
              &amp;lt;td scope="row"&amp;gt;{{ currency.code }}&amp;lt;/td&amp;gt;
              &amp;lt;td scope="row"&amp;gt;{{ currency.chCode }}&amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;
          &amp;lt;/tbody&amp;gt;
        &amp;lt;/table&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class="col"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
import CurrencyService from '@/service/CurrencyService'
export default {
  data() {
    return {
      currencies: [],
      today: new Date()
    }
  },
  created() {
    CurrencyService.getCurrencies()
      .then(response =&amp;gt; {
        this.currencies = response.data
      })
      .catch(error =&amp;gt; {
        console.log(error.response)
      })
  }
}
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we should add service instance for interact with our backend.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import axios from 'axios'

const apiClient = axios.create({
  baseURL: 'http://localhost:9091',
  withCredentials: false,
  headers: {
    Accept: 'application/json',
    'Content-Type': 'application/json'
  }
})

export default {
  getCurrencies() {
    return apiClient.post('/api/getCurrencyFromCbr')
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll also add Docker for our convenience. Our Dockerfile will look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM adoptopenjdk/openjdk11:latestARG JAR_FILE=/backend/target/*.jar
COPY ${JAR_FILE} /backend/currency-rate-vue-0.0.1-SNAPSHOT.jar
ENTRYPOINT ["java","-jar","/backend/currency-rate-vue-0.0.1-SNAPSHOT.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And last, but not least let's write unit test - for check that our app works correctly&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import ru.rbs.currency_vue.dto.CurrencyCreationResponse;
import ru.rbs.currency_vue.model.Currency;
import ru.rbs.currency_vue.model.CurrencyCode;

import java.math.BigDecimal;
import java.time.LocalDateTime;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
class CurrencyControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @Test
    public void testWhenWeAskAboutAllCurrenciesShouldCheckThatAllArePresent() throws Exception {
        mockMvc.perform(post("/api/getCurrencyFromCbr"))
                .andExpect(status().isOk())
                .andDo(print());
    }

    @Test
    public void testWhenWeAskAboutCurrencyShouldCheckThatIsPresent() throws Exception {
        mockMvc.perform(post("/api/getCurrencyFromCbr/USD"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.name").value("Доллар США"))
                .andExpect(jsonPath("$.nominal").value(1))
                .andExpect(jsonPath("$.course").exists())
                .andExpect(jsonPath("$.code").value("840"))
                .andExpect(jsonPath("$.chCode").value("USD"))
                .andDo(print());
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import ru.rbs.currency_vue.dto.ValuteCursOnDate;

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;

@SpringBootTest
class CBRServiceTest {

    @Autowired
    private CBRService cbrService;

    @Test
    public void testWhenWeTryToGetAllCurrenciesCollectionsShouldBeNotEmpty() throws Exception {
        List&amp;lt;ValuteCursOnDate&amp;gt; cursOnDateList = cbrService.getCurrenciesFromCbr();
        assertFalse(cursOnDateList.isEmpty());
    }

    @Test
    public void testWhenWeTryToGetOnlyOneCurrenciesShouldCheckThatWeCanGetIt() throws Exception {
        ValuteCursOnDate rubCursOnDate = cbrService.getCurrencyFromCbr("USD");
        assertNull(rubCursOnDate);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all for me, I hope you liked the article Write comments and subscribe&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Software Architecture #3. Final</title>
      <dc:creator>Yegor Voronianskii</dc:creator>
      <pubDate>Thu, 03 Dec 2020 05:01:35 +0000</pubDate>
      <link>https://dev.to/vrnsky/software-architecture-3-final-e3c</link>
      <guid>https://dev.to/vrnsky/software-architecture-3-final-e3c</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0v3evdmnskvp5octnmwz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0v3evdmnskvp5octnmwz.jpg" alt="Alt Text" width="254" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Software architecture design is one of the software architecture life-cycle activities. As in any software project life cycle, this activity is concerned with the translation of requirements into a design into an implementation. Specifically, the architect need to worry about the following issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architectural requirements. Among all requirements, a few will have a particular importance with respect to the software architecture. These architecturally significant requirements include not only most important functionality of the system and the constraints that need to be taken into account, but also - and most importantly quality attributes such as high performance, high availability, ease of evolution, and iron-clad security. These requirements, along with a clear design purpose and other architectural concerns that may never be written down or may be invisible to external stakeholders and components over another. &lt;/li&gt;
&lt;li&gt;Architectural design. Design is translation, from the world of need(requirements) to the world of solutions, in terms of structures composed of code, framework, and components. A good design is one that satisfies the drivers.&lt;/li&gt;
&lt;li&gt;Architectural documentation. Some level of preliminary documentation (or sketches) of the structures should be created as part of architectural design. This activity, however, refers to the creation of a more format document from these sketches. If the project is small and has a precedent, then architecture documentation may be minimal. In contrast, if the project is large, if distributed teams are collaborating, or if significant technical challenges exist, then architectural documentation will repay the effort invested in this activity. While documentation is often avoided and derided by programmers, it is a standard, non-negotiable deliverable in almost every other engineering discipline. If your system is big enough and if it is mission critical, it should be documented. In other engineering disciplines, a "blueprint" - some of sort of documented design - is an absolutely essential step in moving toward implementation and the commitment of resources&lt;/li&gt;
&lt;li&gt;Architectural evaluation. As with documentation, if your project is non-trivial, then you owe it to yourself and to your stakeholders to evaluate it - that is, to ensure that the decisions made are appropriate to address the critical requirements. Would you deliver code without testing? Of course, not. Similarly, why would you commit enormous resources to fleshing out an architecture if you had not first "tested" the design? You might want to do this when first creating the system or when putting it through a major refactoring. Typically evaluation is done informally and internally, but for try important projects it is advisable to have formal evaluation done by an external team&lt;/li&gt;
&lt;li&gt;Architectural implementation/conformance checking. Finally, you need to implement the architecture that you have created. As an architect, you may need to tweak the design as the system grows and requirements evolve. This is normal. In addition to this tweaking, your major responsibility during implementation is to ensure conformance of the code to the design. If developers are not faithfully implementing the architecture, the may be undermining the qualities that you have designed in. Again, consider what is done in other fields of engineering. When a concrete foundation for a new building is poured, the building that rests on top of that foundation is not constructed until the foundation has first been tested, typically vi a core sample, to ensure that it is wrong enough, dense enough, sufficiently impermeable to water  and gases, and so forth. Without conformance checking, we have no way of ensuring the quality of what is being subsequently constructed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzka411h9cwvfcwlvai52.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzka411h9cwvfcwlvai52.jpg" alt="Alt Text" width="626" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The role of architect
&lt;/h2&gt;

&lt;p&gt;An archives is much more that "just" a designer". This role may be played one or more individuals, has a long list of duties, skills and knowledge that must be satisfied if it to be successful. These prerequisites include the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Leadership: mentoring, team-building, establishing a vision, coach&lt;/li&gt;
&lt;li&gt;Communication: both technical and nontechnical, encouraging collaboration&lt;/li&gt;
&lt;li&gt;Negotiation: dealing with internal and external stakeholders and there conflicting needs and expectations&lt;/li&gt;
&lt;li&gt;Technical skills: life-cycle skills, expertise with technologies, continuous learning, coding&lt;/li&gt;
&lt;li&gt;Project skills: budgeting, personnel, schedule management, risk management&lt;/li&gt;
&lt;li&gt;Analytical skill: architectural analysis, general analysis mindset for project management and measurement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why is architectural design so important? There is a very high cost to a project of not making certain decisions, or not making them early enough. Without doing some architectural thinking and some early design work, you cannot confidently predict project cost, schedule, and quality. Without architecture, the benefits that the system is supposed to bring will be far harder to realise. If you do not make some key architectural decisions early and put if you allow architecture to degrade, you will be unable to maintain spring velocity, because you cannot easily respond to change requests. Such decisions may include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Selection of tools&lt;/li&gt;
&lt;li&gt;Structuring development environment&lt;/li&gt;
&lt;li&gt;Supporting releases&lt;/li&gt;
&lt;li&gt;DevOps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj2qljxoj7nr3ho49vj00.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj2qljxoj7nr3ho49vj00.jpg" alt="Alt Text" width="277" height="182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Architectural concerns
&lt;/h2&gt;

&lt;p&gt;Architectural concerns encompass additional aspects that need to be considered as part of architectural design but that are not expressed as rational requirements. There are several different types of concerns.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;General concerns. These are "broad" issues that one deals with in creating the architecture, such as establishing on overall system structure, the allocation of functionality to modules, the allocation of modules to team, organization of code base, startup and shutdown, and supporting delivery, deployment and updates.&lt;/li&gt;
&lt;li&gt;Specific concerns. These are more detailed system-internal issues such as exception management, dependency management, configuration, logging, authentication, authorisation, caching and so forth that are common across large numbers of applications. Some specific concerns are addressed in reference architectures, but other will be unique to your system. Specific concerns also result from previous design decisions. For example, you may need to address session management if you previously decided to use a reference architecture for the development of web applications.&lt;/li&gt;
&lt;li&gt;Internal requirements. These requirement are usually not specified explicitly in traditional requirement documents, such as customers usually seldom express them. Internal requirements may address aspects that facilitate development, deployment, operation, or maintenance of the system. They are sometimes called "derived requirements"&lt;/li&gt;
&lt;li&gt;Issues. These result from analysis activities, such as design review, so they may not be present initially. For instance, an architectural evaluation may uncover a risk that requires some changes to be performed in current design.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of the decisions surrounding architectural concerns might be trivial or obvious. For example, your deployment structure might be a single processor for an embedded system, or a single cell phone for an app. Your reference architecture might be constrained by company policy. Your authentication and authorisation policies might be dictated by your enterprise architecture and realised in a shared framework. In other cases, however, the decisions required to satisfy particular concerns may be less obvious - for example, in exception management or input validation or structuring code base.&lt;br&gt;
From their past experience, wise architects are usually aware of the concerns that are associated with a particular type of system and the need to make design decisions to address them. Inexperienced architects are usually less aware of such concerns; because these concerns tend to be tacit rather than explicit, the may not consider them as part of the design process, which often results in problem later or.&lt;br&gt;
Architectural concerns frequently result in the introduction of new quality attribute scenarios. The concerns of "supporting logging", for example, is too vague and need to be made more specific.&lt;/p&gt;

&lt;p&gt;The selection of externally developed components, which is a key aspect of the design process, can be a challenge task because of their extensive number. Here are few criteria you should cosied when selection externally developed components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Problem that it addresses. Is is something specific, such as framework for object oriented to relation mapping or something more generic, such as platform.&lt;/li&gt;
&lt;li&gt;Cost. What is the cost of the license, and if it is free, what is cost of support and education?&lt;/li&gt;
&lt;li&gt;Type of license. Does it have a license that is compatible with the project goals?&lt;/li&gt;
&lt;li&gt;Support. Is it well supported? Is there extensive documentation about the technology? Is there an extensive usr or developer community that you can turn for advice?&lt;/li&gt;
&lt;li&gt;Learning curve. How hard is to learn this technology. Have others in your organization already mastered it? Are these courses available?&lt;/li&gt;
&lt;li&gt;Maturity. Is it a technology that has just papered on the market, which may be exciting but still relatively unstable or unsupported?&lt;/li&gt;
&lt;li&gt;Popularity. Is it a relatively widespread technology? Are these positive testimonial or adoption by mature organisations? Will it be easy to hire people who have deep knowledge of it? Is there an active developer community or user group?&lt;/li&gt;
&lt;li&gt;Compatibility and ease of integration. Is it compatible with other technologies used in the project? Can it be integrated easily in project?
Support for critical quality attributes. Does it limit attributes such as performance? Is it secure and robust?&lt;/li&gt;
&lt;li&gt;Size. Will the use of the technology have negative impact of the size of the application under development&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftkd31fmhlp9mivvc6tg5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftkd31fmhlp9mivvc6tg5.jpg" alt="Alt Text" width="626" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In their paper "A General Model of Software Architecture Design Derived from Five Industrial Approaches", Holfmeister and her colleagues compared five industrial software architecture design methods and extracted from their commonalities a generic software architecture design approach.&lt;br&gt;
The derived general model consist of three main activities that are present in all five models reviewed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architectural analysis. In this activity, requirements (called concerns) and system context are used as inputs to determine set of architecturally significant requirements(ASR).&lt;/li&gt;
&lt;li&gt;Architectural synthesis. This activity is described as being the core of architecture design. It proposes architecture solution to a set of ASRs, moving from the problem to the solution space. The results of this activity are candidate architectural solutions, which are partial or complete architecture designs an include information about the rationale.&lt;/li&gt;
&lt;li&gt;Architectural evaluation. This activity ensures that the architectural decisions are the right ones. Candidate architectural solutions are measured agains ASRs. Several evaluations of different architectural solutions are expected, but the eventual result its the validated architecture.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Analysis is the process of breaking a complex entity into its constituent parts as a means of understanding it . The opposite of analysis is synthesis. Analysis and design are therefore inerwined actives. During the design process, the activity of analysis can refer to several aspects&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Studying the inputs to the design process to understand the problem whose solution you are about to design. &lt;/li&gt;
&lt;li&gt;Studying the alternative design concepts that you identified to solve a design problem so as to select the most appropriate one. In this situations, analysis forces you to provide concrete evidence for you choices.&lt;/li&gt;
&lt;li&gt;Ensuring the decisions made during the design process (or an iteration) are appropriate.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>architecture</category>
      <category>software</category>
    </item>
    <item>
      <title>Java Multithreading. Basics</title>
      <dc:creator>Yegor Voronianskii</dc:creator>
      <pubDate>Mon, 30 Nov 2020 02:26:10 +0000</pubDate>
      <link>https://dev.to/vrnsky/java-multithreading-basics-4cdc</link>
      <guid>https://dev.to/vrnsky/java-multithreading-basics-4cdc</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyij4jwm9g1j68gqdy2wt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyij4jwm9g1j68gqdy2wt.jpg" alt="Alt Text" width="599" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do you need multithreading
&lt;/h2&gt;

&lt;p&gt;In the distant past, computers did not have operating systems. They only executed one program from start to finish, and that program had direct access to all of the computer's resources. Not only was it difficult to write a program that would run on bare metal, but running only one program at a time proved to be an inefficient waste of computer resources.&lt;/p&gt;

&lt;p&gt;With the advent of operating systems, it became possible to run several programs at once. Programs were launched in a process - that is, an isolated, independent environment for which the operating system allocated resources such as memory, file descriptors.&lt;/p&gt;

&lt;p&gt;The need to develop operating systems with multithreading support was due to the following factors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Utilization of resources. Programs sometimes have to wait for some kind of third-party operation, such as input and output, and while we waited there was no opportunity to do some useful work.&lt;/li&gt;
&lt;li&gt;Equity in resource allocation. Many users and programs can have the same rights to computer resources. It is preferable to share all resources between them.&lt;/li&gt;
&lt;li&gt;Convenience. It is often easier and simpler to write several programs, each of which performs a different task and then coordinate them, than to write one program that does all the tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Simple thread safe counter
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Sequence {
   private int value;

   public synchronized int getNext() {
       return value++;
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This counter is thread safe because the getNext () method contains the synchronized keyword, which is used to ensure thread safety.&lt;/p&gt;

&lt;p&gt;That is, in this case, each thread that will call this method will receive the actual value. If any thread has not yet executed this method, another thread will be queued and wait for the first thread to complete.&lt;/p&gt;

&lt;p&gt;If many threads have access to variables that can change state, then your program is broken. There are three methods to fix this.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Restrict access to such variables &lt;/li&gt;
&lt;li&gt;Make states immutable&lt;/li&gt;
&lt;li&gt;Use sync to access state variables&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Atomicity
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Counter {
    private int long value;

    public int getNext() {
         return value++;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Race condition
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjw8ic7aujxmjxdrij76a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjw8ic7aujxmjxdrij76a.png" alt="Alt Text" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine meeting your friend at Starbucks near the university at 12 noon. But when you arrived, it turned out that there are two Starbucks and you are not sure which meeting will take place. At 12:10 you didn't see your friend at Starbucks A, so you decided to go to Starbucks B to check if your friend was there, but as it turned out, he was not there. There are the following outcomes&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your friend is late and is not at any of the Starbucks&lt;/li&gt;
&lt;li&gt;Your friend came to Starbucks A when you left to Starbucks B&lt;/li&gt;
&lt;li&gt;Your friend was at Starbucks B and was looking for you, but he didn't find him and went to Starbucks A&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's imagine the worst situation. At 12:15 pm, you visited both Starbucks. What will you do?&lt;/p&gt;

&lt;p&gt;Will you go back to Starbucks A? How many times are you going to go back there?&lt;/p&gt;

&lt;p&gt;Until the consistency protocol is developed, you both can spend all day walking between Starbucks.&lt;/p&gt;

&lt;p&gt;This variant of the race condition can also be called - check then action. You check for some condition, for example file X does not exist, and then perform an action based on the fact that the condition file X does not exist is true. But immediately after your check, the X file may appear, which leads to unexpected problems&lt;/p&gt;

&lt;p&gt;The most famous example of validation and then action is lazy initialization. The goal of lazy initialization is to create an object only when you really need it and another goal is to ensure that the object is initialized only once&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class LazyInitRace {
    private ExpensiveObject instance = null;

    public ExpensiveObject getInstance() {
        if (instance == null) {
           instance = new ExpensiveObject();
        }
        return instance;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (!vector.contains(element)) {
    vector.add(element);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do you think this code is thread safe?&lt;/p&gt;

&lt;p&gt;Answer: No. This attempt to put an item into a collection if there is no such item has a race condition, even if both add &amp;amp; contains methods are atomic. Methods with the synchronized keyword in their signature can do individual operations atomically, but additional synchronization is needed when both such methods are combined in some complex action. Do not overuse the synchronized keyword, as over-synchronization can lead to performance problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Volatile variables
&lt;/h2&gt;

&lt;p&gt;The Java language also provides weaker synchronization — volatile variables that update predictably for other threads. It is not recommended to use this synchronization mechanism, since the code obeying such a synchronization mechanism is fragile and difficult to understand at what moment locks are used.&lt;/p&gt;

&lt;p&gt;This type of variable is convenient, but it has certain limitations. Basically, variables marked volatile are used as completion flags, interrupt flags, or status flags. But it is important to understand that volatile does not guarantee that the increment will execute correctly (since the increment consists of three operations)&lt;/p&gt;

&lt;p&gt;Use volatile only in the following cases&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To describe variables that do not depend on their current value&lt;/li&gt;
&lt;li&gt;This variable does not participate in invariants with other state variables&lt;/li&gt;
&lt;li&gt;When accessing a variable, locking is not required for any other reason&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deadlock
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6k45mgw7tnq8e7wt1js1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6k45mgw7tnq8e7wt1js1.png" alt="Alt Text" width="674" height="439"&gt;&lt;/a&gt;&lt;br&gt;
Under deadlock, we mean the following situation: One thread is waiting for the lock taken by another thread to become available, while the first thread is waiting for the lock taken by the second thread to become available&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class TestDeadlockExample1 {  
  public static void main(String[] args) {  
    final String resource1 = "dev.to";  
    final String resource2 = "dev.architecture";  
    // t1 tries to lock resource1 then resource2  
    Thread t1 = new Thread() {  
      public void run() {  
          synchronized (resource1) {  
           System.out.println("Thread 1: locked resource 1");  

           try { Thread.sleep(150);} catch (Exception e) {}  

           synchronized (resource2) {  
            System.out.println("Thread 1: locked resource 2");  
           }  
         }  
      }  
    };  

    // t2 tries to lock resource2 then resource1  
    Thread t2 = new Thread() {  
      public void run() {  
        synchronized (resource2) {  
          System.out.println("Thread 2: locked resource 2");  

          try { Thread.sleep(150);} catch (Exception e) {}  

          synchronized (resource1) {  
            System.out.println("Thread 2: locked resource 1");  
          }  
        }  
      }  
    };  


    t1.start();  
    t2.start();  
  }  
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Starvation
&lt;/h2&gt;

&lt;p&gt;Fasting describes a situation where a thread cannot regularly access shared resources and cannot make progress. This occurs when shared resources become unavailable for extended periods due to greedy threads. For example, suppose an object provides a synchronized method that often takes a long time to return. If one thread calls this method frequently, other threads that also require frequent synchronized access to the same object will often block.&lt;/p&gt;

&lt;h2&gt;
  
  
  Livelock
&lt;/h2&gt;

&lt;p&gt;A thread often acts in response to the action of another thread. If the action of another thread is also a response to the action of another thread, then a live block may occur. As with the deadlock, blocked threads cannot move on. However, the threads are not blocked - they are simply too busy answering each other to resume work. This is comparable to two people trying to pass each other in the corridor: Andrey moves to the left to let Gregory pass, and Grigory moves to the right to let Andrey pass. Seeing that they are still blocking each other, Andrei moves to the right, and Gregory - to the left.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thread Synchronization and its Application
&lt;/h2&gt;

&lt;p&gt;Synchronization of threads is necessary in order to avoid the problems described above. There is a synchronized mechanism that allows threads to be synchronized&lt;/p&gt;

&lt;p&gt;Every object in Java has an Intrinsic Lock (monitor). When a synchronized method is called from a thread, it needs to get this monitor. The monitor will be released after the thread finishes executing the method. This way we can synchronize the block of instructions working with the object by forcing the threads to get the monitor before executing the block of instructions. Remember that the monitor can only be held by one thread at a time, so other threads wishing to receive it will be suspended until the current thread exits. Only then can a specific waiting thread get the monitor and continue execution.&lt;/p&gt;

</description>
      <category>java</category>
      <category>multithreading</category>
      <category>software</category>
      <category>programming</category>
    </item>
    <item>
      <title>Stop writing code in main method</title>
      <dc:creator>Yegor Voronianskii</dc:creator>
      <pubDate>Sat, 28 Nov 2020 07:19:50 +0000</pubDate>
      <link>https://dev.to/vrnsky/stop-writing-code-in-main-method-2bff</link>
      <guid>https://dev.to/vrnsky/stop-writing-code-in-main-method-2bff</guid>
      <description>&lt;p&gt;Greetings to everyone who reads this post! Due to my work, I often run into novice programmers and look at their code. Sometimes it is beautiful, sometimes not, but I understand that a person learns, and the further he masters the best practices and technologies, the better his code becomes. But I would still like to pay some attention to such a simple task that almost all novice programmers face - writing a calculator&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fea8u28gtpc7dz4iw8s3l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fea8u28gtpc7dz4iw8s3l.png" alt="Alt Text" width="500" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's what novice programmers write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.util.Scanner;

public class Calculator {
    public static void main(String[] args) {
        int sum = 0;
        int number1 = 0, number2 = 0;
        boolean correct = true;
        char operation1;
        Scanner sc = new Scanner(System.in);
        System.out.println("Enter first number:");
        while (!sc.hasNextInt()) {
            System.out.println("Sorry, it is not a digit. Try again, please");
            sc.next();
        }
        number1 = sc.nextInt();
        System.out.println("Thanks! You entered number: " + number1);
        System.out.println("Enter a number:");
        while (!sc.hasNextInt()) {
            System.out.println("It is not a digit. Try again");
            sc.next();
        }
            number2 = sc.nextInt();
        System.out.println("Thanks! It is a digit " + number2);
        do {
            correct = true;
            System.out.println("What would you like to do? + - / *");
            operation1 = sc.next().charAt(0);
            switch (operation1) {
                case '+':
                    sum = number1 + number2;
                    System.out.println("Sum of this two equals to " + sum);
                    break;
                case '-':
                    sum = number1 - number2;
                    System.out.println("The difference between equals to: " + sum);
                    break;
                case '/':
                    if (number2 != 0) {
                        sum = number1 / number2;
                        System.out.println("Divied equals to: " + sum);
                    } else {
                        System.out.println("Divided by zero is not allowed.");
                        correct = false;
                    }
                    break;
                case '*':
                    sum = number1 * number2;
                    System.out.println("Multiplication of this two: " + sum);
                    break;
                default:
                    System.out.println("Unknow operation");
                    correct = false;
                    break;
            }
            } while (correct != true);
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What problems do you see in this code? I see the following problems &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Everything is written in the main method, and certainly represents more than 10 lines &lt;/li&gt;
&lt;li&gt;There are no tests for this code, that is, there is no confidence that it will work correctly &lt;/li&gt;
&lt;li&gt;Structural programming style - the switch statement encourages this &lt;/li&gt;
&lt;li&gt;Using the Scanner, but it can be forgiven because it has convenient methods for getting numbers right away. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;How would you fix this code? I would fix the given code as follows &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Would create an Operation interface for all operations on numbers
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface Operation {
    int execute(int a, int b);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And accordingly I would implement this interface in the following classes&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Addition implements Operation {

    @Override
    public int execute(int a, int b) {
        return a + b;
    }
}

public class Deduction implements Operation {
    @Override
    public int execute(int a, int b) {
        return a - b;
    }
}

public class Division implements Operation {
    @Override
    public int execute(int a, int b) {
        return a / b;
    }
}

public class Multiplication implements Operation {
    @Override
    public int execute(int a, int b) {
        return a * b;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I would do the same with input and output methods, but before we start writing them, let's add a very useful library - Apache Commons&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.apache.commons&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;commons-lang3&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;3.11&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interface for the operation with input-output of information will look like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface IO {

    int getNumber(String message, String errorMessage);

    Operation getOperation(String message);

    void printResult(String result);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is how its implementation will look like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ConsoleIO implements IO {

    private final BufferedReader bufferedReader;
    private final List&amp;lt;String&amp;gt; allowedOperation;
    private Map&amp;lt;String, Operation&amp;gt; operationMap;

    public ConsoleIO(final List&amp;lt;String&amp;gt; allowedOperation) {
        this.bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        this.allowedOperation = allowedOperation;
        fullFillServiceMap();
    }

    @Override
    public int getNumber(String message, String errorMessage) {
        if (StringUtils.isNotBlank(message)) {
            System.out.println(message);
        }
        boolean validNumber = false;
        int numberResult = 0;
        while (!validNumber) {
            try {
                String line = bufferedReader.readLine();
                if (StringUtils.isNumeric(line)) {
                    numberResult = Integer.parseInt(line);
                    validNumber = true;
                }
            } catch (IOException e) {
                System.out.println(errorMessage);
                throw new RuntimeException(e);
            }
        }

        return numberResult;
    }

    @Override
    public Operation getOperation(String operationKey) {
        if (this.allowedOperation == null || this.allowedOperation.isEmpty()) {
            throw new IllegalStateException("Не заданы разрешенные операции");
        }
        boolean validOperation = false;
        while (!validOperation) {
            if (this.allowedOperation.contains(operationKey)) {
                validOperation = true;
            }
        }
        return operationMap.get(operationKey);
    }

    @Override
    public void printResult(String result) {
        System.out.println(result);
    }

    private void fullFillServiceMap() {
        this.operationMap = new HashMap&amp;lt;&amp;gt;();
        this.operationMap.put("+", new Addition());
        this.operationMap.put("-", new Deduction());
        this.operationMap.put("*", new Multiplication());
        this.operationMap.put("/", new Division());
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only thing left is to write the calculator itself, that is, the operation handler&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Calculator {

    private IO io;
    private Map&amp;lt;Integer, String&amp;gt; idOperationKeys;

    public Calculator(IO io) {
        this.io = io;
        fillMap();
    }

    public void launch() {
        boolean working = true;
        while (working) {
            int number = io.getNumber("1.Addition\n2.Substraction\n3.Multiplication\n4.Divison\n5.Exit", "Not valid number");
            if (number == 5) {
                working = false;
            } else {
              int result = 0;
                try {
                    result = io.getOperation(idOperationKeys.get(number))
                            .execute(
                                    io.getNumber("Enter first number", "Not valid number"),
                                    io.getNumber("Enter second number", "Not valid number")
                            );
                    io.printResult("The result of you operation equals to " + result);
                } catch (RuntimeException runtimeException) {
                    io.printResult(runtimeException.getMessage());
                }
            }
        }
    }

    private void fillMap() {
        idOperationKeys = new HashMap&amp;lt;&amp;gt;();
        idOperationKeys.put(1, "+");
        idOperationKeys.put(2, "-");
        idOperationKeys.put(3, "*");
        idOperationKeys.put(4, "/");
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well, in order for our program to finally work, we will edit the main method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class App {

    public static void main(String[] args) {
        new Calculator(
                new ConsoleIO(
                        Arrays.asList("+", "-", "*", "/")
                )
        ).launch();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My implementation does not claim to be the best solution, however I see several advantages in it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;This code is easier to write tests&lt;/li&gt;
&lt;li&gt;The code is open to add new functionality&lt;/li&gt;
&lt;li&gt;No dependencies on any implementation - we use abstraction for input and output of information&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's all for me, thanks for your attention!&lt;/p&gt;

&lt;p&gt;If you liked the article, share with your friends and like&lt;/p&gt;

&lt;p&gt;Subscribe and leave your comments&lt;/p&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>software</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Software Architecture #2</title>
      <dc:creator>Yegor Voronianskii</dc:creator>
      <pubDate>Mon, 23 Nov 2020 05:38:48 +0000</pubDate>
      <link>https://dev.to/vrnsky/software-architecture-2-3amf</link>
      <guid>https://dev.to/vrnsky/software-architecture-2-3amf</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy1j5k6v2abe8o2cgea28.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy1j5k6v2abe8o2cgea28.jpeg" alt="Alt Text" width="300" height="235"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My previous blogpost start from the house picture - as analogy about architecture. But I found some problems with this analogy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is no software construction industry in the same degree that there is for buildings. The building industry has substantial substructure, reflection numerous specialisations, skill sets, training paths, corporate organisations, standards bodies, and regulations. While the software industry has some structure, including that seen in offshore development practices, it is much less differentiated than the building industry&lt;/li&gt;
&lt;li&gt;The disciple off architecture does not have anything akin to the issue of deployment in software: Software is built in one place, but deployed for use in many places, often with specialisation and localisation. Manufactured building, otherwise known as trailers, are somewhat similar, but still there is no corresponding notion to dynamic distributed, mobile architectures, as there is with software&lt;/li&gt;
&lt;li&gt;Software is a machine; building are not (notwithstanding Le Corbusier's declaration that, "A house is machine for living in"). The dynamic character of software - the observation that led to Edsger Dijkstra's famous "&lt;strong&gt;goto&lt;/strong&gt; statement considers harmful" paper (Dijkstra 1968), provides a profoundly difficult challenge to designers, for which there is not counterpart in building design&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fundamental understanding
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3xyd1nwlwiw1hf7mcsla.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3xyd1nwlwiw1hf7mcsla.png" alt="Alt Text" width="800" height="591"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are three fundamental understandings of architecture, the recognition of which helps situate architecture with respect to rest of software engineering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every application has an architecture&lt;/li&gt;
&lt;li&gt;Every application has at least one architect&lt;/li&gt;
&lt;li&gt;Architecture is not a phase of development&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All applications do have architectures because they all result from key design decision.&lt;br&gt;
The architect is the person, or in most cases, group who makes the principal decisions about applications, who establishes and (it is hoped) maintains the foundational design.&lt;br&gt;
Architecture refers to the conceptual essence of an application, the principal decision regarding its design, the key abstractions that characterise the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcdi1i9as4xvnwe3hvnrt.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcdi1i9as4xvnwe3hvnrt.jpeg" alt="Alt Text" width="728" height="543"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Consideration of architecture rightly and properly begins at the outset of any software development activity. Notions of structure, design, and solution are quite appropriate during the requirements analysis activity.&lt;br&gt;
In waterfall model, indeed in most process models, the initial phase of activities is focused on developing the requirement for an application - the statement of what the application is supposed to do.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Existing design and architecture provide the vocabulary for talking about what might be&lt;/li&gt;
&lt;li&gt;Understanding of what works now, and how it works, affects our wants and perceived needs, typically in very solution-focused terms&lt;/li&gt;
&lt;li&gt;The insights from experiences with existing system helps imagine what might work and enable to assess, at an early stage, how long we must be willing to wait for it, and how much we will need to pay for it&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Design
&lt;/h2&gt;

&lt;p&gt;Designing is, by definition, the activity that creates a system's software architecture -its set of principal design decisions. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The traditional design phase is not exclusively "the place or the with" when a system's architecture is developed - for that happens over the course of development - but it is a time when particular emphasis is placed on architectural concerns.&lt;/li&gt;
&lt;li&gt;Since principal design decisions are made throughout development, designing must be seen as an spect of many other development activities&lt;/li&gt;
&lt;li&gt;Architectural decisions are of many different kinds, requiring a rich repertoire of design techniques&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The architect must deal, for example, with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stakeholder issues, such as choices concerning the use of proprietary, commercial off-the-shelf or open-source components, with their attendant and varying licensing obligation&lt;/li&gt;
&lt;li&gt;Over arching style and structure&lt;/li&gt;
&lt;li&gt;Types of connector for composing subelements&lt;/li&gt;
&lt;li&gt;Package and primary class structure(this, is low-level style and structure when working in an object-oriented development context)&lt;/li&gt;
&lt;li&gt;Distributed and decentralised system concerns&lt;/li&gt;
&lt;li&gt;Deployment issues&lt;/li&gt;
&lt;li&gt;Security and other nonfunctional properties&lt;/li&gt;
&lt;li&gt;Post-implementation issues (means for supporting upgrade and adoption)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Design techniques
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Object-oriented design
&lt;/h4&gt;

&lt;p&gt;Object-oriented design (OOD) is usually tight in the context of object-oriented programming, that is, reduction of an algorithm to machine-executable form. The essence of OOD is the identification of so-called objects, which are encapsulations of state with function for accessing and manipulation that state. Numerous variations are found in different object-oriented programming languages regarding the way object are specified, related to one another, created destroyed, and so on.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OOD views all application as consisting, solely, of one software species (namely, "object"), regardless of purpose. Forcing all concepts and entities int a single mold can obfuscate important differences. The REST style, for instance, maintains distinct notions of "user agent", "origin-server", and "cache". Apart from using programming language types to try characterise these distinct elements, OOD does not offer any helpful modelling mechanism.&lt;/li&gt;
&lt;li&gt;OOD provides only one kind of encapsulation (the object), one notion of interface, one type of explicit connector (procedure call), no real notion of structure (objects are constantly created and destroyed), and no notion of required interfaces. This implies that all richness of a given solution approach has to be mapped down or transformed to this level of single choice. Some architectures such as pipe-and-filter-may not be at all effective after such transformation&lt;/li&gt;
&lt;li&gt;OOD is so closely related to programming language concerns and choices that it tends to have the forest obscured by the Rees. For instance, the vagaries of type inheritance may obscure identification of principal objects critical to the design. Similarly, it is so bound with programming language issues that the language may start dictating what the important decisions are.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Domain-Specific Software Architectures
&lt;/h4&gt;

&lt;p&gt;This approach known as domain specific software architecture, is appropriate when prior experience and prior architectures are able to strongly influence new projects. The key notion is that if a developer or company has worked within particular application domain for many years, it is likely that a best approach or best general solution for application within that domain will have been identified. Future application in that domain can leverage this knowledge, whit those application having their fundamental architecture determined by the architecture of the past generation applications. The technical essence of the domain-specific software engineering approach is to capture and characterise the best solutions and the best practices from past projects within domain in such a way that production of new applications can focus more or less exclusively on the points of novel variation.&lt;br&gt;
To effectively follow the DSSA approach, good technical support is required: The architecture of the previous generation of application must be capture and refined for reuse; the points of allowable variation must be identified and isolated, the interfaces between the points of variation and the core architecture must be made explicit, the dependencies between multiple points of variation must be identified, and so on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation and implementation strategies
&lt;/h2&gt;

&lt;p&gt;The task of the implementation activity is to create machine-executable source code that is faithful to the architecture and that fully develops all outstanding details of the applications. This is true whether speaking from the perspective of classical forward engineering or from the software architecture-centric view of software engineering.&lt;br&gt;
First, the implementation activity may add to or modify the architecture - if key design decisions are made while working with the source code, they are part of the architecture as much as any principal decision made much earlier in the process. Second, there is no presumption that architecture is completed before implementation begins. &lt;br&gt;
The source code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Must not utilise major new computation elements that have no corresponding elements in the architecture&lt;/li&gt;
&lt;li&gt;Must not contain new connection between elements of the architecture (for example, such as might be motivated by efficiency concerns) that are not found in the architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The implementation does have an architecture: It is latent, as opposed to what is documented.&lt;br&gt;
Failure to recognize this distinction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Robs one of the ability to reason about the implemented application's architecture in the future.&lt;/li&gt;
&lt;li&gt;Misleads all stakeholders regarding what they believe they have as opposed to what they really have&lt;/li&gt;
&lt;li&gt;Makes any development or evolution strategy that is based on documented but inaccurate architecture doomed to failure&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Analysis and testing
&lt;/h2&gt;

&lt;p&gt;Analysis and testing are activities undertaken to asses the qualities of an artifact. One of the virtues of conduction analysis before code exists is cost savings: The earlier an error is detected and corrected, the lower the aggregate cost.&lt;br&gt;
First, the structural architecture of an application can be examined for consistency, correctness, and exhibition of desired nonfunctional properties. If the architecture upon which the implementation is (later) based is of high quality, the prospects for a high-quality implementation are significantly raised&lt;br&gt;
Second, the architectural model may be examined for consistency with requirements. Regardless of whether the requirements were developed in the classical way (that is, before any development solution notions).&lt;br&gt;
Third, the architectural model may be used in determining and supporting analysis and testing strategies applied to the source code&lt;br&gt;
Fourth, there architectural model can be compared to a model derived from the source code of an application. This is a form checking your answer. &lt;/p&gt;

&lt;h2&gt;
  
  
  Evolution and maintenance
&lt;/h2&gt;

&lt;p&gt;Software evolution and software maintenance - the terms are synonymous - refer to all manner of activities that chronologically follow the release of an application. There range from bug fixes to major additions of new functionality to creation of specialised version of the application for specific markets or platforms.&lt;br&gt;
The typical software engineering approach to maintenance is largely ad hoc. In a best-practices situation, each type of change cause the software process to return to whatever point. Thus, if new functionality is requested, the requires returning the requirements analysis phase and then moving forward sequence from there. &lt;/p&gt;

&lt;h2&gt;
  
  
  The design process
&lt;/h2&gt;

&lt;p&gt;The typical assumption of software design is that the process can proceed in general manned of architectural design or engineering design, which can be summarised (Jones 1970) as consisting of the following four stages&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Feasibility stage: Identifying a set of feasible concepts&lt;/li&gt;
&lt;li&gt;Preliminary design stage: Selection and development of the best concept&lt;/li&gt;
&lt;li&gt;Detailed design stage: Development of engineering description of the concept&lt;/li&gt;
&lt;li&gt;Planning stage: Evaluation and altering the concept to suit the requirements of production, distribution, consumption and product retirement&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>java</category>
      <category>software</category>
      <category>architecture</category>
      <category>programming</category>
    </item>
    <item>
      <title>Software Architecture</title>
      <dc:creator>Yegor Voronianskii</dc:creator>
      <pubDate>Sun, 22 Nov 2020 08:00:34 +0000</pubDate>
      <link>https://dev.to/vrnsky/software-architecture-1k7e</link>
      <guid>https://dev.to/vrnsky/software-architecture-1k7e</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frpm5oszc1weogwc7o2d9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frpm5oszc1weogwc7o2d9.jpg" alt="Alt Text" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Introduction&lt;br&gt;
In this article, I will try to explain what architecture and clean architecture is, and architecture's role in projects.&lt;/p&gt;

&lt;p&gt;Examples of web architecture application&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftulofphvlpo28ngrfrao.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftulofphvlpo28ngrfrao.jpeg" alt="Alt Text" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's consider an example of a service with one architectural level (Single Tier)&lt;/p&gt;

&lt;p&gt;In an application with one architectural level, the user interface, business logic, that is, the backend part of the application and the database are on the same server&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgw5b65ldm2s3j020vfwk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgw5b65ldm2s3j020vfwk.jpeg" alt="Alt Text" width="800" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An example of an application with one architectural level are applications such as MS Office, GIMP&lt;/p&gt;

&lt;p&gt;Benefits of using a single-layer architecture&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Very little or no delay in the interaction of components due to the fact that the components are located on the same server&lt;/li&gt;
&lt;li&gt;Although it largely depends on the machine's power and software hardware requirements, to measure the real performance of a single-tier application&lt;/li&gt;
&lt;li&gt;In addition, the user's data remains on his machine and does not need to be transferred over the network. This ensures data security at the highest level. Client data cannot be intercepted, since data exchange will occur within the same server&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Disadvantages of this architecture&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The impossibility of changing the code or functions after delivery to the production server. For example, in the 90s, if the game was shipped with an erroneous code, the studios could do nothing&lt;/li&gt;
&lt;li&gt;Code in peer-to-peer applications is also vulnerable to rework and reversal. Business security is minimal, because in the case of reverse engineering, an attacker or competitor can gain access to your codebase, which can lead to financial losses. Example - your application works with finances, attackers have exposed part of your system's code and can now bypass some of your checks and thus use your application for fraud&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Two-tier architecture
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fg6gnaiojx8vyxbf0r2qw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fg6gnaiojx8vyxbf0r2qw.jpg" alt="Alt Text" width="800" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A two-tier application includes a client and a server. The client will contain the user interface and business logic on the same machine. And the server will be a backend application deployed on another computer.&lt;/p&gt;

&lt;p&gt;There are times when you need to use a two-tier architecture, such as to-do list applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Three-tier architecture
&lt;/h3&gt;

&lt;p&gt;Three-tier architecture is quite popular and often used. Most simple websites like blogs, news sites use this architecture&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuhz1m7br2iejbido1y5e.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuhz1m7br2iejbido1y5e.jpg" alt="Alt Text" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's consider an example of a simple blog - the client interface will be written using HTML, JavaScript, CSS and the backend application will be launched on a server, for example Apache, and the backend part will use the PostgreSQL database as storage&lt;/p&gt;

&lt;h3&gt;
  
  
  N-tier architecture
&lt;/h3&gt;

&lt;p&gt;This term is used to describe an architecture that uses more than three components. Examples of these components&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cache - an example of this technology JCache, Caffeine. This technology is used for the following things - 1. Reduce the response time from the application without requesting any data in the database, 2. Also save some responses from third-party systems, since this can take a very long time&lt;/li&gt;
&lt;li&gt;Message broker - examples are Apache Kafka, RabbitMQ. This tool is necessary to save any messages, a message can mean some kind of request to a third-party system, for example, in Kafka you can store messages that will have to be sent to the tax system or the fiscal data operator&lt;/li&gt;
&lt;li&gt;Load balancer - examples are Nginx, Ribbon, Eureka. This tool is required to distribute the load on the application. Imagine the following situation - you have a distributed application, which means there are several instances or nodes, and in order to optimize the speed for the end user, all requests go through the balancer, which chooses a less loaded instance / node&lt;/li&gt;
&lt;li&gt;Search services - to search for information in huge amounts of data&lt;/li&gt;
&lt;li&gt;Components responsible for processing data arrays&lt;/li&gt;
&lt;li&gt;Components using heterogeneous technologies, commonly known as web services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All modern social applications - Instagram, Facebook and scalable services like Uber, Airbnb, as well as games with a huge number of players like Pokemon Go, for example, use an N-tier architecture&lt;/p&gt;

&lt;h3&gt;
  
  
  Clean architecture
&lt;/h3&gt;

&lt;p&gt;The center of your application is not the database. An architecture is also not one or more frameworks that you can use. The center of your app is the use cases for your app. The center of the application is the functionality for which the business gets paid, that is, what problem / what value does your application bring to the business - this place is the center of the application&lt;/p&gt;

&lt;p&gt;Clean architecture is a set of practices, techniques, design patterns that enable you to create an extensible and reliable application. Designed to prevent the following problems that may arise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decisions are made very quickly - hasty decisions can lead to problems when the application is on the production server&lt;/li&gt;
&lt;li&gt;Difficult to make changes&lt;/li&gt;
&lt;li&gt;Stuck on a certain framework - one day an organization / person may decide that he / she does not have the strength to support this framework. Accordingly, you should not be strongly tied to the framework&lt;/li&gt;
&lt;li&gt;Focusing only on technical aspects - it is important to understand that when developing, you should focus not only on technical aspects, but also on what business value the development of new functionality will bring&lt;/li&gt;
&lt;li&gt;It's hard to find the right places in the project&lt;/li&gt;
&lt;li&gt;Business logic is scattered throughout the code - if some requirements change, the programmer will have to find all the places in the code and change the functionality in each place. If the business logic is isolated in one place, then the programmer only needs to change the code in one place&lt;/li&gt;
&lt;li&gt;Lack of tests&lt;/li&gt;
&lt;li&gt;Infrequent updates
Clean architecture also provides the following benefits when used&lt;/li&gt;
&lt;li&gt;Effective testing strategy&lt;/li&gt;
&lt;li&gt;Code for using frameworks is isolated&lt;/li&gt;
&lt;li&gt;Database independence&lt;/li&gt;
&lt;li&gt;All business logic is contained in the application use cases&lt;/li&gt;
&lt;li&gt;Hard to do wrong&lt;/li&gt;
&lt;li&gt;The application is always ready for output to the production
environment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fex7iwwba2ocgd2y3hcvq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fex7iwwba2ocgd2y3hcvq.png" alt="Alt Text" width="800" height="600"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fex7iwwba2ocgd2y3hcvq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fex7iwwba2ocgd2y3hcvq.png" alt="Alt Text" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's analyze these figures in more detail:&lt;/p&gt;

&lt;p&gt;The core of the application is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Entities representing the domain area or subject area. Subject area for payment gateway application - Internet finance&lt;/li&gt;
&lt;li&gt;At this level is the code that is applicable to the entire object as a whole (for example, checking the format of the hostname)&lt;/li&gt;
&lt;li&gt;Java Plain Objects: no frameworks or annotations required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Core:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Represents the business actions of your application - this is what your application can do.&lt;/li&gt;
&lt;li&gt;Pure business logic, Java code without using any frameworks, but using utilitarian libraries such as Apache Commons&lt;/li&gt;
&lt;li&gt;Defines the interfaces for the data that are needed to apply the logic. One or more data providers implement the interface, but in case of use it is not known where the data is coming from&lt;/li&gt;
&lt;li&gt;At this level, business exceptions are thrown - exceptions that are directly related to the application domain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Data providers (dataproviders):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Receiving and storing data from multiple sources of information (database, network devices, file system, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Application entrypoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This application layer describes the way to interact with the application and usually includes a delivery mechanism (for example, REST API, scheduled tasks, GUI, other systems)&lt;/li&gt;
&lt;li&gt;Launching a use case and converting the result into a format that matches the delivery mechanism&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Configuration&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connects all components together&lt;/li&gt;
&lt;li&gt;Dependency Injection is isolated here&lt;/li&gt;
&lt;li&gt;Contain "dirty details" - such as Main class, web server configuration, database configuration, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fimzgb7rlhtu01z1u78zh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fimzgb7rlhtu01z1u78zh.png" alt="Alt Text" width="800" height="600"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fimzgb7rlhtu01z1u78zh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fimzgb7rlhtu01z1u78zh.png" alt="Alt Text" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Architectural Application Templates
&lt;/h1&gt;

&lt;p&gt;An architectural pattern is a repetitive and generic solution to a problem arising from an application architecture problem within a given context.&lt;/p&gt;

&lt;p&gt;Let's take a look at 10 popular architectural patterns&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multilevel&lt;/li&gt;
&lt;li&gt;Client - server&lt;/li&gt;
&lt;li&gt;Leading - slave&lt;/li&gt;
&lt;li&gt;Channels and filters&lt;/li&gt;
&lt;li&gt;Mediator template&lt;/li&gt;
&lt;li&gt;Peer-to-peer template&lt;/li&gt;
&lt;li&gt;Event bus&lt;/li&gt;
&lt;li&gt;Model - View - Controller&lt;/li&gt;
&lt;li&gt;Board&lt;/li&gt;
&lt;li&gt;Interpreter&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Multilevel
&lt;/h3&gt;

&lt;p&gt;It is used to structure programs that can be decomposed into groups of certain subtasks located at certain levels of abstraction. Each layer provides services for the next higher layer.&lt;/p&gt;

&lt;p&gt;Most often, there are 4 layers in common information systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Presentation layer (also known as user interface layer)&lt;/li&gt;
&lt;li&gt;Application layer (also known as service layer)&lt;/li&gt;
&lt;li&gt;Business logic layer (also known as domain layer)&lt;/li&gt;
&lt;li&gt;Data access layer (also known as data storage layer)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Common desktop applications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Web applications e-commerce.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Client - Server
&lt;/h3&gt;

&lt;p&gt;This template consists of two parts: server and many clients . The server component provides services to the client components. Clients request services from the server, and it, in turn, provides these very services to clients. Moreover, the server continues to "eavesdrop" on client requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Online applications (email, document sharing, banking).&lt;/p&gt;

&lt;h3&gt;
  
  
  Master - Slave
&lt;/h3&gt;

&lt;p&gt;This pattern also involves two participants - master and slaves. The Leader distributes tasks to identical Followers and calculates the final result based on the results received from its "Subordinates".&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In database replication. There, the main database is considered an authoritative source, and the subordinate databases are synchronized with it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Peripheral devices connected to the bus in the computer (master and slave devices).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Channels and Filters
&lt;/h3&gt;

&lt;p&gt;This pattern is suitable for systems that generate and process data streams. Each processing step takes place inside a filter component. Data for processing is transmitted via channels. These channels can be used to buffer or synchronize data.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;· Compilers. Sequential filters perform lexical, parsing, semantic analysis, and code generation.&lt;/p&gt;

&lt;p&gt;· Workflows in bioinformatics.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mediator template
&lt;/h3&gt;

&lt;p&gt;This pattern is needed to structure distributed systems with disconnected components. These components can communicate with each other through a remote service call. The mediator component is responsible for coordinating the interaction of components.&lt;/p&gt;

&lt;p&gt;The server hosts its capabilities (services and characteristics) with an intermediary (broker). The client requests a service from the broker. The broker then redirects the client to the appropriate service from its registry.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;· Message brokers by type &lt;a href="https://en.wikipedia.org/wiki/Apache_ActiveMQ" rel="noopener noreferrer"&gt;Apache ActiveMQ&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Apache_Kafka" rel="noopener noreferrer"&gt;Apache Kafka&lt;/a&gt;,  &lt;a href="https://en.wikipedia.org/wiki/RabbitMQ" rel="noopener noreferrer"&gt;RabbitMQ&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/JBoss_Messaging" rel="noopener noreferrer"&gt;JBoss Messaging&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Peer-to-peer template
&lt;/h3&gt;

&lt;p&gt;There are separate components in this template, the so-called  peers. Peers can act as a client requesting services from other peers (peers), and a server providing services to other peers. A peer can be a client or a server, or all at once, and can dynamically change its role over time.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;· File sharing networks (&lt;a href="https://en.wikipedia.org/wiki/Gnutella" rel="noopener noreferrer"&gt;Gnutella&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Gnutella2" rel="noopener noreferrer"&gt;G2&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;· Multimedia Protocols (&lt;a href="https://en.wikipedia.org/wiki/P2PTV" rel="noopener noreferrer"&gt;P2PTV&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Peer_Distributed_Transfer_Protocol" rel="noopener noreferrer"&gt;PDTP&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;· Proprietary multimedia applications (like the same &lt;a href="https://en.wikipedia.org/wiki/Spotify" rel="noopener noreferrer"&gt;Spotify&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Event Bus
&lt;/h3&gt;

&lt;p&gt;This template mainly interacts with events and has 4 main components: event source, event listener, channel and event bus. Sources place messages for specific channels on the event bus. Listeners subscribe to specific channels. Listeners are notified of the appearance of messages posted on channels from their subscription.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Android development&lt;/p&gt;

&lt;p&gt;Notification services&lt;/p&gt;

&lt;h3&gt;
  
  
  Model - View - Controller
&lt;/h3&gt;

&lt;p&gt;This pattern is also known as the MVC pattern. It divides interactive applications into 3 parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;model - contains key data and functionality;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;view - shows information to the user (more than one view can be specified);&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;controller - deals with the processing of data from the user.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is done in order to differentiate the internal presentation of information from the way it is presented and received from the user. This design isolates components and allows for efficient code reuse.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;· Architecture of WWW-applications written in the main programming languages.&lt;/p&gt;

&lt;p&gt;· Web frameworks (for example, &lt;a href="https://en.wikipedia.org/wiki/Django_%28web_framework%29" rel="noopener noreferrer"&gt;Django&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/%20wiki%20/%20Ruby_on_Rails" rel="noopener noreferrer"&gt;Rails&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  Board
&lt;/h3&gt;

&lt;p&gt;This pattern is suitable for problems for which there are no clear deterministic solutions. The Board template has 3 main components:&lt;/p&gt;

&lt;p&gt;· board is a structured global memory containing objects from the space of possible solutions;&lt;/p&gt;

&lt;p&gt;· source of knowledge - specialized modules with their own presentation;&lt;/p&gt;

&lt;p&gt;· control components - selects, configures and executes modules.&lt;/p&gt;

&lt;p&gt;All components have access to the board. Components can produce new data objects that are added to the board. Components look for specific kinds of data on the board. One way to search is to match patterns against an existing source of knowledge.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;· speech recognition;&lt;/p&gt;

&lt;p&gt;· Identification and tracking of vehicles;&lt;/p&gt;

&lt;p&gt;· Determination of protein structures;&lt;/p&gt;

&lt;p&gt;· Interpretation of signals Sonar.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interpreter
&lt;/h3&gt;

&lt;p&gt;It is suitable for developing a component that must interpret programs written in a special programming language. Basically, it describes how to evaluate strings (in other words: "sentences" or "expressions") written in some particular programming language. The point is to assign a class to each character in the language.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;· Languages ​​of queries to the database (SQL);&lt;/p&gt;

&lt;p&gt;· Languages ​​that are used to describe data transfer protocols.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Comparison of architectural patterns&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Below are the pros and cons of each of the architectural patterns.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Layered Template&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One low layer can be used by different layers of a higher rank.&lt;/li&gt;
&lt;li&gt;Layers make standardization easier because we clearly define the levels.&lt;/li&gt;
&lt;li&gt;Changes are made within one layer, while the other layers remain unchanged.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not universal.&lt;/li&gt;
&lt;li&gt;In some situations it is possible to skip some layers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Client / Server Template&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A set of services that clients can request is suitable for modeling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requests are usually executed in separate threads on the server.&lt;/li&gt;
&lt;li&gt;Interaction between processes increases resource consumption, because different clients have different views.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Master-Follower Template&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accuracy, because service execution is delegated to different slaves with different implementations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All slaves are isolated, they have no general condition.&lt;/li&gt;
&lt;li&gt;The waiting period in the master-slave communication is a significant disadvantage. For example, in real time systems.&lt;/li&gt;
&lt;li&gt;Suitable only for those problems whose solution can be decomposed into parts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Template "Channels and Filters"&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They can implement parallel processes, when input and output consist of streams, and filters begin calculations after receiving data.&lt;/li&gt;
&lt;li&gt;Simple addition of filters. The system can be easily expanded.&lt;/li&gt;
&lt;li&gt;Filters are suitable for reuse. They can build different pipelines, creating all kinds of combinations of the existing set of filters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The efficiency is reduced by the slowest filtration processes. When moving from one filter to another, data transformation is performed, which leads to increased resource consumption.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Mediator Template&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is possible to dynamically change, add, delete and move objects. This pattern makes the distribution process transparent to the developer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Need to standardize service descriptions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Peer-to-Peer Template&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supports decentralized computing. Extremely resilient to failures at any node.&lt;/li&gt;
&lt;li&gt;High scalability in terms of resource and computing power.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is no guarantee of the quality of services; nodes cooperate spontaneously.&lt;/li&gt;
&lt;li&gt;It is difficult to guarantee security.&lt;/li&gt;
&lt;li&gt;Performance depends on the number of nodes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Event Bus Template&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easily add new subscribers, publishers and connections. Works well for highly distributed applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Problem with scalability, because all messages go through one event bus.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Model-View-Controller Template&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Facilitates the creation of different representations of the same model; they can be enabled or disabled at run time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The complexity of the algorithm increases. Can lead to many unnecessary adjustments to user actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Board Template&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy adding of new applications.&lt;/li&gt;
&lt;li&gt;You can easily expand the data space structures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Editing data structures is really difficult because such changes affect all applications.&lt;/li&gt;
&lt;li&gt;Synchronization and access control may be required.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Template "Interpreter"&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Highly dynamic behavior possible.&lt;/li&gt;
&lt;li&gt;An excellent solution for end users in terms of programming convenience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance problems as an interpreted language is slower than a compiled one.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>architecture</category>
      <category>software</category>
      <category>java</category>
    </item>
  </channel>
</rss>
