Clean code in Spring ecosystem
Tags: kotlin, codequality, architecture, refactorit
Published: 2020-04-03 20:06:53

I work a lot with Spring components including Spring Boot and Spring Cloud. There is a reason for it and I want to share it with you.
<br>I pose a lot of questions to myself about the design and architecture of the code I write besides _how to implement this solution_. The reason for it is caring about future engineer work within a project.
<br>Certainly, a lot of programmers have this kind of attitude. We ask questions regarding modularity like:
* How to make changes easier in the future?
* Should I make it reusable? How can I do it?
* Is there any ready to use solution from our tech stack?
* How to test future changes easier?
* Is there any way to make existed code more consistently and uniformly?

I think the most important question is how to make it shareable with other developers who could use this solution. The way we solve it is by decomposing current code modules.
<br>Spring framework provides an opportunity to make your design lose coupling and there is more material than requires about it online. But I'd like to show you the way you can reach it without academic knowledge.

### **Problem**
I wrote a [Medium story](https://medium.com/@art.ptushkin/image-proxy-server-based-on-spring-cloud-gateway-filters-c1afdab271b0) about how I'd been choosing a solution for images processing. It could help you to get the reasoning below.
<br>Long story short, I developed a gateway server for images processing and by the way, a made proxy server on implementing Spring Cloud Gateway.
You can find [the code at the GitHub repository.](https://github.com/artemptushkin/proxy-image)

### **Implementation**
I've started writing a standalone gateway service on purpose to figure out how Spring Cloud Gateway works.
The only need here is to have this dependency at the classpath:
```xml
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
```
I've been proceeding a _curl_ requests and playing around with properties until I sorted out how to write custom filters. I made up a list of goals I want to achieve here from modularity.
* It starts as a standalone jar file
* It has an independent component to fetch inside any custom Spring Cloud Gateway Server. Obviously, there is a lot of it in Java community.
* Functionality must be switched on/off by config

My **first** goal has been already reached by default because I had added the dependency above.
Spring Boot Starter represent a library with auto configuration of beans. It could be used as independent component for my **second** goal. You can read more about [custom starter implementation](https://www.baeldung.com/spring-boot-custom-starter).
<br>Basically it has these requirements:
* Your starter jar archive has a `spring.factories` file
```properties
org.springframework.boot.autoconfigure.EnableAutoConfiguration=io.github.aptushkin.proxy.image.autoconfiguration.ProxyImageModificationAutoConfiguration
```
* Spring Configuration Context is configured inside classpath by Java class
```kotlin
@Configuration
@Import(ImageModificationConfiguration::class)
@ConditionalOnProperty(prefix = "proxy.image", name = ["enabled"], havingValue = "true", matchIfMissing = true)
class ProxyImageModificationAutoConfiguration
```
You can see annotation `@ConditionalOnProperty` which gives me the **third** point from my goals. The switching off is enabled by changing the application property: `proxy.image.enabled: true`. It has a property `matchIfMissing = true` which means that this configuration is also turned on non-existed property case.

Thus I created an additional `proxy-image-starter` module inside this repository. The next step is to add it as a dependency inside my server _pom.xml_:
```xml
<dependency>
  <groupId>io.github.artemptushkin.proxy.image</groupId>
  <artifactId>proxy-image-starter</artifactId>
  <version>${project.version}</version>
</dependency>
```
#### **Spring boot starter testing**
Please pay attention that it's important to [write unit-tests](https://github.com/artemptushkin/proxy-image/tree/master/proxy-image-starter/src/test/kotlin/io/github/aptushkin/proxy/image/autoconfiguration) for all the application properties and Spring bean declarations you have written.
<br>It is much more easier to understand your code if there is a test which speaks:
>If you apply a property _A_ than you'll have a bean _B_ inside your Spring context. This test proves it

#### **What I've got from this modularity?**

I have an opportunity to write the starter code independently from server one. It is important because server dependency is redundant for unit-tests, it contains a lot of unnecessary functionality that can be tested separately.
<br>All I need is to test what kind of beans I will get if I add this starter to some project.
<br>Also, it is available to share with other developers now. They can fetch it and try it on their application side.

#### **The actual functionality implementation**
The first thing that comes up to a developer's mind is to write code right here - inside the starter library. It could be done, but there are consequences for project support in the future.
<br>Your starter configuration classes will be growing up along with **actual functionality**. This seems okay until complexity reaches the threshold: at some point, it will be **hard** to understand what is actually happening at the module.

That's why I recommend creating an additional library (core, common etc.) for the functional classes. Specifically when you develop public libraries.
<br>Thus I create a module `proxy-image-common` for all the classes that I need for my functionality. The next step is to add it to the starter _pom.xml_ file:
```xml
<dependency>
  <groupId>io.github.artemptushkin.proxy.image</groupId>
  <artifactId>proxy-image-common</artifactId>
  <version>${project.version}</version>
</dependency>
```
So I got this lose coupled dependency chain:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/bllstaq9j3rul53312cv.PNG)
<br>This means that the starter provides us some beans in some way and *library clients don't know* how it is done.
The common library, in turn, provides some classes which we can use inside our Spring application.

#### **Heading to the code**

I found out that there is a `ModifyResponseBodyGatewayFilterFactory` class that actually modifies the response from the downstream services by a `rewriteFunction` via `Config` class. The last one is configurable by Spring Properties this way:
```yaml
spring:
  cloud:
    gateway:
      default-filters:
        - ProxyForward
      routes:
        - id: modify_image_router
          uri: no://op
          predicates:
            - Path=/**
          filters:
            - name: CropImage
              args:
                responseHeaderName: Content-Type
                regexp: image/.*
                defaultWidth: 600
                defaultHeight: 400
```
Values under _args_ are fields of `Config` class.
<br>I discovered it by making no doubts about Spring classes reusability based on my experience and open source code.
> It ought to be the way to change a class behavior on its client side by changing some interface implementation

I made up new goals regarding my code design now. I want to achieve reusability and keep code as simple as it could be for other developers in the feature:
* Small classes that accept a few objects as a constructor parameter and same with the method parameter, better no more than one object
* A common interface. The implementation of it has to modify an image

>**Abstractions first**. If you want to achieve reusability and loose coupling - start on writing abstractions (interfaces)

<br>The interface of response's body bytes modifications:
```kotlin
interface ByteArrayModifier {
    fun modify(byteArray: ByteArray): ByteArray
}
```
My first implementation looked like:
```kotlin
val inputImage = ByteArrayInputStream(byteArray).use {
    return@use ImageIO.read(it)
}
//... some image processing logic
return ByteArrayOutputStream().use {
    ImageIO.write(scaledImage, format, it)
    return@use it.toByteArray()
}
```
I noticed that a logic of `byteArray -> BufferedImage` and reverse transformation is the same for any current implementation. I extracted it to the `abstract` class and got only the requirements to implement `#modifyImage(BufferedImage)` conversion itself:
```kotlin
abstract class AbstractImageModifier(private val format: String) : ByteArrayModifier {

    override fun modify(byteArray: ByteArray): ByteArray {
        val inputImage = ByteArrayInputStream(byteArray).use {
            return@use ImageIO.read(it)
        }
        ...
    }

    protected abstract fun modifyImage(image: BufferedImage): BufferedImage
}
```
Implementations became small and easy to test:
```kotlin
class CropImageModifier(private val cropRequest: CropRequest): AbstractImageModifier(cropRequest.format) {
    override fun modifyImage(image: BufferedImage): BufferedImage {
        val width = cropRequest.width
        val height = cropRequest.height
        val x = cropRequest.x
        val y = cropRequest.y
        if (x != null && y != null) {
            return Scalr.crop(image, x, y, width, height)
        }
        return Scalr.crop(image, width, height);
    }
}
```
It is important to notice that such classes provide an opportunity to get a small amount of data (objects) in the constructor. It leads us to reuse those implementations at another place of code and keep code and tests easy to read.
<br>As you can see I named the constructor input classes as `...Request` because I think it can be used as a part of another starter for classic REST API applications and basically this DTO class represents query parameters i.e. request data.

#### **More code**

I have many small quality code examples of other approaches in [this project](https://github.com/artemptushkin/proxy-image). As you can see at the repository packages below, the _modifier interface_ is not the only abstraction I've found for the project.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/r4l6hqz3nkoyjvgjw2kp.PNG)

I have plans to write a starter for a classic Spring REST API server to enable filters inside those applications directly and I am open to this library customization.
<br>Please, join to contribute!

### **Conclusions**

I hope this article helps you to find new code design approaches and maybe inspires you to write more reusable solutions.
<br>Summing up conclusion I'd like to give some advice:
* Make strong requirements to your code's quality and the one you review
* Abstract coding is much easier since you start to do it. Just write -> ask -> change it!
* Share your code to make it better and more useful for other developers