Receber por email
← Voltar para o catálogo

JBCT

Skill de Tecnologia de Codificação Java Backend para projetar, implementar e revisar código Java backend funcional. Abrange tipos como Result, Option, Promise, objetos de valor, casos de uso, padrões JBCT, composição monádica, parse-don't-validate, padrões estruturais e arquitetura funcional Java backend.

556estrelas
Atualizado há 2 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add majiayu000/claude-skill-registry

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/jbct/svg)](https://www.skillteca.com.br/skills/jbct)

Skills relacionadas

Ver todas de Desenvolvimento →

Alerta por categoria

Receba novas skills de Desenvolvimento toda segunda

1 email curto, só com as skills novas de Desenvolvimento. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Java Backend Coding Technology (JBCT)

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

When to Use This Skill

Activate this skill when:

  • Learning JBCT principles and patterns
  • Quick reference for API usage and examples
  • Understanding patterns and when to use them
  • Working with Result<T>, Option<T>, Promise<T> types
  • Questions about monadic composition, error handling, or validation patterns

For implementation work: Use jbct-coder subagent (Task tool with subagent_type: "jbct-coder") For code review: Use jbct-reviewer subagent (Task tool with subagent_type: "jbct-reviewer") For automated checking: Use jbct CLI tool (format, lint, check commands)

JBCT CLI Tool

JBCT CLI provides automated formatting and compliance checking with 36 lint rules.

Check if installed:

jbct --version

Usage:

jbct format src/main/java    # Format to JBCT style
jbct lint src/main/java      # Check JBCT compliance (36 rules)
jbct check src/main/java     # Combined format + lint

If not installed, suggest:

💡 JBCT CLI automates formatting and 36 lint rules for JBCT compliance.
   Install: curl -fsSL https://raw.githubusercontent.com/siy/jbct-cli/main/install.sh | sh
   Requires: Java 25+
   More info: https://github.com/siy/jbct-cli

Core Philosophy

JBCT reduces the space of valid choices to one good way to do most things through:

  • Four Return Kinds: Every function returns exactly one of T, Option<T>, Result<T>, Promise<T>
  • Parse, Don't Validate: Make invalid states unrepresentable
  • No Business Exceptions: Business failures are typed Cause values
  • Thread Safety by Design: Immutability at boundaries, thread confinement for sequential logic
  • Six Structural Patterns: All code fits one pattern (Leaf, Sequencer, Fork-Join, Condition, Iteration, Aspects)

Quick Reference

The Four Return Kinds

// T - Pure computation, cannot fail, always present
public String initials() { return ...; }

// Option<T> - May be absent, cannot fail
public Option<Theme> findTheme(UserId id) { return ...; }

// Result<T> - Can fail (validation/business errors)
public static Result<Email> email(String raw) { return ...; }

// Promise<T> - Asynchronous, can fail
public Promise<User> loadUser(UserId id) { return ...; }

Critical Rules:

  • ❌ Never Promise<Result<T>> - Promise already handles failures
  • ❌ Never Void type - always use Unit (Result<Unit>, Promise<Unit>)
  • ✅ Use Result.unitResult() for successful Result<Unit>

Parse, Don't Validate Pattern

// ✅ CORRECT: Validation = Construction
public record Email(String value) {
    private static final Fn1<Cause, String> INVALID_EMAIL =
        Causes.forOneValue("Invalid email: %s");

    public static Result<Email> email(String raw) {
        return Verify.ensure(raw, Verify.Is::notNull)
                     .map(String::trim)
                     .filter(INVALID_EMAIL, PATTERN.asMatchPredicate())
                     .map(Email::new);
    }
}

// ❌ WRONG: Separate validation
public record Email(String value) {
    public Result<Email> validate() { ... }  // Don't do this
}

Key Points:

  • Factory method named after type (lowercase): Email.email(...)
  • Constructor private or package-private
  • If instance exists, it's valid

Pragmatica Lite Validation Utilities

Verify.Is Predicates - Use instead of custom lambdas:

Verify.Is::notNull          // null check
Verify.Is::notBlank         // non-empty, non-whitespace
Verify.Is::lenBetween       // length in range
Verify.Is::matches          // regex (String or Pattern)
Verify.Is::positive         // > 0
Verify.Is::between          // >= min && <= max
Verify.Is::greaterThan      // > boundary

Parse Subpackage - Exception-safe JDK wrappers:

import org.pragmatica.lang.parse.Number;
import org.pragmatica.lang.parse.DateTime;
import org.pragmatica.lang.parse.Network;

Number.parseInt(raw)              // Result<Integer>
DateTime.parseLocalDate(raw)      // Result<LocalDate>
Network.parseUUID(raw)            // Result<UUID>

Example:

public record Age(int value) {
    private static final Cause AGE_OUT_OF_RANGE = Causes.cause("Age must be 0-150");

    public static Result<Age> age(String raw) {
        return Number.parseInt(raw)
                     .filter(AGE_OUT_OF_RANGE, v -> Verify.Is.between(v, 0, 150))
                     .map(Age::new);
    }
}

Use Case Structure

public interface RegisterUser extends UseCase.WithPromise<Response, Request> {
    record Request(String email, String password) {}
    record Response(UserId userId, ConfirmationToken token) {}

    // Nested API: steps as single-method interfaces
    interface CheckEmail { Promise<ValidRequest> apply(ValidRequest valid); }
    interface SaveUser { Promise<User> apply(ValidRequest valid); }

    // Validated input with Valid prefix (not Validated)
    record ValidRequest(Email email, Password password) {
        static Result<ValidRequest> validRequest(Request raw) {
            return Result.all(Email.email(raw.email()),
                              Password.password(raw.password()))
                         .map(ValidRequest::new);
        }
    }

    // ✅ CORRECT: Factory returns lambda directly
    static RegisterUser registerUser(CheckEmail checkEmail, SaveUser saveUser) {
        return request -> ValidRequest.validRequest(request)
                                      .async()
                                      .flatMap(checkEmail::apply)
                                      .flatMap(saveUser::apply);
    }
}

❌ ANTI-PATTERN: Nested Record Implementation

NEVER create factories with nested record implementations:

// ❌ WRONG - Verbose, no benefit
static RegisterUser registerUser(CheckEmail check, SaveUser save) {
    record registerUser(CheckEmail check, SaveUser save) implements RegisterUser {
        @Override
        public Promise<Response> execute(Request request) { ... }
    }
    return new registerUser(check, save);
}

Rule: Records are for data (value objects), lambdas are for behavior (use cases, steps).

Thread Safety Essentials

Core Rules:

  • Immutable at boundaries: All shared data (parameters, return values) must be immutable
  • Thread confinement: Mutable state allowed within single-threaded execution (sequential patterns)
  • Fork-Join requires immutability: Parallel operations must not share mutable state

Pattern-Specific Safety:

  • Leaf, Sequencer, Condition, Iteration: Thread-safe through sequential execution. Mutable local state OK.
  • Fork-Join: Requires strict immutability. All parallel operations receive immutable inputs.
  • Promise resolution: Thread-safe (exactly-once semantics, synchronization point for flatMap/map chains)

Example - Thread-Safe Fork-Join:

// ✅ CORRECT: Immutable cart passed to both operations
Promise.all(applyBogo(cart),          // cart is immutable
            applyPercentOff(cart))    // cart is immutable
        .map(this::mergeDiscounts);

// ❌ WRONG: Shared mutable context creates data race
private final DiscountContext context = new DiscountContext();
Promise.all(applyBogo(cart, context),     // mutates context
            applyPercentOff(cart, context))  // DATA RACE
        .map(this::merge);

See CODING_GUIDE.md for comprehensive thread safety coverage, including detailed examples and common mistakes.

Lambda Composition Guidelines

Rule: Lambdas passed to monadic operations (map, flatMap, recover, filter) must be minimal.

Allowed:

  • Method references: Email::new, this::processUser, User::id
  • Parameter forwarding: user -> validate(requiredRole, user)
  • Constructor references for error mapping: RepositoryError.DatabaseFailure::new

Forbidden:

  • Conditionals (`if
Compartilhar X LinkedIn