Bluetape4k Projects Part 5: utilities and adoption path

This is Part 5 of the bluetape4k-projects series. Part 4
covered operational boundaries such as databases, Redis, messaging, observability, and resilience. This post moves to
smaller modules: IDs, time, units, money, geo data, rule/state/workflow helpers, and probabilistic structures.
Utilities differ from domain repositories. Repositories such as bluetape4k-exposed, bluetape4k-leader, and
bluetape4k-text have their own ecosystems and release rhythm. Utilities in projects capture smaller decisions that
repeat across service code. Small decisions become standards quickly. If they spread before becoming standards, future
cleanup gets much harder than standardization.

IDs Are Policy First
Section titled “IDs Are Policy First”bluetape4k-idgenerators organizes UUID v1-v7, ULID, KSUID, Snowflake, Flake, and Hashids behind generator APIs. The
main value is not the count of supported algorithms. The value is exposing selection rules in one place.
| Requirement | Start with |
|---|---|
| Database primary key with sortability | UUID v7 |
| String ID with time ordering | ULID or KSUID |
| Long ID in distributed systems | Snowflake |
| Short URL or obfuscation | Hashids |
| Full randomness | UUID v4 |
val orderId = Uuid.V7.nextId()val publicId = Uuid.V7.nextBase62()val eventId = Ksuid.Millis.generate()val shardKey = Snowflakers.Default.nextId()IDs are hard to change later. They leak into indexes, URLs, events, logs, and external contracts. A random UUID may be a fine answer, but it still has consequences for ordering, storage, public exposure, and shard strategy.
Domain Values: Money, Units, Location, Time
Section titled “Domain Values: Money, Units, Location, Time”money, measured, geo, science, and javatimes keep domain values from becoming anonymous strings and numbers.
bluetape4k-measured models units through Units and Measure<T : Units>. It covers length, time, mass, volume,
temperature, angle, area, storage, frequency, energy/power, velocity, and acceleration.
val speed = 10 * Length.meters / Time.secondsval duration = 5 * Time.secondsval distance = speed * duration
println(distance `as` Length.meters)Money and units start comfortably as primitives: BigDecimal amount, String currency, Double distance. Then exchange
rates, rounding, unit conversion, and display formats arrive. At that point it is better to let types carry the meaning.
geo and science cover geocode/geohash/geoip2, coordinate transforms, shapefile reading, JTS geometry operations, and
PostGIS loading pipelines. These modules should be adopted only by services that actually own that domain.
Rules, State, Workflow
Section titled “Rules, State, Workflow”rule-engine, states, workflow, and probabilistic describe decisions and flow.
rule-engine supports Kotlin DSL rules, annotation-based rules, coroutine rules, YAML/JSON/HOCON readers, and script
engines such as MVEL2, SpEL, Kotlin Script, Janino, and Groovy. The core model is simple: inspect Facts, evaluate a
condition, and run an action when the condition matches.
val discountRule = rule { name = "discount" priority = 1 condition { facts -> (facts.get<Int>("amount") ?: 0) > 1000 } action { facts -> facts["discount"] = true }}
ruleEngine { skipOnFirstAppliedRule = true } .fire(ruleSetOf(discountRule), Facts.of("amount" to 1500))states is a Kotlin DSL finite-state machine with guards, coroutine FSM support, and StateFlow observation.
workflow composes sequential, parallel, conditional, repeat, and retry flows with synchronous virtual-thread execution
or coroutine/Flow execution.
Selection is straightforward. Use rule-engine when policy calculation depends on facts. Use states when an object moves through a small set of named states. Use workflow when multiple steps need retry, cancellation, or partial success.
Validate Adoption Through Examples
Section titled “Validate Adoption Through Examples”Do not stop at the utility README. Read the closest example too. projects/examples includes coroutine, JPA/Blaze
Persistence, Querydsl, Redisson, virtual-thread, and idgenerator Spring Boot/Ktor demos. bluetape4k-workshop shows
application-oriented paths for cache, Redis, coroutines, virtual threads, observability, messaging, and Spring Data.
| Service need | First utility/example | Why |
|---|---|---|
| Public IDs and batch ID endpoints | idgenerators, idgenerator Spring Boot/Ktor demo | Check generator choice and HTTP exposure together |
| Redis locks or cache patterns | redisson-demo, cache series | Separate primitive usage from cache strategy |
| Teaching coroutine flow | coroutines-demo, coroutine workshop | Verify cancellation, Flow, and context behavior |
| Evaluating virtual threads | virtualthreads-demo, virtual-thread blog series | Check no pooling, semaphore use, and synchronized risks |
| Spring Data coroutine helpers | Spring Boot R2DBC/MongoDB README, workshop | See repository boundary and test fixture shape |
The adoption path should stay conservative:
- Import the BOM first.
- Add one utility module for one repeated problem.
- Read the README and the nearest example together.
- For benchmarked modules, read the measurement direction and context before claiming speed.
- Lock the ID/time/serialization/failure policy in service tests.
This keeps projects as a toolbox instead of a framework.
Source Links
Section titled “Source Links”- Utilities root:
utils/ - Examples root:
examples/ - Workshop root: bluetape4k-workshop
- ID generators README:
utils/idgenerators/README.md - Measured README:
utils/measured/README.md - Rule engine README:
utils/rule-engine/README.md
Closing
Section titled “Closing”Utilities are easy to add because they are small, and that is exactly why they deserve care. IDs, time, money, units, rules, and workflows settle deep inside a service. A helper can become a data contract after a few months.
The useful path is simple: align versions with the BOM, add one module for one problem, inspect the example shape, and lock the policy in tests. That is conservative enough and still fast.
Next, we move to the Spring Boot 4 and Ktor 3 application layer.
Comments
Leave a note or reaction with your GitHub account.