Skip to content

Commit

Permalink
Documentation update
Browse files Browse the repository at this point in the history
  • Loading branch information
SuppieRK committed Feb 15, 2025
1 parent 3c6f590 commit 280dc19
Show file tree
Hide file tree
Showing 21 changed files with 211 additions and 72 deletions.
36 changes: 18 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
# JIQS

> The work on this software project is in no way associated with my employer nor with the role I'm having at my
> employer.
>
> I maintain this project alone and as much or as little as my **spare time** permits using my **personal** equipment.
JIQS (pronounced as "jicks," rhyming with "kicks") repository offers a template for the alternative highly customizable
Java microservice stack with focus on simplicity, modularity and control over dependencies where each piece can be
determined individually and excluded / replaced.

It should also open a path for [platform engineers](https://platformengineering.org/blog/what-is-platform-engineering)
to craft a bigger abstraction, tailored for specific company business needs to reduce friction during development.
It opens a path for [platform engineers](https://platformengineering.org/blog/what-is-platform-engineering) to craft a
bigger abstraction, tailored for specific company business needs to reduce friction during development.

Please, review each module `README.md` files for more specific information, as well as comments in the codebase.

## What contributes to the simplicity?

Expand All @@ -14,22 +21,15 @@ to craft a bigger abstraction, tailored for specific company business needs to r
- Focusing on pure SQL, no
ORM [for](https://martinfowler.com/bliki/OrmHate.html) [several](https://medium.com/building-the-system/dont-be-a-sucker-and-stop-using-orms-190add65add4) [reasons](https://en.wikipedia.org/wiki/Object%E2%80%93relational_impedance_mismatch).

## Dependencies offered by default

- [Javalin](https://javalin.io/) as a web server core.
- [jOOQ](https://www.jooq.org/) as a way to talk to the database in pure SQL.
- [Flyway](https://www.red-gate.com/products/flyway/) as a database migration tool which also leverages SQL.
- [Gestalt](https://gestalt-config.github.io/gestalt/) as a customizable configuration library.
- [Inject](https://github.com/SuppieRK/inject) as a standalone dependency injection library.
- [Spotless](https://github.com/diffplug/spotless) to maintain code formatting rules.

### Glue dependencies
## What are the disadvantages?

- [jooq-java-class-generator](https://github.com/SuppieRK/jooq-java-class-generator) to glue Flyway and jOOQ together.
- [Javalin Swagger](https://javalin.io/tutorials/openapi-example) to provide API documentation for consumers.
- [Google JIB](https://github.com/GoogleContainerTools/jib) to build deployable Docker image artifact.
- No "plug-n-play".
- Requires more experience to make right decisions.
- No textbook definition on how to do things:
- Potentially a breeding ground for a poorly documented internal framework with non-transferable knowledge.

### Other dependencies
## What are the advantages?

`build.gradle` has dependencies split into sections, where `PREFERENTIAL` sections can and should be replaced to suit
your needs.
- Select the tech stack most suitable for your business needs, which usually will perform better than the generic stack.
- Better control over dependencies, which also improves security posture.
- Less framework-biased hiring process, leaving more room to explore problem-solving and language skills.
10 changes: 6 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// For this template purpose it makes sense to define these plugins here
// TODO do not forget to include this plugins when decoupling template modules into their own repositories
allprojects {
// https://docs.gradle.org/current/userguide/idea_plugin.html
apply plugin: 'idea'
// https://docs.gradle.org/current/userguide/idea_plugin.html
apply plugin: 'idea'

// https://docs.gradle.org/current/userguide/java_plugin.html
apply plugin: 'java'
// https://docs.gradle.org/current/userguide/java_plugin.html
apply plugin: 'java'
}
41 changes: 41 additions & 0 deletions platform-library/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Platform Library

Defines common structural components of the service.

Typically, this library should define the most generic and general components for any service to use within a company:

- Web server to handle HTTP requests.
- Configuration reader.
- Database connection pool.
- Message bus connection primitives.
- And many more.

> It is also a very good idea to create a separate project to maintain Bill of Materials which would define dependency
> versions for additional control.
## Dependencies offered by default

`build.gradle` in this project defines `api` dependencies split into sections, where seconds commented with
`PREFERENTIAL` can and should be replaced to suit your needs.

### Core

- [Javalin](https://javalin.io/) as a web server core:
- Check out [TechEmpower benchmarks](https://www.techempower.com/benchmarks) for more
options. [Jooby](https://jooby.io/) is a very viable replacement here.
- [jOOQ](https://www.jooq.org/) as a way to talk to the database in pure SQL.
- [Flyway](https://www.red-gate.com/products/flyway/) as a database migration tool which also leverages SQL.

### Optional

- [Inject](https://github.com/SuppieRK/inject) as a standalone dependency injection library:
- This can be a nice Quality of Life addition, but with enough attention to details can be removed - after all any
direct object creation will be much faster than any reflection-based Dependency Injector.
- If you are adamant on the need for Dependency Injection, as alternative I would personally recommend checking out
a set of libraries from [Avaje](https://avaje.io/inject/).
- [Gestalt](https://gestalt-config.github.io/gestalt/) as a customizable configuration library:
- Alternatively you can directly read and parse configuration file using Jackson / SnakeYaml to reduce clutter.

### Code health

- [Spotless](https://github.com/diffplug/spotless) to maintain code formatting rules.
12 changes: 6 additions & 6 deletions platform-library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,6 @@ dependencies {
// https://mvnrepository.com/artifact/io.javalin.community.openapi/javalin-swagger-plugin
api group: 'io.javalin.community.openapi', name: 'javalin-swagger-plugin', version: javalinVersion

// https://mvnrepository.com/artifact/io.github.suppierk/inject
api group: 'io.github.suppierk', name: 'inject', version: injectVersion

// https://mvnrepository.com/artifact/com.github.gestalt-config/gestalt-core
api group: 'com.github.gestalt-config', name: 'gestalt-core', version: gestaltVersion

// https://mvnrepository.com/artifact/com.zaxxer/HikariCP
api group: 'com.zaxxer', name: 'HikariCP', version: hikariVersion

Expand All @@ -51,6 +45,12 @@ dependencies {
// ===== PREFERENTIAL DEPENDENCIES =====
// =====================================

// https://mvnrepository.com/artifact/io.github.suppierk/inject
api group: 'io.github.suppierk', name: 'inject', version: injectVersion

// https://mvnrepository.com/artifact/com.github.gestalt-config/gestalt-core
api group: 'com.github.gestalt-config', name: 'gestalt-core', version: gestaltVersion

// https://mvnrepository.com/artifact/com.github.gestalt-config/gestalt-yaml
api group: 'com.github.gestalt-config', name: 'gestalt-yaml', version: gestaltVersion

Expand Down
5 changes: 0 additions & 5 deletions platform-library/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,21 @@
group=io.github.suppierk
version=0.0.1
javaVersion=21

# Plugin dependency properties
spotlessVersion=7.0.2
mavenPublishPluginVersion=0.30.0

# Common dependency properties
javalinVersion=6.4.0
injectVersion=2.0.1
gestaltVersion=0.35.1
hikariVersion=6.2.1
jooqVersion=3.19.16
flywayVersion=11.1.0

# Preferential dependency properties
postgresVersion=42.7.4
uuidCreatorVersion=6.0.0

# Test dependencies properties
junitVersion=5.11.4

# Preferential test dependencies properties
testcontainersVersion=1.20.4
equalsVerifierVersion=3.17.5
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@
import io.github.suppierk.utils.Memoized;
import io.javalin.Javalin;
import java.io.Closeable;
import platform.dependencies.ConfigurationProvider;
import platform.dependencies.ConfigurationReaderProvider;
import platform.dependencies.JacksonProvider;
import platform.dependencies.JavalinProvider;
import platform.dependencies.JooqProvider;
import platform.dependencies.*;
import platform.endpoints.HealthcheckEndpointGroup;
import platform.primitives.ServerPort;

Expand Down
17 changes: 17 additions & 0 deletions platform-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Platform Gradle Plugin

Defines common plugins and dependencies for services.

It is a good idea to package this plugin with:

- Platform library.
- Additional glue and settings for the plugins provided.

## Dependencies offered by default

### Core

- [Javalin Swagger](https://javalin.io/tutorials/openapi-example) to provide API documentation for consumers.
- [Google JIB](https://github.com/GoogleContainerTools/jib) to build deployable Docker image artifact.
- [jooq-java-class-generator](https://github.com/SuppieRK/jooq-java-class-generator) to glue Flyway and jOOQ together.
- There are other alternatives to this plugin as well!
9 changes: 7 additions & 2 deletions platform-plugin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,17 @@ repositories {
}

dependencies {
// ====================
// Exposed plugin dependencies
// ===============================
// ===== COMMON DEPENDENCIES =====
// ===============================

// https://plugins.gradle.org/plugin/io.github.suppierk.jooq-java-class-generator
api group: "io.github.suppierk.jooq-java-class-generator", name: "io.github.suppierk.jooq-java-class-generator.gradle.plugin", version: jooqJavaClassGeneratorVersion

// =====================================
// ===== PREFERENTIAL DEPENDENCIES =====
// =====================================

// https://plugins.gradle.org/plugin/com.diffplug.spotless
api group: "com.diffplug.spotless", name: "com.diffplug.spotless.gradle.plugin", version: spotlessVersion
}
Expand Down
2 changes: 0 additions & 2 deletions platform-plugin/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
group=io.github.suppierk
version=0.0.1
javaVersion=21

# Plugin dependency properties
gradlePluginPublishVersion=1.3.1
gradleGithubActions=1.4.0
spotlessVersion=7.0.2

# Dependency properties
jooqJavaClassGeneratorVersion=1.0.1
1 change: 1 addition & 0 deletions platform-plugin/settings.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
rootProject.name = 'platform-plugin'

// Refers to a platform library project which allows further decoupling, if needed
includeBuild '../platform-library'
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ public void apply(Project root) {
.add(
"implementation",
"io.github.suppierk:platform-library:%s".formatted(PLATFORM_LIBRARY_VERSION));

// Registering additional database-specific dependency for jOOQ class generator
root.getDependencies()
.add("jooqGenerator", "org.postgresql:postgresql:%s".formatted(POSTGRESQL_VERSION));

Expand Down
6 changes: 6 additions & 0 deletions service/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Service

Defines an example of how typical service implementation can look like.

The core idea here is to reduce as much setup as we can with platform functionality - leaving developer's focus on a
business task at hand.
2 changes: 0 additions & 2 deletions service/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
group=io.github.suppierk
version=0.0.1
javaVersion=21

# Database properties
databaseJooqGeneratedClassesPackageName=service.db

# Plugin dependency properties
jibVersion=3.3.2
1 change: 1 addition & 0 deletions service/settings.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
rootProject.name = 'service'

// Refers to platform projects which allows further decoupling, if needed
includeBuild '../platform-plugin'
includeBuild '../platform-library'
26 changes: 20 additions & 6 deletions service/src/main/java/service/endpoints/UsersEndpointGroup.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@
import io.javalin.http.Context;
import io.javalin.http.HttpStatus;
import io.javalin.http.NotFoundResponse;
import io.javalin.openapi.HttpMethod;
import io.javalin.openapi.OpenApi;
import io.javalin.openapi.OpenApiContent;
import io.javalin.openapi.OpenApiParam;
import io.javalin.openapi.OpenApiRequestBody;
import io.javalin.openapi.OpenApiResponse;
import io.javalin.openapi.*;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import java.util.Map;
Expand All @@ -24,6 +19,11 @@
import service.models.responses.UserResponse;
import service.services.UsersService;

/**
* This is essentially a controller, which defines endpoints to manipulate data in the app.
*
* <p>Be careful with business logic, as this class also defines a lot of OpenAPI annotations.
*/
@Singleton
public class UsersEndpointGroup implements EndpointGroup, CrudHandler {
private static final String USER_ID = "userId";
Expand All @@ -32,16 +32,26 @@ public class UsersEndpointGroup implements EndpointGroup, CrudHandler {

private final UsersService service;

/**
* Default constructor.
*
* <p>Because of the way how {@link io.github.suppierk.inject.Injector} is implemented,
* constructor parameter will never be {@code null}.
*
* @param service to invoke database operations.
*/
@Inject
public UsersEndpointGroup(UsersService service) {
this.service = service;
}

/** {@inheritDoc} */
@Override
public void addEndpoints() {
crud(SINGULAR_USER_ENDPOINT, this);
}

/** {@inheritDoc} */
@Override
@OpenApi(
summary = "Create new user",
Expand All @@ -59,6 +69,7 @@ public void create(Context context) {
context.json(response);
}

/** {@inheritDoc} */
@Override
@OpenApi(
summary = "Get all users",
Expand All @@ -73,6 +84,7 @@ public void getAll(Context context) {
context.json(service.getAll());
}

/** {@inheritDoc} */
@Override
@OpenApi(
summary = "Get user by ID",
Expand Down Expand Up @@ -109,6 +121,7 @@ public void getOne(Context context, String resourceId) {
context.json(response);
}

/** {@inheritDoc} */
@Override
@OpenApi(
summary = "Update user by ID",
Expand Down Expand Up @@ -147,6 +160,7 @@ public void update(Context context, String resourceId) {
context.json(response);
}

/** {@inheritDoc} */
@Override
@OpenApi(
summary = "Delete user by ID",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
public record UserRequest(String username, char[] password) {
@Override
public boolean equals(Object o) {
if (!(o instanceof UserRequest that)) return false;
return Objects.equals(username, that.username) && Objects.deepEquals(password, that.password);
if (!(o instanceof UserRequest(String thatUsername, char[] thatPassword))) {
return false;
}

return Objects.equals(username, thatUsername) && Objects.deepEquals(password, thatPassword);
}

@Override
Expand Down
Loading

0 comments on commit 280dc19

Please sign in to comment.