Java Omnibus
OOAD & Architecture / J2EE / Jakarta EE Patterns / Service to Worker Pattern
J2EE Presentation Java Order Management
Presentation

Service to Worker Pattern

Service to Worker separates request handling, business execution, and rendering so the web layer stays coordinated without collapsing into controller-centric business logic.

Why This Topic Matters

Why it matters in enterprise Java

Checkout, returns, and order placement flows often need validation, business orchestration, and then a rendered success or failure screen. Service to Worker gives that flow a clean shape.

Pattern Essentials

Intent, problem, and solution

Intent

What the pattern is trying to achieve

Coordinate request handling, business processing, and view rendering as distinct steps in one web flow.

Problem

What goes wrong without it

Controllers often mix parameter parsing, business orchestration, and rendering decisions in one place.

Solution

How the pattern answers the problem

Use the controller to receive the request, invoke application services, populate the model, and forward to a dedicated view.

Modern Relevance

Why it still matters now

This remains the dominant shape of many Spring MVC web flows and server-rendered business applications.

Structure

How the collaboration works

  • Request enters a controller or front controller.
  • Controller delegates the main use case to a service.
  • The result is prepared into a view model.
  • A dedicated view renders the response.
Java Example

Java example in the Order Management domain

Java example: checkout flow with service orchestration and rendered outcome
package org.javaomnibus.ecommerce.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public final class CheckoutController {
    private final CheckoutApplicationService checkoutApplicationService;

    public CheckoutController(CheckoutApplicationService checkoutApplicationService) {
        this.checkoutApplicationService = checkoutApplicationService;
    }

    @PostMapping("/checkout")
    public String checkout(CheckoutForm form, Model model) {
        CheckoutReceipt receipt = checkoutApplicationService.checkout(form.toCommand());
        model.addAttribute("receipt", receipt);
        return "checkout-success";
    }
}
Code Walkthrough

Step by step

  1. The controller handles web concerns and delegates the use case.
  2. The application service owns the main checkout orchestration.
  3. The model is populated for the view instead of the service rendering directly.
  4. The rendered template remains separate from business execution.
Real-World Usage

Where this pattern shows up

  • Server-rendered form submission flows
  • Order placement and returns flows
  • Web applications where business work must complete before rendering a response
When Not To Use

Cases where another shape is better

  • Pure JSON APIs where no view rendering exists
  • Static pages with negligible business processing
Trade-Offs

Trade-offs and design pressure

  • Controllers can still become fat if the service boundary is weak.
  • The pattern adds some ceremony, but that ceremony often pays for itself in maintainability.
Comparison Note

How this differs from nearby patterns

Service to Worker is stronger than Dispatcher View when meaningful business processing occurs before rendering. Dispatcher View is lighter when the controller mostly prepares a model and forwards.

Common Misuse

Mistakes to avoid

  • Keeping orchestration in the controller instead of the application service
  • Using the service to build HTML or framework-specific response models
  • Letting the controller access persistence directly
Related Pages

Related concepts


What To Read Next