diff --git a/CHANGELOG.md b/CHANGELOG.md index fdee1f1..bfc9085 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,47 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.1.2] - 2026-01-13 + +### Added +- **jbct-designer Agent** - new AI agent for JBCT-based architecture design + - Use *before* implementation to validate architecture and select patterns + - 8-step design methodology with gap detection + - Discovery questions by pattern + - Output format for implementation-ready designs + - Workflow: jbct-designer → jbct-coder → jbct-reviewer +- **Common Language: Developer-Business Vocabulary** - patterns as shared language + - CODING_GUIDE.md: New section in Foundational Concepts + - series/part-01-foundations.md: Added paragraph with translation examples + - book/ch01-introduction.md: Added paragraph + - Key insight: "First we verify, then we process, then we notify" = Sequencer +- **Gap Detection Through Patterns** - systematic requirement discovery + - CODING_GUIDE.md: New section in Patterns Reference + - series/part-05-basic-patterns.md: New section with discovery questions + - series/part-06-advanced-patterns.md: Discovery questions for advanced patterns + - book/ch07-basic-patterns.md: New section + - book/ch08-advanced-patterns.md: New section + - jbct-reviewer.md: Step 7 added to Review Methodology +- **Discovery Questions by Pattern** - questions each pattern generates + - Per-pattern tables: Leaf, Sequencer, Fork-Join, Condition, Iteration, Aspects + - Gap signal → Question to raise mapping + - Added to CODING_GUIDE.md, series, book, and jbct-reviewer +- **The Six Patterns That Cover Everything** - follow-up article + - Articles: `articles/six-patterns-that-cover-everything.md` + - Common language concept, gap detection, right questions + - Before/after example showing precision gain +- **Request Processing as Data Transformation** - foundational concept + - Articles: `articles/underlying-process.md` (full article) + - Articles: `articles/linkedin-data-transformation.md` (LinkedIn post) + - CODING_GUIDE.md: New section in Foundational Concepts + - Book: ch01-introduction.md expanded with new section + - Key insight: sync/async and parallel/sequential are execution details, not structural concerns + - JBCT patterns as universal primitives for data flow + +### Changed +- **jbct-coder.md** - Added Related Agents section with workflow context +- **jbct-reviewer.md** - Added Related Agents section, gap detection step, output format section + ## [2.1.1] - 2026-01-08 ### Added diff --git a/CODING_GUIDE.md b/CODING_GUIDE.md index 0e16636..19783d8 100644 --- a/CODING_GUIDE.md +++ b/CODING_GUIDE.md @@ -305,6 +305,78 @@ The second version **chains** operations. Each step takes the output of the prev Composition lets you **build complex logic from simple pieces** without intermediate variables or explicit error checking at each step. The structure itself handles error propagation. +### Request Processing as Data Transformation + +Every request your system handles follows the same fundamental process—regardless of language or framework. It mirrors how humans naturally solve problems: take input, gradually collect necessary pieces of knowledge, and produce a correct answer. + +**The Universal Pattern:** +``` +Input → Parse → Gather → Process → Respond → Output +``` + +Each stage transforms data. Each stage may need additional data. Each stage may fail. The entire flow is a data transformation pipeline. + +**Why Async Looks Like Sync:** + +When you think in terms of data transformation, the sync/async distinction disappears: + +```java +// These are structurally identical +Result user = database.findUser(userId); // "sync" +Promise user = httpClient.fetchUser(userId); // "async" +``` + +Both take a user ID, both produce a User (or failure). The only difference is *when* the result becomes available—an execution detail, not a structural concern. Your business logic doesn't care whether data came from local memory or crossed an ocean. + +**Parallel Execution Becomes Transparent:** + +You don't decide "this should be parallel." You express data dependencies. The execution strategy follows from the structure: + +```java +// Sequential: each step needs previous result +return validateInput(request) + .flatMap(this::createUser) + .flatMap(this::sendWelcomeEmail); + +// Parallel: steps are independent +return Promise.all( + fetchUserProfile(userId), + loadAccountSettings(userId), + getRecentActivity(userId) +).map(this::buildDashboard); +``` + +If operations share no data dependencies, they're naturally parallelizable. If one needs another's output, they're naturally sequential. The patterns in this technology—Leaf, Sequencer, Fork-Join, Condition, Iteration, Aspects—are the fundamental ways data can flow through any system. They're not arbitrary design choices; they're the vocabulary for describing data transformation. + +### Common Language: Developer-Business Vocabulary + +The six patterns don't just describe code structure—they describe business processes. This creates a shared vocabulary between developers and business stakeholders. + +**Watch the precision gain:** + +> **Before:** "Get the user's stuff and show it" +> +> **After:** "Fork-Join: fetch profile, preferences, and history in parallel, then combine into dashboard view" + +Same requirement. One is vague. One is implementable. + +**The translation is mechanical:** + +- "Check if..." → **Leaf** → Single validation +- "First... then... then..." → **Sequencer** → `.flatMap()` chain +- "Get X and Y and Z, then..." → **Fork-Join** → `Promise.all()` +- "If... otherwise..." → **Condition** → Ternary/switch +- "For each..." → **Iteration** → `.map()` / loop +- "Always log/retry/timeout..." → **Aspects** → Wrapper function + +When a developer asks "Can these operations run in parallel?" they're really asking "Do these steps depend on each other's results?" + +When business says "First we verify, then we process, then we notify"—that's a Sequencer. Directly translatable to code. + +When business says "We need the user's profile, their preferences, and their history to show the dashboard"—that's a Fork-Join. Three independent fetches, one combined result. + +**Why this matters:** Requirements discussions become technical design sessions. Gaps surface during conversation, not during implementation. Code structure mirrors business process because they're the same thing. + ### Smart Wrappers (Monads) This technology uses **Smart Wrappers**—types that wrap values and control how operations are applied to them. @@ -2008,6 +2080,58 @@ private Promise recoverNetworkError(Cause cause) { ## Patterns Reference +### Gap Detection Through Patterns + +When you model business processes using these patterns, **gaps become visible**. The patterns don't just implement requirements—they validate them. + +**Missing validation:** +You're building a Sequencer: verify → process → notify. But what validates the input before "verify"? The pattern demands something produces the input for step one. If nothing does, you've found a gap. + +**Unclear dependencies:** +Business describes five things that need to happen. Are they a Sequencer (dependent chain) or Fork-Join (independent operations)? If they can't tell you which outputs feed which inputs, the process isn't fully defined. + +**Missing error handling:** +Every Leaf can fail. Every step in a Sequencer can fail. When you map business process to patterns, you naturally ask: "What happens when this fails?" If they don't know, you've found a gap. + +**Inefficient flows:** +Business describes a sequential process: get A, then get B, then get C, then combine. But if A, B, and C don't depend on each other, this should be Fork-Join, not Sequencer. The pattern reveals the inefficiency. + +### Discovery Questions by Pattern + +Each pattern generates specific questions. You're not inventing questions—the patterns generate them. + +**Leaf questions:** +- "What exactly does this operation do?" +- "Can it fail? What failures are possible?" +- "Is it sync (`Result`) or async (`Promise`)?" + +**Sequencer questions:** +- "What do we need from step 1 to perform step 2?" +- "Can step 3 ever happen if step 2 fails?" +- "Is this order fixed, or could steps be reordered?" + +**Fork-Join questions:** +- "Do these operations depend on each other?" +- "Can we fetch X while also fetching Y?" +- "What do we do if one succeeds and another fails?" + +**Condition questions:** +- "What determines which path we take?" +- "Are these paths mutually exclusive?" +- "Is there a default path?" + +**Iteration questions:** +- "Do we process all items or stop at first failure?" +- "Does order matter?" +- "Can items be processed independently (in parallel)?" + +**Aspects questions:** +- "Should we retry on failure? How many times?" +- "Is there a timeout?" +- "What needs to be logged/measured?" + +--- + ### Leaf **Definition:** A Leaf is the smallest unit of processing - a function that does one thing and has no internal steps. It's either a business leaf (pure computation) or an adapter leaf (I/O or side effects). diff --git a/README.md b/README.md index 9ce287e..f968567 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Java Backend Coding Technology -> **Version 2.1.1** | [Full Changelog](CHANGELOG.md) +> **Version 2.1.2** | [Full Changelog](CHANGELOG.md) A framework-agnostic methodology for writing predictable, testable Java backend code optimized for human-AI collaboration. @@ -231,7 +231,7 @@ void email_acceptsValidFormat() { ### Changelog & Versioning - **[CHANGELOG.md](CHANGELOG.md)** - Version history following [Keep a Changelog](https://keepachangelog.com/) - - Current version: 2.1.1 (2026-01-08) + - Current version: 2.1.2 (2026-01-12) - Golden formatting patterns, Pragmatica Lite 0.9.10, 36 lint rules - Semantic versioning for documentation releases @@ -392,6 +392,6 @@ If you find this useful, consider [sponsoring](https://github.com/sponsors/siy). --- -**Version:** 2.1.1 | **Last Updated:** 2026-01-08 | **[Full Changelog](CHANGELOG.md)** +**Version:** 2.1.2 | **Last Updated:** 2026-01-12 | **[Full Changelog](CHANGELOG.md)** **Copyright © 2025 Sergiy Yevtushenko. Released under the [MIT License](LICENSE).** diff --git a/ai-tools/agents/jbct-coder.md b/ai-tools/agents/jbct-coder.md index e8d5486..8a92704 100644 --- a/ai-tools/agents/jbct-coder.md +++ b/ai-tools/agents/jbct-coder.md @@ -1,7 +1,7 @@ --- name: jbct-coder title: Java Backend Coding Technology Agent -description: Specialized agent for generating business logic code using Java Backend Coding Technology v2.1.1 with Pragmatica Lite Core 0.9.10. Produces deterministic, AI-friendly code that matches human-written code structurally and stylistically. Includes evolutionary testing strategy guidance. +description: Specialized agent for generating business logic code using Java Backend Coding Technology v2.1.2 with Pragmatica Lite Core 0.9.10. Produces deterministic, AI-friendly code that matches human-written code structurally and stylistically. Includes evolutionary testing strategy guidance. tools: Read, Write, Edit, MultiEdit, Grep, Glob, LS, Bash, TodoWrite, Task, WebSearch, WebFetch --- @@ -1762,7 +1762,9 @@ public class JooqUserRepository implements SaveUser { ## References -- **Full Guide**: `CODING_GUIDE.md` - Comprehensive explanation of all patterns and principles (v2.1.1) +- **Full Guide**: `CODING_GUIDE.md` - Comprehensive explanation of all patterns and principles (v2.1.2) +- **Design Agent**: `ai-tools/agents/jbct-designer.md` - Use for architecture design and planning before coding +- **Review Agent**: `ai-tools/agents/jbct-reviewer.md` - Use for code review after implementation - **Testing Strategy**: `series/part-05-testing-strategy.md` - Evolutionary testing approach, integration-first philosophy, test organization - **Systematic Application**: `series/part-10-systematic-application.md` - Checkpoints for coding and review - **API Reference**: `CLAUDE.md` - Complete Pragmatica Lite API documentation diff --git a/ai-tools/agents/jbct-designer.md b/ai-tools/agents/jbct-designer.md new file mode 100644 index 0000000..a3b19a8 --- /dev/null +++ b/ai-tools/agents/jbct-designer.md @@ -0,0 +1,457 @@ +--- +name: jbct-designer +title: JBCT Design and Planning Agent +description: Specialized agent for JBCT-based architecture design and planning. Validates requirements, selects patterns, detects gaps, and produces implementation-ready designs before coding begins. Use before jbct-coder to front-load thinking and prevent issues. +tools: Read, Write, Edit, Grep, Glob, LS, WebSearch, Task, TodoWrite +--- + +# JBCT Design Agent + +You are an expert software architect specializing in **Java Backend Coding Technology (JBCT)** - a functional composition methodology that makes code structure predictable and deterministic. + +Your role is to **front-load thinking before coding**. You validate requirements, select appropriate patterns, detect gaps, and produce designs that translate directly to implementation. + +**Position in workflow:** +``` +Requirements → jbct-designer → jbct-coder → jbct-reviewer +``` + +**Core insight:** The "coding technology" is mostly about not coding. You'll spend time asking the right questions. The coding becomes mechanical once design is complete. + +--- + +## The Six Patterns + +Every data transformation falls into one of six patterns. These aren't design choices - they're the only ways data can flow: + +- **Leaf** - Single transformation, atomic, no substeps +- **Sequencer** - A → B → C, dependent chain, output becomes input +- **Fork-Join** - A + B + C → D, independent operations merging +- **Condition** - Route based on value, branching +- **Iteration** - Same transformation, many times +- **Aspects** - Wrap transformation (retry, timeout, logging) + +**Reality is constrained.** There's no seventh option. Data either transforms, chains, combines, branches, iterates, or gets wrapped. + +--- + +## Design Methodology + +### Step 1: Understand the Request Flow + +Map the request to the universal pattern: +``` +Input → Parse → Gather → Process → Respond → Output +``` + +Ask: +- What is the input? (HTTP request, message, command) +- What validation must pass before processing? +- What data must be gathered? +- What business logic transforms the data? +- What is the output format? + +### Step 2: Identify Pattern Structure + +For each stage, determine which pattern applies: + +| If you see... | Pattern | Code Structure | +|---------------|---------|----------------| +| Single atomic operation | Leaf | Pure function or `Promise.lift()` | +| "First... then... then..." | Sequencer | `.flatMap()` chain | +| "Get X and Y and Z, then..." | Fork-Join | `Result.all()` / `Promise.all()` | +| "If... otherwise..." | Condition | Ternary / switch expression | +| "For each..." | Iteration | `.map()` / loop | +| "Always log/retry/timeout..." | Aspects | Wrapper function | + +### Step 3: Apply Gap Detection + +Use pattern structure to find missing requirements. Each pattern demands specific information: + +**Leaf gaps:** +- What exactly does this operation do? +- Can it fail? What failures are possible? +- Is it sync (`Result`) or async (`Promise`)? + +**Sequencer gaps:** +- What does step 1 produce that step 2 needs? +- Can we proceed if a middle step fails? +- Is the order fixed or flexible? + +**Fork-Join gaps:** +- Are these truly independent (no shared data)? +- What if one succeeds and another fails? +- Can they run in parallel safely? + +**Condition gaps:** +- What determines the branch? +- Are branches mutually exclusive? +- Is there a default case? + +**Iteration gaps:** +- Stop on first failure or collect all? +- Does order matter? +- Can items process in parallel? + +**Aspects gaps:** +- How many retries? What backoff? +- What timeout duration? +- What must be logged/measured? + +### Step 4: Ask the Right Questions + +Questions emerge from patterns. Use this checklist: + +**At the start (Validation/Parsing):** +- "How do we know this request is valid?" +- "What makes [field] valid in your domain?" +- "What's the first thing we verify?" + +**For sequences:** +- "What do we need from step 1 to perform step 2?" +- "Can step 3 happen if step 2 fails?" +- "Is this order fixed?" + +**For parallel work:** +- "Do these operations depend on each other?" +- "Can we fetch X while also fetching Y?" +- "What if one succeeds and another fails?" + +**For branching:** +- "What determines which path?" +- "Are these mutually exclusive?" +- "Is there a default?" + +**For collections:** +- "Process all or stop at first failure?" +- "Does order matter?" +- "Can items process independently?" + +**For cross-cutting:** +- "Retry on failure? How many times?" +- "Timeout duration?" +- "What needs logging?" + +### Step 5: Define Value Objects + +For each input field, determine: + +1. **Type**: Primitive wrapper or composite? +2. **Validation rules**: What makes it valid? +3. **Optionality**: Required (`T`) or optional (`Option`)? +4. **Factory method**: `TypeName.typeName(String raw) → Result` + +Example analysis: +``` +Field: email +- Type: Email (record wrapping String) +- Validation: Not blank, matches pattern, max 255 chars +- Optionality: Required +- Factory: Email.email(String) → Result + +Field: referralCode +- Type: ReferralCode (record wrapping String) +- Validation: Alphanumeric, 8 chars +- Optionality: Optional +- Factory: ReferralCode.referralCode(String) → Result> +``` + +### Step 6: Define Error Types + +For each failure point, define: + +1. **Error name**: Noun-first, past tense (`EmailNotFound`, `PaymentFailed`) +2. **Category**: Validation error, business error, infrastructure error +3. **Message**: Fixed string or parameterized +4. **Recovery**: Can caller recover? How? + +Group related errors: +```java +public sealed interface UserError extends Cause { + enum Validation implements UserError { + INVALID_EMAIL, + PASSWORD_TOO_WEAK, + USERNAME_TAKEN + } + + enum Business implements UserError { + ACCOUNT_LOCKED, + EMAIL_NOT_VERIFIED + } +} +``` + +### Step 7: Design Step Interfaces + +For each step in the use case: + +1. **Name**: Verb + noun (`CheckEmailUniqueness`, `CreateUser`) +2. **Input**: Value objects from previous step +3. **Output**: `Result` or `Promise` +4. **Pattern**: Leaf, Sequencer, Fork-Join, etc. + +Example: +``` +Step: CheckEmailUniqueness +- Input: Email +- Output: Promise +- Pattern: Leaf (adapter) +- Failure: EmailAlreadyExists + +Step: CreateValidUser +- Input: (Email, Password, Option) +- Output: Result +- Pattern: Fork-Join (validate all, combine) +- Failures: Validation errors from each field +``` + +### Step 8: Compose the Use Case + +Determine overall composition: + +1. **Sync or async?** - Any I/O → async (`Promise`) +2. **Sequential or parallel?** - Check data dependencies +3. **Entry point**: `ValidRequest.validRequest(Request) → Result` +4. **Main flow**: Pattern of patterns (usually Sequencer of steps) + +--- + +## Output Format + +Produce a design document with: + +### 1. Overview +``` +Use Case: [Name] +Type: [Sync/Async] +Main Pattern: [Sequencer/Fork-Join/etc.] +``` + +### 2. Request Flow +``` +Input → [Stage 1] → [Stage 2] → ... → Output +``` + +### 3. Value Objects +| Field | Type | Validation | Optional | Factory | +|-------|------|------------|----------|---------| +| email | Email | pattern, length | No | `Email.email()` | + +### 4. Error Types +| Error | Category | When | +|-------|----------|------| +| EmailNotFound | Business | Lookup fails | + +### 5. Steps +| Step | Input | Output | Pattern | +|------|-------|--------|---------| +| ValidateRequest | Request | ValidRequest | Fork-Join | + +### 6. Composition +``` +ValidRequest.validRequest(request) + .async() + .flatMap(step1::execute) + .flatMap(step2::execute) + ... +``` + +### 7. Open Questions +- [Any unresolved ambiguities] + +### 8. Test Strategy +- Value object tests: [list validations to test] +- Use case tests: [list scenarios] + +--- + +## Common Design Patterns + +### Pattern: Request Validation (Fork-Join) +``` +Request contains: email, password, referralCode + +Design: +Result.all( + Email.email(request.email()), + Password.password(request.password()), + ReferralCode.referralCode(request.referralCode()) // returns Result> +).map(ValidRequest::new) +``` + +### Pattern: Sequential Processing (Sequencer) +``` +Steps: validate → check uniqueness → create → notify + +Design: +validRequest.async() + .flatMap(checkUniqueness::execute) + .flatMap(createUser::execute) + .flatMap(sendWelcome::execute) +``` + +### Pattern: Parallel Data Gathering (Fork-Join) +``` +Need: profile, preferences, history (independent) + +Design: +Promise.all( + loadProfile.execute(userId), + loadPreferences.execute(userId), + loadHistory.execute(userId) +).map(Dashboard::new) +``` + +### Pattern: Conditional Processing (Condition) +``` +Premium users get discount, others don't + +Design: +user.isPremium() + ? applyDiscount.execute(order) + : Promise.success(order) +``` + +### Pattern: Collection Processing (Iteration) +``` +Process each item in cart + +Design: +cart.items().stream() + .map(item -> calculateTax.execute(item)) + .collect(...) // or Promise.allOf for async +``` + +--- + +## Zone-Based Architecture + +Verify design respects zone boundaries: + +**Zone A (Use Case):** +- Orchestration only +- No business logic +- No I/O +- Composes Zone B and C + +**Zone B (Domain/Steps):** +- Business logic +- Pure functions where possible +- No direct I/O (delegates to adapters) + +**Zone C (Adapters):** +- All I/O happens here +- Database, HTTP, messaging +- Wraps external APIs + +**Check:** +- [ ] Use case only composes steps +- [ ] Steps don't call adapters directly (injected via interface) +- [ ] Adapters are behind interfaces +- [ ] No I/O in domain package + +--- + +## Vertical Slicing Check + +Each use case should be self-contained: + +``` +com.example.app/ +└── usecase/ + └── registeruser/ # Everything for RegisterUser + ├── RegisterUser.java # Interface + factory + ├── ValidRequest.java # Or nested in RegisterUser + ├── UserError.java # Use-case specific errors + └── steps/ # Internal steps + ├── CheckEmailUniqueness.java + └── CreateUser.java +``` + +**Check:** +- [ ] Use case has single package +- [ ] No dependencies on other use case internals +- [ ] Shared types in separate `domain` package +- [ ] Steps are internal (package-private or nested) + +--- + +## Handoff to jbct-coder + +When design is complete, provide: + +1. **Design document** (format above) +2. **Package structure** (where files go) +3. **Interface signatures** (exact method signatures) +4. **Test scenarios** (what to test) + +The coder should be able to implement mechanically from your design. + +--- + +## Red Flags During Design + +Stop and clarify if you see: + +- **Unclear dependencies**: "Does step B need step A's output?" +- **Mixed sync/async**: Some steps sync, others async (usually all should be async) +- **Vague validation**: "Validate the email" (what rules exactly?) +- **Missing error cases**: Happy path only, no failure handling +- **Circular dependencies**: Step A needs B, B needs A +- **God use case**: 10+ steps (consider splitting) +- **Shared mutable state**: Steps modifying common object + +--- + +## Example Design Session + +**Requirement:** "Register a new user with email, password, and optional referral code" + +**Design Process:** + +1. **Flow:** Input → Validate → Check uniqueness → Create → Send welcome → Output + +2. **Patterns:** + - Validate: Fork-Join (parallel validation of fields) + - Check uniqueness: Leaf (adapter call) + - Create: Leaf (adapter call) + - Send welcome: Leaf (adapter call) + - Overall: Sequencer (dependent steps) + +3. **Value Objects:** + - Email: required, pattern validation + - Password: required, strength validation + - ReferralCode: optional, format validation + +4. **Questions asked:** + - "Is referral code optional?" → Yes + - "What email patterns are valid?" → Standard RFC 5322 + - "Password requirements?" → Min 8 chars, 1 upper, 1 digit + - "What if email already exists?" → Fail with EmailAlreadyExists + - "Send welcome sync or async?" → Async (don't block registration) + +5. **Errors:** + - Validation: InvalidEmail, WeakPassword, InvalidReferralCode + - Business: EmailAlreadyExists + - Infrastructure: DatabaseUnavailable, EmailServiceDown + +6. **Composition:** + ``` + ValidRequest.validRequest(request) // Fork-Join validation + .async() + .flatMap(checkUniqueness::execute) // Leaf + .flatMap(createUser::execute) // Leaf + .flatMap(sendWelcome::execute) // Leaf + ``` + +Design complete. Ready for jbct-coder. + +--- + +## References + +- **CODING_GUIDE.md** - Complete JBCT reference +- **jbct-coder.md** - Implementation agent (receives your designs) +- **jbct-reviewer.md** - Review agent (validates implementations) +- **articles/six-patterns-that-cover-everything.md** - Pattern rationale +- **articles/underlying-process.md** - Data transformation philosophy diff --git a/ai-tools/agents/jbct-reviewer.md b/ai-tools/agents/jbct-reviewer.md index 151ccd0..104aee8 100644 --- a/ai-tools/agents/jbct-reviewer.md +++ b/ai-tools/agents/jbct-reviewer.md @@ -11,6 +11,16 @@ You are an expert code reviewer specializing in **Java Backend Coding Technology Your goal is to provide comprehensive, actionable code review focused on JBCT compliance while maintaining the general code quality principles of security, performance, and maintainability. +## Related Agents + +**JBCT workflow:** jbct-designer → jbct-coder → **jbct-reviewer** + +- **jbct-designer**: Use *before* implementation to validate architecture, select patterns, and detect requirement gaps +- **jbct-coder**: Use *during* implementation to generate JBCT-compliant code +- **jbct-reviewer** (this agent): Use *after* implementation to validate compliance + +If reviewing uncovers fundamental architectural issues, recommend running jbct-designer to redesign before fixing code. + ## Pragmatica Lite Core Library JBCT uses **Pragmatica Lite Core 0.9.10** for functional types (`Option`, `Result`, `Promise`). @@ -1419,6 +1429,21 @@ Before reviewing, enumerate ALL files to review: - Code clarity and maintainability - Documentation gaps +### Step 7: Gap Detection Through Patterns + +**Use patterns to detect requirement gaps:** + +| Pattern | Gap Signal | Question to Raise | +|---------|-----------|-------------------| +| **Leaf** | Missing validation | What inputs could be invalid? What errors could the external system return? | +| **Sequencer** | Unclear step boundaries | Are all steps explicit? Can any step fail? What happens on failure? | +| **Fork-Join** | Incomplete parallel data | Are all necessary pieces gathered? Do branches truly have no dependencies? | +| **Condition** | Missing branches | What if neither condition is met? Are there edge cases not handled? | +| **Iteration** | Unbounded processing | What's the maximum size? What if the collection is empty? | +| **Aspects** | Missing cross-cutting | Is there logging, metrics, or auth that should wrap this? | + +If gaps are detected, include them in the review output under "🔍 Detected Requirement Gaps". + ## REVIEW OUTPUT FORMAT Structure your review as follows: @@ -1572,6 +1597,22 @@ void validRequest_fails_forInvalidEmail() { --- +## 🔍 Detected Requirement Gaps + +[If gap detection revealed missing requirements or unclear behavior] + +### Gap 1: [Pattern-Detected Gap] +**Pattern**: Sequencer | **Location**: `path/to/file.ext:line` + +**Gap Signal**: [What pattern analysis revealed] +**Questions for stakeholders**: +- [Question about missing requirement] +- [Question about edge case behavior] + +**Recommendation**: Clarify with product/business before implementation. + +--- + ## 📚 JBCT Learning Opportunities [Educational notes about JBCT patterns, principles, or conventions that could benefit the team] diff --git a/ai-tools/skills/jbct/README.md b/ai-tools/skills/jbct/README.md index 78d609c..a357eb1 100644 --- a/ai-tools/skills/jbct/README.md +++ b/ai-tools/skills/jbct/README.md @@ -89,7 +89,7 @@ Claude Code navigates to specific files as needed, optimizing context usage. ## Version -Based on Java Backend Coding Technology v2.1.1 +Based on Java Backend Coding Technology v2.1.2 ## License diff --git a/articles/linkedin-data-transformation.md b/articles/linkedin-data-transformation.md new file mode 100644 index 0000000..0574484 --- /dev/null +++ b/articles/linkedin-data-transformation.md @@ -0,0 +1,47 @@ +# LinkedIn Post: Request Processing as Data Transformation + +--- + +**The insight that changed how I think about async code:** + +Request processing is data transformation. Always. Regardless of language or framework. + +When you receive a question, you don't answer immediately. You gather context. You retrieve knowledge. You combine pieces. You transform raw data into understanding. + +Software works identically: +``` +Input → Parse → Gather → Process → Respond → Output +``` + +Here's what this means: + +**Async looks exactly like sync** when you think in data flow: +```java +Result user = database.findUser(id); // "sync" +Promise user = api.fetchUser(id); // "async" +``` + +Same input. Same output. Only difference: *when* the result arrives. That's an execution detail, not a structural concern. + +**Parallel becomes transparent.** You don't decide "this should be parallel." You express data dependencies. The execution follows: + +- Need previous result? → Sequential +- Independent operations? → Naturally parallelizable + +The six patterns that cover everything: +- Leaf (single transform) +- Sequencer (A → B → C) +- Fork-Join (A + B + C → D) +- Condition (route by value) +- Iteration (transform collection) +- Aspects (wrap transform) + +Once you see request processing as data transformation, implementing any task in close to optimal form becomes routine. + +Not a paradigm. Not a methodology. The underlying reality every framework tries to express. + +--- + +Full article: [link to article] + +#SoftwareEngineering #Java #FunctionalProgramming #BackendDevelopment #CodeQuality diff --git a/articles/six-patterns-that-cover-everything.md b/articles/six-patterns-that-cover-everything.md new file mode 100644 index 0000000..e094b04 --- /dev/null +++ b/articles/six-patterns-that-cover-everything.md @@ -0,0 +1,177 @@ +--- +title: "The Six Patterns That Cover Everything" +tags: [java, functionalprogramming, architecture, backend] +canonical_url: https://pragmatica.dev/articles/six-patterns-that-cover-everything +published: true +description: "Six patterns describe every possible data flow. They also describe every business process. This isn't coincidence - it's why they work as a shared language between developers and business." +--- + +# The Six Patterns That Cover Everything + +## The Complete Vocabulary + +Every data transformation you'll ever write falls into one of six patterns: + +- **Leaf** - One thing. No substeps. Atomic. +- **Sequencer** - This, then that. Output becomes input. +- **Fork-Join** - These together, then combine. Independent operations merging. +- **Condition** - Which path? Route based on value. +- **Iteration** - Same thing, many times. Transform a collection. +- **Aspects** - Wrap it. Add retry, timeout, logging around an operation. + +That's it. Six patterns. They cover everything. + +Not "cover most cases." Not "work well for common scenarios." Everything. Every piece of request processing logic you'll ever write is one of these six, or a composition of them. + +## Why Only Six? + +These aren't design patterns someone invented. They're the fundamental ways data can flow: + +1. **Transform a value** (Leaf) +2. **Chain dependent transforms** (Sequencer) +3. **Combine independent transforms** (Fork-Join) +4. **Choose between transforms** (Condition) +5. **Apply transform to many values** (Iteration) +6. **Enhance a transform** (Aspects) + +There's no seventh option. Data either transforms, chains, combines, branches, iterates, or gets wrapped. That's the complete set of possibilities. + +This is why learning six patterns gives you everything. Not because JBCT is comprehensive - because reality is constrained. + +## The Strange Coincidence + +Here's what's remarkable: these same six patterns describe every business process. + +Think about any workflow in your domain: + +- **Leaf**: "Validate the email format" - one check, atomic +- **Sequencer**: "First verify identity, then check permissions, then grant access" - dependent chain +- **Fork-Join**: "Get user profile, account balance, and recent transactions, then build the dashboard" - independent data gathering +- **Condition**: "If premium user, apply discount; otherwise, standard pricing" - routing +- **Iteration**: "For each item in cart, calculate tax" - collection processing +- **Aspects**: "Log every payment attempt" - cross-cutting concern + +Business processes and code patterns use the same vocabulary. This isn't coincidence. It's because both describe how information flows and transforms. Business logic IS data transformation - we just use different words for it. + +## The Common Language + +This equivalence creates something powerful: a shared language between developers and business stakeholders. + +Watch the precision gain: + +> **Before:** "Get the user's stuff and show it" +> +> **After:** "Fork-Join: fetch profile, preferences, and history in parallel, then combine into dashboard view" + +Same requirement. One is vague. One is implementable. + +When a developer asks "Can these operations run in parallel?" they're really asking "Do these steps depend on each other's results?" + +When business says "First we verify, then we process, then we notify" - that's a Sequencer. Directly translatable to code. + +When business says "We need the user's profile, their preferences, and their history to show the dashboard" - that's a Fork-Join. Three independent fetches, one combined result. + +The translation becomes mechanical: + +- "Check if..." → **Leaf** → Single validation +- "First... then... then..." → **Sequencer** → `.flatMap()` chain +- "Get X and Y and Z, then..." → **Fork-Join** → `Promise.all()` +- "If... otherwise..." → **Condition** → Ternary/switch +- "For each..." → **Iteration** → `.map()` / loop +- "Always log/retry/timeout..." → **Aspects** → Wrapper function + +No translation layer. No impedance mismatch. The same six concepts, different vocabulary. + +## Gap Detection + +Here's where it gets interesting. When you model business processes using these patterns, gaps become visible. + +**Missing validation:** +You're building a Sequencer: verify -> process -> notify. But what validates the input before "verify"? The pattern demands something produces the input for step one. If nothing does, you've found a gap. + +**Unclear dependencies:** +Business describes five things that need to happen. Are they a Sequencer (dependent chain) or Fork-Join (independent operations)? If they can't tell you which outputs feed which inputs, the process isn't fully defined. + +**Missing error handling:** +Every Leaf can fail. Every step in a Sequencer can fail. When you map business process to patterns, you naturally ask: "What happens when this fails?" If they don't know, you've found a gap. + +**Inefficient flows:** +Business describes a sequential process: get A, then get B, then get C, then combine. But if A, B, and C don't depend on each other, this should be Fork-Join, not Sequencer. The pattern reveals the inefficiency. + +The patterns don't just implement requirements - they validate them. + +## The Right Questions + +Once you think in patterns, the right questions emerge naturally: + +**At the start (Leaf/Validation):** +- "How do we know this request is valid?" +- "What makes an email/phone/amount valid in your domain?" +- "What's the first thing we need to verify?" + +**For sequences (Sequencer):** +- "What do we need from step 1 to perform step 2?" +- "Can step 3 ever happen if step 2 fails?" +- "Is this order fixed, or could steps be reordered?" + +**For parallel work (Fork-Join):** +- "Do these operations depend on each other?" +- "Can we fetch user profile while also fetching their orders?" +- "What do we do if one succeeds and another fails?" + +**For branching (Condition):** +- "What determines which path we take?" +- "Are these paths mutually exclusive?" +- "Is there a default path?" + +**For collections (Iteration):** +- "Do we process all items or stop at first failure?" +- "Does order matter?" +- "Can items be processed independently (in parallel)?" + +**For cross-cutting concerns (Aspects):** +- "Should we retry on failure? How many times?" +- "Is there a timeout?" +- "What needs to be logged/measured?" + +You're not inventing questions. The patterns generate them. Each pattern has a fixed set of things that must be defined. If they're not defined, you ask. + +## From Patterns to Process Design + +The flow works both ways. + +**Forward:** Business describes a process -> you identify patterns -> you implement code + +**Backward:** You see the patterns -> you notice gaps -> you ask questions -> business clarifies -> process improves + +This backward flow is underrated. Developers who think in patterns become process consultants. They don't just implement what they're told - they improve what they're told by making implicit assumptions explicit. + +"You said first A, then B, then C. But B doesn't use A's output. Can B and A happen at the same time? That would be faster." + +"You said validate the request. What exactly are we validating? Email format? Email exists in system? User is active? Each is a separate check." + +"You said handle the error. Which error? Network timeout? Invalid data? User not found? Each might need different handling." + +The patterns force precision. Vague requirements become concrete when you have to place them in one of six boxes. + +## The Result + +When developers and business share this vocabulary: + +- Requirements discussions become technical design sessions +- Gaps surface during conversation, not during implementation +- Code structure mirrors business process (because they're the same thing) +- Changes in business process map directly to code changes +- New team members understand both business and code faster + +Six patterns. Complete coverage. Shared language. Gap detection built in. + +This is why pattern-based thinking isn't just a coding technique. It's a communication framework that makes the implicit explicit and the vague precise. + +The irony? You'll spend an hour asking the right questions. The coding takes 30 seconds. Turns out the "coding technology" is mostly about not coding. + +--- + +*Part of [Java Backend Coding Technology](https://pragmatica.dev) - a methodology for writing predictable, testable backend code.* + +**Previous:** [The Underlying Process of Request Processing](https://dev.to/siy/the-underlying-process-of-request-processing-1od4) diff --git a/articles/underlying-process.md b/articles/underlying-process.md new file mode 100644 index 0000000..cb88d90 --- /dev/null +++ b/articles/underlying-process.md @@ -0,0 +1,155 @@ +--- +title: "The Underlying Process of Request Processing" +tags: [java, functionalprogramming, architecture, backend] +canonical_url: https://pragmatica.dev/articles/underlying-process +published: true +description: "Request processing is data transformation. When you think in data flow, sync/async and parallel/sequential become transparent execution details." +--- + +# The Underlying Process of Request Processing + +## Beyond Languages and Frameworks + +Every request your system handles follows the same fundamental process. It doesn't matter if you're writing Java, Rust, or Python. It doesn't matter if you're using Spring, Express, or raw sockets. The underlying process is universal because it mirrors how humans naturally solve problems. + +When you receive a question, you don't answer immediately. You gather context. You retrieve relevant knowledge. You combine pieces of information. You transform raw data into meaningful understanding. Only then do you formulate a response. This is data transformation—taking input and gradually collecting necessary pieces of knowledge to provide a correct answer. + +Software request processing works identically. + +## The Universal Pattern + +Every request follows these stages: + +1. **Parse** - Transform raw input into validated domain objects +2. **Gather** - Collect necessary data from various sources +3. **Process** - Apply business logic to produce results +4. **Respond** - Transform results into appropriate output format + +This isn't a framework pattern. It's not a design choice. It's the fundamental nature of information processing. Whether you're handling an HTTP request, processing a message from a queue, or responding to a CLI command—the process is the same. + +``` +Input → Parse → Gather → Process → Respond → Output +``` + +Each stage transforms data. Each stage may need additional data. Each stage may fail. The entire flow is a data transformation pipeline. + +## Why Async Looks Like Sync + +Here's the insight that changes everything: **when you think in terms of data transformation, the sync/async distinction disappears**. + +Consider these two operations: + +```java +// "Synchronous" +Result user = database.findUser(userId); + +// "Asynchronous" +Promise user = httpClient.fetchUser(userId); +``` + +From a data transformation perspective, these are identical: +- Both take a user ID +- Both produce a User (or failure) +- Both are steps in a larger pipeline + +The only difference is *when* the result becomes available. But that's an execution detail, not a structural concern. Your business logic doesn't care whether the data came from local memory or crossed an ocean. It cares about what the data *is* and what to do with it. + +When you structure code as data transformation pipelines, this becomes obvious: + +```java +// The structure is identical regardless of sync/async +return userId.all( + id -> findUser(id), // Might be sync or async + id -> loadPermissions(id), // Might be sync or async + id -> fetchPreferences(id) // Might be sync or async +).map(this::buildContext); +``` + +The pattern doesn't change. The composition doesn't change. Only the underlying execution strategy changes—and that's handled by the types, not by you. + +## Parallel Execution Becomes Transparent + +The same principle applies to parallelism. When operations are independent, they can run in parallel. When they depend on each other, they must run sequentially. This isn't a choice you make—it's determined by the data flow. + +```java +// Sequential: each step needs the previous result +return validateInput(request) + .flatMap(this::createUser) + .flatMap(this::sendWelcomeEmail); + +// Parallel: steps are independent +return Promise.all( + fetchUserProfile(userId), + loadAccountSettings(userId), + getRecentActivity(userId) +).map(this::buildDashboard); +``` + +You don't decide "this should be parallel" or "this should be sequential." You express the data dependencies. The execution strategy follows from the structure. If operations share no data dependencies, they're naturally parallelizable. If one needs another's output, they're naturally sequential. + +This is why thinking in data transformation is so powerful. You describe *what* needs to happen and *what data flows where*. The *how*—sync vs async, sequential vs parallel—emerges from the structure itself. + +## The JBCT Patterns as Universal Primitives + +Java Backend Coding Technology captures this insight in six patterns: + +- **Leaf** - Single transformation (atomic) +- **Sequencer** - A → B → C, dependent chain (sequential) +- **Fork-Join** - A + B + C → D, independent merge (parallel-capable) +- **Condition** - Route based on value (branching) +- **Iteration** - Transform collection (map/fold) +- **Aspects** - Wrap transformation (decoration) + +These aren't arbitrary design patterns. They're the fundamental ways data can flow through a system: +- Transform a single value (Leaf) +- Chain dependent transformations (Sequencer) +- Combine independent transformations (Fork-Join) +- Choose between transformations (Condition) +- Apply transformation to many values (Iteration) +- Enhance a transformation (Aspects) + +Every request processing task—regardless of domain, language, or framework—decomposes into these six primitives. Once you internalize this, implementation becomes mechanical. You're not inventing structure; you're recognizing the inherent structure of the problem. + +## Optimal Implementation as Routine + +When you see request processing as data transformation, optimization becomes straightforward: + +1. **Identify independent operations** → They can parallelize (Fork-Join) +2. **Identify dependent chains** → They must sequence (Sequencer) +3. **Identify decision points** → They become conditions +4. **Identify collection processing** → They become iterations +5. **Identify cross-cutting concerns** → They become aspects + +You're not making architectural decisions. You're reading the inherent structure of the problem and translating it directly into code. + +This is why JBCT produces consistent code across developers and AI assistants. There's essentially one correct structure for any given data flow. Different people analyzing the same problem arrive at the same solution—not because they memorized patterns, but because the patterns are the natural expression of data transformation. + +## The Shift in Thinking + +Traditional programming asks: "What sequence of instructions produces the desired effect?" + +Data transformation thinking asks: "What shape does the data take at each stage, and what transformations connect them?" + +The first approach leads to imperative code where control flow dominates. The second leads to declarative pipelines where data flow dominates. + +When you make this shift: +- Async stops being "harder" than sync +- Parallel stops being "risky" +- Error handling stops being an afterthought +- Testing becomes straightforward (pure transformations are trivially testable) + +You're no longer fighting the machine to do what you want. You're describing transformations and letting the runtime figure out the optimal execution strategy. + +## Conclusion + +Request processing is data transformation. This isn't a paradigm or a methodology—it's the underlying reality that every paradigm and methodology is trying to express. + +Languages and frameworks provide different syntax. Some make data transformation easier to express than others. But the fundamental process doesn't change. Input arrives. Data transforms through stages. Output emerges. + +JBCT patterns aren't rules to memorize. They're the vocabulary for describing data transformation in Java. Once you see the underlying process clearly, using these patterns becomes as natural as describing what you see. + +The result: any processing task, implemented in close to optimal form, as a matter of routine. + +--- + +*Part of [Java Backend Coding Technology](../README.md) - a methodology for writing predictable, testable backend code.* diff --git a/book/TABLE_OF_CONTENTS.md b/book/TABLE_OF_CONTENTS.md index a22dad9..00f74b3 100644 --- a/book/TABLE_OF_CONTENTS.md +++ b/book/TABLE_OF_CONTENTS.md @@ -1,7 +1,7 @@ # Java Backend Coding Technology ## Unified Code Through Functional Composition -**Based on:** JBCT v2.1.1 | **Pragmatica Lite Core:** 0.9.10 +**Based on:** JBCT v2.1.2 | **Pragmatica Lite Core:** 0.9.10 --- diff --git a/book/ch01-introduction.md b/book/ch01-introduction.md index 1b7d5eb..ee3ebba 100644 --- a/book/ch01-introduction.md +++ b/book/ch01-introduction.md @@ -1,6 +1,6 @@ # Chapter 1: Introduction - Code Unification -**Based on:** JBCT v2.1.1 | **Pragmatica Lite Core:** 0.9.10 +**Based on:** JBCT v2.1.2 | **Pragmatica Lite Core:** 0.9.10 ## What You'll Learn @@ -41,6 +41,8 @@ The benefits compound: **Requirement discovery** becomes systematic. When you structure code as validation → steps → composition, gaps become obvious. Missing validation rules surface when you define value objects. Unclear business logic reveals itself when you can't name a step clearly. Edge cases emerge when you model errors as explicit types. +**Common language** emerges when patterns become vocabulary. The six patterns (Leaf, Sequencer, Fork-Join, Condition, Iteration, Aspects) describe both code structure and business processes. When business says "First we verify, then we process, then we notify"—that's a Sequencer. When they say "We need profile, preferences, and history"—that's a Fork-Join. The translation is mechanical, and requirements discussions become technical design sessions. + **Business logic as a readable language** happens when patterns become vocabulary. The four return types, parse-don't-validate, and the fixed pattern catalog form a consistent way to express domain concepts in code. Anyone who understands the domain can pick up a new codebase virtually instantly. **Deterministic code generation** becomes possible when the mapping from requirements to code is mechanical. Given a use case specification - inputs, outputs, validation rules, steps - there's essentially one correct structure. Different developers (or AI assistants) should produce nearly identical implementations. @@ -169,6 +171,49 @@ The second version **chains** operations. Each step takes the output of the prev Why this matters: composition lets you **build complex logic from simple pieces** without intermediate variables or explicit error checking at each step. The structure itself handles error propagation. +### Request Processing as Data Transformation + +Every request your system handles follows the same fundamental process. It doesn't depend on language or framework. It mirrors how humans naturally solve problems: take input, gradually collect necessary pieces of knowledge, and produce a correct answer. + +**The Universal Pattern:** +``` +Input → Parse → Gather → Process → Respond → Output +``` + +Each stage transforms data. Each stage may need additional data. Each stage may fail. The entire flow is a data transformation pipeline. + +**Why Async Looks Like Sync:** + +When you think in terms of data transformation, the sync/async distinction disappears: + +```java +// These are structurally identical +Result user = database.findUser(userId); // "sync" +Promise user = httpClient.fetchUser(userId); // "async" +``` + +Both take a user ID, both produce a User (or failure). The only difference is *when* the result becomes available—an execution detail, not a structural concern. + +**Parallel Execution Becomes Transparent:** + +You don't decide "this should be parallel." You express data dependencies. The execution strategy follows from the structure: + +```java +// Sequential: each step needs previous result +return validateInput(request) + .flatMap(this::createUser) + .flatMap(this::sendWelcomeEmail); + +// Parallel: steps are independent +return Promise.all( + fetchUserProfile(userId), + loadAccountSettings(userId), + getRecentActivity(userId) +).map(this::buildDashboard); +``` + +The JBCT patterns—Leaf, Sequencer, Fork-Join, Condition, Iteration, Aspects—are the fundamental ways data can flow through any system. Once you start thinking in data transformation, implementing any processing task in close to optimal form becomes routine. + ### What Are Monads (Smart Wrappers)? In JBCT, we use types that wrap values and control how operations are applied to them. diff --git a/book/ch07-basic-patterns.md b/book/ch07-basic-patterns.md index 93404f7..f35a248 100644 --- a/book/ch07-basic-patterns.md +++ b/book/ch07-basic-patterns.md @@ -290,6 +290,28 @@ If adding "to" makes it sound awkward or overly detailed ("to hash password, the --- +## Gap Detection Through Patterns + +When you model business processes using patterns, **gaps become visible**. The patterns validate requirements, not just implement them. + +**How patterns reveal gaps:** +- **Missing validation:** Building a Sequencer but nothing validates the input before step 1? Gap found. +- **Unclear dependencies:** Are these a Sequencer (dependent) or Fork-Join (independent)? If unknown, process isn't defined. +- **Missing error handling:** Every Leaf can fail. What happens when this fails? +- **Inefficient flows:** Sequential process described but steps are independent? Should be Fork-Join. + +**Discovery questions by pattern:** + +| Pattern | Key Questions | +|---------|--------------| +| **Leaf** | What does it do? Can it fail? Sync or async? | +| **Condition** | What determines the path? Mutually exclusive? Default? | +| **Iteration** | Stop on first failure? Order matters? Can parallelize? | + +Advanced patterns (Sequencer, Fork-Join, Aspects) covered in Chapter 8. + +--- + ## Pattern: Leaf **Definition:** A **Leaf** (an atomic operation with no substeps) is the smallest unit of processing - a function that does one thing and has no internal steps. It's either a business leaf (pure computation) or an adapter leaf (I/O or side effects). diff --git a/book/ch08-advanced-patterns.md b/book/ch08-advanced-patterns.md index 406b89a..b5245cf 100644 --- a/book/ch08-advanced-patterns.md +++ b/book/ch08-advanced-patterns.md @@ -10,6 +10,20 @@ --- +## Discovery Questions for Advanced Patterns + +Chapter 7 introduced gap detection. Here are the discovery questions for advanced patterns: + +| Pattern | Key Questions | +|---------|--------------| +| **Sequencer** | What does step 1 produce that step 2 needs? Can step 3 happen if step 2 fails? Is order fixed? | +| **Fork-Join** | Do these depend on each other? Can we fetch X while fetching Y? What if one succeeds and another fails? | +| **Aspects** | Retry on failure? How many times? Timeout duration? What needs logging? | + +These questions emerge from the patterns themselves—the structure demands specific information. + +--- + ## Pattern: Sequencer **Definition:** A Sequencer chains dependent steps linearly using `map` and `flatMap`. Each step's output feeds the next step's input. This is the primary pattern for use case implementation. diff --git a/book/manuscript/ch01-introduction.md b/book/manuscript/ch01-introduction.md index 1b7d5eb..ee3ebba 100644 --- a/book/manuscript/ch01-introduction.md +++ b/book/manuscript/ch01-introduction.md @@ -1,6 +1,6 @@ # Chapter 1: Introduction - Code Unification -**Based on:** JBCT v2.1.1 | **Pragmatica Lite Core:** 0.9.10 +**Based on:** JBCT v2.1.2 | **Pragmatica Lite Core:** 0.9.10 ## What You'll Learn @@ -41,6 +41,8 @@ The benefits compound: **Requirement discovery** becomes systematic. When you structure code as validation → steps → composition, gaps become obvious. Missing validation rules surface when you define value objects. Unclear business logic reveals itself when you can't name a step clearly. Edge cases emerge when you model errors as explicit types. +**Common language** emerges when patterns become vocabulary. The six patterns (Leaf, Sequencer, Fork-Join, Condition, Iteration, Aspects) describe both code structure and business processes. When business says "First we verify, then we process, then we notify"—that's a Sequencer. When they say "We need profile, preferences, and history"—that's a Fork-Join. The translation is mechanical, and requirements discussions become technical design sessions. + **Business logic as a readable language** happens when patterns become vocabulary. The four return types, parse-don't-validate, and the fixed pattern catalog form a consistent way to express domain concepts in code. Anyone who understands the domain can pick up a new codebase virtually instantly. **Deterministic code generation** becomes possible when the mapping from requirements to code is mechanical. Given a use case specification - inputs, outputs, validation rules, steps - there's essentially one correct structure. Different developers (or AI assistants) should produce nearly identical implementations. @@ -169,6 +171,49 @@ The second version **chains** operations. Each step takes the output of the prev Why this matters: composition lets you **build complex logic from simple pieces** without intermediate variables or explicit error checking at each step. The structure itself handles error propagation. +### Request Processing as Data Transformation + +Every request your system handles follows the same fundamental process. It doesn't depend on language or framework. It mirrors how humans naturally solve problems: take input, gradually collect necessary pieces of knowledge, and produce a correct answer. + +**The Universal Pattern:** +``` +Input → Parse → Gather → Process → Respond → Output +``` + +Each stage transforms data. Each stage may need additional data. Each stage may fail. The entire flow is a data transformation pipeline. + +**Why Async Looks Like Sync:** + +When you think in terms of data transformation, the sync/async distinction disappears: + +```java +// These are structurally identical +Result user = database.findUser(userId); // "sync" +Promise user = httpClient.fetchUser(userId); // "async" +``` + +Both take a user ID, both produce a User (or failure). The only difference is *when* the result becomes available—an execution detail, not a structural concern. + +**Parallel Execution Becomes Transparent:** + +You don't decide "this should be parallel." You express data dependencies. The execution strategy follows from the structure: + +```java +// Sequential: each step needs previous result +return validateInput(request) + .flatMap(this::createUser) + .flatMap(this::sendWelcomeEmail); + +// Parallel: steps are independent +return Promise.all( + fetchUserProfile(userId), + loadAccountSettings(userId), + getRecentActivity(userId) +).map(this::buildDashboard); +``` + +The JBCT patterns—Leaf, Sequencer, Fork-Join, Condition, Iteration, Aspects—are the fundamental ways data can flow through any system. Once you start thinking in data transformation, implementing any processing task in close to optimal form becomes routine. + ### What Are Monads (Smart Wrappers)? In JBCT, we use types that wrap values and control how operations are applied to them. diff --git a/series/INDEX.md b/series/INDEX.md index 4c644b5..7155a39 100644 --- a/series/INDEX.md +++ b/series/INDEX.md @@ -1,6 +1,6 @@ # Java Backend Coding Technology: Complete Learning Series -**Based on:** [CODING_GUIDE.md](../CODING_GUIDE.md) v2.1.1 +**Based on:** [CODING_GUIDE.md](../CODING_GUIDE.md) v2.1.2 ## About This Series diff --git a/series/part-01-foundations.md b/series/part-01-foundations.md index 8908026..3e31737 100644 --- a/series/part-01-foundations.md +++ b/series/part-01-foundations.md @@ -30,6 +30,15 @@ The benefits compound: **Asking correct questions** becomes easy because the technology provides a framework for inquiry. When discussing requirements with domain experts, you can ask: "What validation rules apply to this field?" (maps to value object factories). "What happens if this step fails?" (maps to error types). "Can these operations run in parallel?" (maps to Fork-Join vs. Sequencer). "Is this value optional or required?" (maps to `Option` vs `T`). The questions are grounded in structure, not abstraction, so answers are concrete and immediately implementable. +**Common language** emerges when patterns become vocabulary. The six patterns (Leaf, Sequencer, Fork-Join, Condition, Iteration, Aspects) describe both code structure and business processes. When business says "First we verify, then we process, then we notify"—that's a Sequencer. When they say "We need profile, preferences, and history to show the dashboard"—that's a Fork-Join. The translation is mechanical: + +- "Check if..." → **Leaf** → Single validation +- "First... then... then..." → **Sequencer** → `.flatMap()` chain +- "Get X and Y and Z, then..." → **Fork-Join** → `Promise.all()` +- "If... otherwise..." → **Condition** → Ternary/switch + +This shared vocabulary means requirements discussions become technical design sessions. Gaps surface during conversation, not during implementation. + **Business logic as a readable language** happens when patterns become vocabulary. The four return types, parse-don't-validate, and the fixed pattern catalog form a Business Logic Expression Language - a consistent way to express domain concepts in code. When you use the same patterns everywhere, business logic becomes immediately apparent in all necessary details. The structure itself tells the story: a Sequencer shows process steps, Fork-Join reveals parallel operations, `Result>` declares "optional but must be valid when present." Anyone who somewhat understands the domain can pick up a new codebase virtually instantly. No more narrow specializations where only one developer understands "their" module. A large part of the code becomes universally readable. Fresh onboarding happens in days, not months - developers spend time learning the domain, not deciphering structural choices. **Tooling and automation** become dramatically simpler when the structure is predictable. Code generators don't need to infer patterns - there's one pattern for validation, one for composition, one for error handling. Static analysis can verify properties mechanically: does this function return exactly one of the four allowed types? Does validation happen before construction? Are errors properly typed? AI assistants can generate more accurate code because the target structure is well-defined and consistent. diff --git a/series/part-05-basic-patterns.md b/series/part-05-basic-patterns.md index aac1906..a498d5f 100644 --- a/series/part-05-basic-patterns.md +++ b/series/part-05-basic-patterns.md @@ -386,6 +386,28 @@ If adding "to" makes it sound awkward or overly detailed ("to hash password, the --- +## Gap Detection and Discovery Questions + +When you model business processes using patterns, **gaps become visible**. The patterns don't just implement requirements—they validate them. + +**How patterns reveal gaps:** +- **Missing validation:** Building a Sequencer but nothing validates the input before step 1? Gap found. +- **Unclear dependencies:** Are these operations a Sequencer (dependent) or Fork-Join (independent)? If they can't tell you which outputs feed which inputs, the process isn't fully defined. +- **Missing error handling:** Every Leaf can fail. When you map process to pattern, you naturally ask "What happens when this fails?" +- **Inefficient flows:** Sequential process described but steps are independent? Should be Fork-Join, not Sequencer. + +**Discovery questions by pattern:** + +| Pattern | Key Questions | +|---------|--------------| +| **Leaf** | What does it do? Can it fail? Sync or async? | +| **Condition** | What determines the path? Mutually exclusive? Default? | +| **Iteration** | Stop on first failure? Order matters? Can parallelize? | + +Advanced patterns (Sequencer, Fork-Join, Aspects) are covered in Part 6 with their specific discovery questions. + +--- + ## Pattern: Leaf **Definition:** A **Leaf** (an atomic operation with no substeps) is the smallest unit of processing - a function that does one thing and has no internal steps. It's either a business leaf (pure computation) or an adapter leaf (I/O or side effects). diff --git a/series/part-06-advanced-patterns.md b/series/part-06-advanced-patterns.md index ae6d3c6..f787e20 100644 --- a/series/part-06-advanced-patterns.md +++ b/series/part-06-advanced-patterns.md @@ -22,6 +22,20 @@ These patterns compose the basic building blocks you learned in Part 3. Together --- +## Discovery Questions for Advanced Patterns + +Part 5 introduced gap detection. Here are the discovery questions for advanced patterns: + +| Pattern | Key Questions | +|---------|--------------| +| **Sequencer** | What does step 1 produce that step 2 needs? Can step 3 happen if step 2 fails? Is order fixed? | +| **Fork-Join** | Do these depend on each other? Can we fetch X while fetching Y? What if one succeeds and another fails? | +| **Aspects** | Retry on failure? How many times? Timeout duration? What needs logging? | + +These questions emerge from the patterns themselves. You're not inventing questions—the structure demands specific information. + +--- + ## Pattern: Sequencer **Definition:** A Sequencer chains dependent steps linearly using `map` and `flatMap`. Each step's output feeds the next step's input. This is the primary pattern for use case implementation.