Java Backend Coding Technology

Version 2.1.2 | Full Changelog

A framework-agnostic methodology for writing predictable, testable Java backend code optimized for human-AI collaboration.

Here’s What Changes

Without JBCT With JBCT
// Hidden failure modes, unclear control flow
public User findUser(String userId) throws NotFoundException {
    long id;
    try {
        id = Long.parseLong(userId);
    } catch (NumberFormatException e) {
        throw new IllegalArgumentException("Invalid user ID");
    }

    User user = repository.findById(id);
    if (user == null) {
        throw new NotFoundException("User not found: " + id);
    }

    return user;
    // Multiple failure modes hidden in throws
    // Caller must read docs to know what exceptions to catch
}
// Parse don't validate - invalid states unrepresentable
public record UserId(long value) {
    // private UserId {}  // Not yet supported in Java

    public static Result<UserId> userId(String raw) {
        return Number.parseLong(raw)
            .map(UserId::new);
    }
}

public interface FindUser {
    Promise<User> execute(UserId id);
}

// Usage
UserId.userId(userIdStr)
      .async()
      .flatMap(findUser::execute)
      // Parsing errors: Result<UserId>
      // Not found errors: Promise<User>
      // All failures typed, compiler enforces handling

Result: Parse-don’t-validate makes invalid states impossible. Typed errors eliminate hidden exceptions. Type signatures document failure modes.

Why β€œTechnology”?

In industrial manufacturing, technology is the structured method of producing goods with reliably consistent quality within reliably consistent time. It’s not just tools. It’s the engineered process that ensures stable output under defined conditions. Technology emphasizes predictability, repeatability, and control.

Traditional software development relies on β€œbest practices.” These are subjective guidelines that often contradict each other, leaving developers to make judgment calls on every decision. Should this be a service or a helper? When is a class too complex? How should errors flow? These questions consume cognitive energy and produce inconsistent results across teams, projects, and even within the same codebase. It’s β€œart” more than engineering.

Java Backend Coding Technology transforms this into a technology. Less art, more engineering. It provides mechanical rules that eliminate subjective debates: unified code structure from functions to packages; clearly defined approaches to testing, logging, and interaction with external code; five objective criteria that replace β€œit depends” with measurable standards. The result is code that looks the same whether you wrote it, a colleague wrote it, or AI generated it. Predictable, testable, and optimized for both human and AI collaboration.

πŸš€ Quick Start

New to this technology? Start with the learning series:

  1. Series Index - Overview and navigation for the 9-part learning series
  2. Part 1: Foundations - Mental model and core ideas
  3. Part 2: The Four Return Types - T, Option, Result, Promise
  4. Part 3: Parse, Don’t Validate - Making invalid states unrepresentable
  5. Part 4: Error Handling & Composition - Errors as values, null policy, monadic rules
  6. Part 5: Basic Patterns - Leaf, Condition, Iteration
  7. Part 6: Advanced Patterns - Sequencer, Fork-Join, Aspects
  8. Part 7: Testing Philosophy - Integration-first, evolutionary testing
  9. Part 8: Testing in Practice - Organization, examples, migration
  10. Part 9: Production Systems - Complete walkthrough, project structure, frameworks

Need the complete reference? See CODING_GUIDE.md - comprehensive technical documentation with all patterns, principles, and examples.

⚑ Quick Wins: Start Small

Don’t want to learn a whole new paradigm? You don’t have to. Here are three changes you can make today that provide immediate value:

1. Convert One Value Object

Pick your most-validated field (email, phone, user ID).

Before:

// DTO with validation annotations
public class UserRequest {
    @NotBlank @Email
    private String email;  // Can still be constructed with invalid data
    // getter/setter
}

// Validation happens at controller, but domain code has no guarantees

After:

// Validation = construction
public record Email(String value) {
    // private Email {}  // Not yet supported in Java

    private static final Cause EMAIL_REQUIRED = Causes.cause("Email is required");
    private static final Fn1<Cause, String> EMAIL_BLANK = Causes.forOneValue("Email cannot be blank: %s");
    private static final Fn1<Cause, String> INVALID_FORMAT = Causes.forOneValue("Invalid email format: %s");

    public static Result<Email> email(String raw) {
        return Verify.ensure(raw, Verify.Is::notNull, EMAIL_REQUIRED)
            .filter(EMAIL_BLANK, Verify.Is::notBlank)
            .filter(INVALID_FORMAT, PATTERN.asMatchPredicate())
            .map(Email::new);
    }
}
// Impossible to create invalid Email - type system guarantees it

Win: Business logic only sees valid emails. No defensive if (email == null) checks.

2. Convert One Service Method

Pick a method that can fail in business-meaningful ways.

Before:

public User findUser(String id) throws UserNotFoundException {
    User user = repository.findById(id);
    if (user == null) {
        throw new UserNotFoundException(id);
    }
    return user;
}
// Caller doesn't know it throws without reading docs/code

After:

public Promise<User> findUser(UserId id) {
    return repository.findById(id)  // Returns Promise<Option<User>>
        .flatMap(opt -> opt.async(USER_NOT_FOUND)); // Replace missing value with corresponding business error
}
// Compiler forces caller to handle the failure case

Win: Failures are type-safe. No hidden exceptions. Async I/O explicit in return type.

3. Convert One Test

Make one test more readable using functional assertions.

Before:

@Test
void testEmailValidation() {
    try {
        validateEmail("invalid");
        fail("Should have thrown exception");
    } catch (ValidationException e) {
        assertTrue(e.getMessage().contains("email"));
    }
}
// Verbose, requires manual assertion, easy to forget fail()

After:

@Test
void email_rejectsInvalidFormat() {
    Email.email("invalid")
         .onSuccess(Assertions::fail);  // Fail if unexpectedly succeeds
}

@Test
void email_acceptsValidFormat() {
    Email.email("[email protected]")
         .onFailure(Assertions::fail)  // Fail if unexpectedly fails
         .onSuccess(email -> assertEquals("[email protected]", email.value()));
}

Win: Clear test intent. No try-catch boilerplate. Better failure messages.


That’s it. Three small changes. Each takes 10 minutes. Each provides immediate value. You don’t have to rewrite your whole appβ€”adopt incrementally.

πŸ“š Documentation

For Developers

  • CODING_GUIDE.md - Complete technical reference (100+ pages)

    • Core concepts: Four Return Kinds, Parse-Don’t-Validate, No Business Exceptions
    • Pattern catalog: Leaf, Sequencer, Fork-Join, Condition, Iteration, Aspects
    • Evaluation framework: Five objective criteria for code decisions
    • Naming conventions, testing patterns, project structure
    • Complete use case walkthrough with Spring Boot and JOOQ integration
  • series/ - Progressive learning path (9 parts)

    • Parts 2-4 cover core principles (split for digestibility)
    • Parts 7-8 cover comprehensive testing strategy
    • Designed for sequential reading
    • Builds concepts incrementally
    • Ideal for onboarding and teaching

For Managers & Decision Makers

  • MANAGEMENT_PERSPECTIVE.md - Business case for structural standardization
    • ROI of predictable code structure
    • Risk reduction through mechanical refactoring rules
    • Team velocity improvements with reduced subjective debates
    • Onboarding time reduction

Changelog & Versioning

  • CHANGELOG.md - Version history following Keep a Changelog
    • Current version: 2.1.2 (2026-01-12)
    • Golden formatting patterns, Pragmatica Lite 0.9.10, 36 lint rules
    • Semantic versioning for documentation releases

πŸ”§ Tools

JBCT provides comprehensive tooling for AI-assisted development and automated compliance checking.

AI Tools

AI Tooling Documentation - Complete guide to Claude Code integration:

Tool Purpose
jbct skill Learning, quick reference, pattern understanding
jbct-coder Autonomous code generation following JBCT patterns
jbct-reviewer Code review for JBCT compliance
jbct-review Parallel review with 10 focused workers (/jbct-review command)

Quick Install:

# Install all AI tools
mkdir -p ~/.claude/skills ~/.claude/agents
cp -r skills/jbct skills/jbct-review ~/.claude/skills/
cp jbct-coder.md jbct-reviewer.md ~/.claude/agents/

CLI Tools

CLI Documentation - Command-line formatting and linting:

Command Description
jbct format Format Java code to JBCT style
jbct lint Check JBCT compliance (37 rules)
jbct check Combined format + lint (recommended for CI)
jbct init Scaffold new JBCT project

Quick Install (Linux/macOS):

curl -fsSL https://raw.githubusercontent.com/siy/jbct-cli/main/install.sh | sh

Maven Plugin

Maven Plugin Documentation - Build integration:

<plugin>
    <groupId>org.pragmatica-lite</groupId>
    <artifactId>jbct-maven-plugin</artifactId>
    <version>0.4.6</version>
</plugin>

Requirements: Java 25+, Maven 3.9+

πŸ“‚ Repository Structure

coding-technology/
β”œβ”€β”€ CODING_GUIDE.md              # Complete technical reference
β”œβ”€β”€ series/                       # 9-part learning series
β”‚   β”œβ”€β”€ INDEX.md                 # Series overview and navigation
β”‚   β”œβ”€β”€ part-01-foundations.md
β”‚   β”œβ”€β”€ part-02-four-return-types.md
β”‚   β”œβ”€β”€ part-03-parse-dont-validate.md
β”‚   β”œβ”€β”€ part-04-error-handling.md
β”‚   β”œβ”€β”€ part-05-basic-patterns.md
β”‚   β”œβ”€β”€ part-06-advanced-patterns.md
β”‚   β”œβ”€β”€ part-07-testing-philosophy.md
β”‚   β”œβ”€β”€ part-08-testing-practice.md
β”‚   └── part-09-production-systems.md
β”œβ”€β”€ MANAGEMENT_PERSPECTIVE.md    # Business case and ROI
β”œβ”€β”€ CHANGELOG.md                 # Version history
β”œβ”€β”€ AI-TOOLING.md                # AI tools documentation
β”œβ”€β”€ CLI-TOOLING.md               # CLI tools documentation
β”œβ”€β”€ MAVEN-PLUGIN.md              # Maven plugin documentation
β”œβ”€β”€ skills/                      # Claude Code skills
β”‚   β”œβ”€β”€ jbct/                    # JBCT main skill
β”‚   β”‚   β”œβ”€β”€ SKILL.md             # Skill definition
β”‚   β”‚   └── README.md            # Installation instructions
β”‚   └── jbct-review/             # Parallel review skill
β”‚       └── SKILL.md             # /jbct-review command
β”œβ”€β”€ jbct-coder.md                # Claude Code subagent: code generation
β”œβ”€β”€ jbct-reviewer.md             # Claude Code subagent: code review
β”œβ”€β”€ examples/                    # Java code examples
β”‚   └── [Maven projects demonstrating patterns]
β”œβ”€β”€ sources/                     # Research materials
β”‚   β”œβ”€β”€ articles/                # Reference articles
β”‚   β”œβ”€β”€ code/                    # Code snippets
β”‚   └── patterns/                # Pattern documentation
β”œβ”€β”€ templates/                   # Reusable templates
└── PL_IMPROVEMENTS.md           # Pragmatica Lite enhancement backlog

🀝 Contributing

This repository documents a methodology, not a software project. Contributions welcome:

  • Experience reports - How the technology worked in your project
  • Pattern discoveries - New patterns or refinements
  • Examples - Real-world use case implementations
  • Questions & discussions - Open issues for clarification

πŸ“– Key Concepts at a Glance

Four Return Kinds: Every function returns exactly one:

  • T - Synchronous, cannot fail, always present
  • Option<T> - Synchronous, cannot fail, might be absent
  • Result<T> - Synchronous, can fail, present if success
  • Promise<T> - Asynchronous, can fail

Parse, Don’t Validate: Make invalid states unrepresentable. Validation is parsing - if construction succeeds, the object is valid.

No Business Exceptions: Business failures are expected outcomes, not exceptions. They flow through Result or Promise as typed Cause objects.

Six Patterns: All code fits one pattern:

  1. Leaf - Atomic operation (business logic or I/O adapter)
  2. Sequencer - Chain dependent steps (2-5 steps)
  3. Fork-Join - Parallel independent operations
  4. Condition - Branching as values
  5. Iteration - Functional combinators over collections
  6. Aspects - Cross-cutting concerns (retry, timeout, metrics)

Vertical Slicing: Each use case is self-contained. Business logic isolated per use case, not centralized.

  • Pragmatica Lite Core - The foundational library providing Option, Result, Promise, and functional utilities

Maven:

<dependency>
   <groupId>org.pragmatica-lite</groupId>
   <artifactId>core</artifactId>
   <version>0.9.10</version>
</dependency>

Gradle:

implementation 'org.pragmatica-lite:core:0.9.10'

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

You are free to:

  • Use this methodology in commercial and non-commercial projects
  • Modify and adapt the documentation and examples
  • Distribute and share the content
  • Create derivative works

Support

If you find this useful, consider sponsoring.


Version: 2.1.2 | Last Updated: 2026-01-12 | Full Changelog

Copyright Β© 2025 Sergiy Yevtushenko. Released under the MIT License.