404kidwiz

java-architect

6
0
# Install this skill:
npx skills add 404kidwiz/claude-supercode-skills --skill "java-architect"

Install specific skill from multi-skill repository

# Description

Expert Java architect specializing in Java 21, Spring Boot 3, and Jakarta EE ecosystem. This agent excels at designing enterprise-grade applications with modern Java features, microservices architecture, and comprehensive enterprise integration patterns.

# SKILL.md


name: java-architect
description: Expert Java architect specializing in Java 21, Spring Boot 3, and Jakarta EE ecosystem. This agent excels at designing enterprise-grade applications with modern Java features, microservices architecture, and comprehensive enterprise integration patterns.


Java Architect Specialist

Purpose

Provides expert Java architecture expertise specializing in Java 21, Spring Boot 3, and Jakarta EE ecosystem. Designs enterprise-grade applications with modern Java features (virtual threads, pattern matching), microservices architecture, and comprehensive enterprise integration patterns for scalable, maintainable systems.

When to Use

  • Building enterprise applications with Spring Boot 3 (microservices, REST APIs)
  • Implementing Java 21 features (virtual threads, pattern matching, records, sealed classes)
  • Designing microservices architecture with Spring Cloud (service discovery, circuit breakers)
  • Developing Jakarta EE applications (CDI, JPA, JAX-RS)
  • Creating reactive applications with Spring WebFlux
  • Building event-driven systems (Kafka, RabbitMQ)
  • Optimizing JVM performance (GC tuning, profiling)

Core Capabilities

Enterprise Architecture

  • Designing microservices and monolith architectures
  • Implementing domain-driven design patterns (aggregates, bounded contexts)
  • Configuring Spring Cloud ecosystem (Eureka, Config, Gateway)
  • Building API-first architectures with OpenAPI/Swagger

Modern Java Development

  • Implementing Java 21 virtual threads for high concurrency
  • Using pattern matching and sealed classes for type safety
  • Building records and data classes for immutable models
  • Applying functional programming patterns with streams

Spring Ecosystem

  • Spring Boot application configuration and deployment
  • Spring Data JPA for database access and optimization
  • Spring Security for authentication and authorization
  • Spring WebFlux for reactive, non-blocking applications

Performance Optimization

  • JVM tuning and garbage collection configuration
  • Memory profiling and leak detection
  • Connection pooling and database optimization
  • Application startup optimization with GraalVM

---

2. Decision Framework

Spring Framework Selection Decision Tree

Application Requirements
│
├─ Need reactive, non-blocking I/O?
│  └─ Spring WebFlux ✓
│     - Netty/Reactor runtime
│     - Backpressure support
│     - High concurrency (100K+ connections)
│
├─ Traditional servlet-based web app?
│  └─ Spring MVC ✓
│     - Tomcat/Jetty runtime
│     - Familiar blocking model
│     - Easier debugging
│
├─ Microservices with service discovery?
│  └─ Spring Cloud ✓
│     - Eureka/Consul for discovery
│     - Config server
│     - API gateway (Spring Cloud Gateway)
│
├─ Batch processing?
│  └─ Spring Batch ✓
│     - Chunk-oriented processing
│     - Job scheduling
│     - Transaction management
│
└─ Need minimal footprint?
   └─ Spring Boot with GraalVM Native Image ✓
      - AOT compilation
      - Fast startup (<100ms)
      - Low memory (<50MB)

JPA vs JDBC Decision Matrix

Factor Use JPA/Hibernate Use JDBC (Spring JdbcTemplate)
Complexity Complex domain models with relationships Simple queries, reporting
Performance OLTP with caching (2nd-level cache) OLAP, bulk operations
Type safety Criteria API, type-safe queries Plain SQL with RowMapper
Maintenance Schema evolution with migrations Direct SQL control
Learning curve Steeper (lazy loading, cascades) Simpler, explicit
N+1 queries Risk (needs @EntityGraph, fetch joins) Explicit control

Example decision: E-commerce order system with relationships → JPA (Order → OrderItems → Products)
Example decision: Analytics dashboard with aggregations → JDBC (complex SQL, performance-critical)

Virtual Threads (Project Loom) Decision Path

Concurrency Requirements
│
├─ High thread count (>1000 threads)?
│  └─ Virtual Threads ✓
│     - Millions of threads possible
│     - No thread pool tuning
│     - Blocking code becomes cheap
│
├─ I/O-bound operations (DB, HTTP)?
│  └─ Virtual Threads ✓
│     - JDBC calls don't block platform threads
│     - HTTP client calls scale better
│
├─ CPU-bound operations?
│  └─ Platform Threads (ForkJoinPool) ✓
│     - Virtual threads don't help
│     - Use parallel streams
│
└─ Need compatibility with existing code?
   └─ Virtual Threads ✓
      - Drop-in replacement for Thread
      - No code changes required

Red Flags → Escalate to Oracle

Observation Why Escalate Example
JPA N+1 queries causing 1000+ DB calls Complex lazy loading issue "Single page load triggers 500 SELECT queries"
Circular dependency in Spring beans Architectural design problem "BeanCurrentlyInCreationException during startup"
Memory leak despite GC tuning Complex object retention "Heap grows to max despite Full GC, heap dump shows mysterious retention"
Distributed transaction spanning multiple microservices SAGA pattern or compensating transactions "Need ACID across Order, Payment, Inventory services"
Reactive stream backpressure overload Complex reactive pipeline "Flux overproducing, downstream can't keep up"

---

Workflow 2: Event-Driven Microservice with Kafka

Scenario: Implement event sourcing for order service

Step 1: Configure Spring Kafka

// Configuration/KafkaConfig.java
@Configuration
@EnableKafka
public class KafkaConfig {

    @Value("${spring.kafka.bootstrap-servers}")
    private String bootstrapServers;

    @Bean
    public ProducerFactory<String, DomainEvent> producerFactory() {
        Map<String, Object> config = Map.of(
            ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers,
            ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class,
            ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class,
            ProducerConfig.ACKS_CONFIG, "all",
            ProducerConfig.RETRIES_CONFIG, 3,
            ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true
        );

        return new DefaultKafkaProducerFactory<>(config);
    }

    @Bean
    public KafkaTemplate<String, DomainEvent> kafkaTemplate() {
        return new KafkaTemplate<>(producerFactory());
    }

    @Bean
    public ConsumerFactory<String, DomainEvent> consumerFactory() {
        Map<String, Object> config = Map.of(
            ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers,
            ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class,
            ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class,
            ConsumerConfig.GROUP_ID_CONFIG, "order-service",
            ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest",
            ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false,
            JsonDeserializer.TRUSTED_PACKAGES, "com.example.order.domain.events"
        );

        return new DefaultKafkaConsumerFactory<>(config);
    }
}

Step 2: Define domain events

// Domain/Events/DomainEvent.java
public sealed interface DomainEvent permits 
    OrderCreated, OrderItemAdded, OrderProcessingStarted, OrderCompleted, OrderCancelled {

    UUID aggregateId();
    LocalDateTime occurredAt();
    long version();
}

public record OrderCreated(
    UUID aggregateId,
    UUID customerId,
    LocalDateTime occurredAt,
    long version
) implements DomainEvent {}

public record OrderItemAdded(
    UUID aggregateId,
    UUID productId,
    int quantity,
    BigDecimal unitPrice,
    LocalDateTime occurredAt,
    long version
) implements DomainEvent {}

public record OrderCompleted(
    UUID aggregateId,
    BigDecimal totalAmount,
    LocalDateTime occurredAt,
    long version
) implements DomainEvent {}

Step 3: Event publisher

// Infrastructure/EventPublisher.java
@Component
public class DomainEventPublisher {

    private final KafkaTemplate<String, DomainEvent> kafkaTemplate;
    private static final String TOPIC = "order-events";

    public DomainEventPublisher(KafkaTemplate<String, DomainEvent> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    @Async
    public CompletableFuture<Void> publish(DomainEvent event) {
        return kafkaTemplate.send(TOPIC, event.aggregateId().toString(), event)
            .thenAccept(result -> {
                var metadata = result.getRecordMetadata();
                log.info("Published event: {} to partition {} offset {}",
                    event.getClass().getSimpleName(),
                    metadata.partition(),
                    metadata.offset());
            })
            .exceptionally(ex -> {
                log.error("Failed to publish event: {}", event, ex);
                return null;
            });
    }
}

Step 4: Event consumer

// Infrastructure/OrderEventConsumer.java
@Component
public class OrderEventConsumer {

    private final OrderProjectionService projectionService;

    @KafkaListener(
        topics = "order-events",
        groupId = "order-read-model",
        containerFactory = "kafkaListenerContainerFactory"
    )
    public void handleEvent(
        @Payload DomainEvent event,
        @Header(KafkaHeaders.RECEIVED_PARTITION) int partition,
        @Header(KafkaHeaders.OFFSET) long offset
    ) {
        log.info("Received event: {} from partition {} offset {}", 
            event.getClass().getSimpleName(), partition, offset);

        switch (event) {
            case OrderCreated e -> projectionService.handleOrderCreated(e);
            case OrderItemAdded e -> projectionService.handleOrderItemAdded(e);
            case OrderCompleted e -> projectionService.handleOrderCompleted(e);
            case OrderCancelled e -> projectionService.handleOrderCancelled(e);
            default -> log.warn("Unknown event type: {}", event);
        }
    }
}

Expected outcome:
- Event-driven architecture with Kafka
- Type-safe event handling (sealed interfaces, pattern matching)
- Async event publishing with CompletableFuture
- Idempotent event processing

---

4. Patterns & Templates

Pattern 1: Repository Pattern with Specifications

Use case: Type-safe dynamic queries

// Specification for dynamic filtering
public class OrderSpecifications {

    public static Specification<Order> hasCustomerId(CustomerId customerId) {
        return (root, query, cb) -> 
            cb.equal(root.get("customerId"), customerId);
    }

    public static Specification<Order> hasStatus(OrderStatus status) {
        return (root, query, cb) -> 
            cb.equal(root.get("status"), status);
    }

    public static Specification<Order> createdBetween(LocalDateTime start, LocalDateTime end) {
        return (root, query, cb) -> 
            cb.between(root.get("createdAt"), start, end);
    }

    public static Specification<Order> totalGreaterThan(BigDecimal amount) {
        return (root, query, cb) -> 
            cb.greaterThan(root.get("totalAmount"), amount);
    }
}

// Usage: Combine specifications
Specification<Order> spec = Specification
    .where(hasCustomerId(customerId))
    .and(hasStatus(new OrderStatus.Pending()))
    .and(createdBetween(startDate, endDate));

List<Order> orders = orderRepository.findAll(spec);

---

Pattern 3: CQRS with Separate Read/Write Models

Use case: Optimize reads independently from writes

// Write model (domain entity)
@Entity
public class Order {
    // Rich behavior, complex relationships
    public void addItem(Product product, int quantity) { ... }
    public void complete() { ... }
}

// Read model (denormalized projection)
@Entity
@Table(name = "order_summary")
@Immutable
public class OrderSummary {

    @Id
    private UUID orderId;
    private UUID customerId;
    private String customerName;
    private int itemCount;
    private BigDecimal totalAmount;
    private String status;
    private LocalDateTime createdAt;

    // Getters only (no setters, immutable)
}

// Read repository (optimized queries)
public interface OrderSummaryRepository extends JpaRepository<OrderSummary, UUID> {

    @Query("""
        SELECT os FROM OrderSummary os
        WHERE os.customerId = :customerId
        ORDER BY os.createdAt DESC
        """)
    List<OrderSummary> findByCustomerId(@Param("customerId") UUID customerId);
}

---

❌ Anti-Pattern: LazyInitializationException

What it looks like:

@Service
@Transactional
public class OrderService {

    public Order findById(OrderId id) {
        return orderRepository.findById(id).orElseThrow();
    }
}

@RestController
public class OrderController {

    @GetMapping("/orders/{id}")
    public OrderDto getOrder(@PathVariable UUID id) {
        Order order = orderService.findById(new OrderId(id));

        // Transaction already closed!
        var items = order.getItems(); // LazyInitializationException!

        return new OrderDto(order, items);
    }
}

Why it fails:
- Lazy loading outside transaction: Hibernate proxy can't load data
- N+1 queries: Even if transaction open, lazy loads trigger multiple queries

Correct approach:

// Option 1: Eager fetch with @EntityGraph
@Repository
public interface OrderRepository extends JpaRepository<Order, OrderId> {

    @EntityGraph(attributePaths = {"items", "items.product"})
    Optional<Order> findById(OrderId id);
}

// Option 2: DTO projection (no lazy loading)
@Query("""
    SELECT new com.example.dto.OrderDto(
        o.id, o.customerId, o.totalAmount,
        COUNT(i.id), o.status, o.createdAt
    )
    FROM Order o
    LEFT JOIN o.items i
    WHERE o.id = :id
    GROUP BY o.id, o.customerId, o.totalAmount, o.status, o.createdAt
    """)
Optional<OrderDto> findOrderDtoById(@Param("id") OrderId id);

// Option 3: Open Session in View (not recommended for APIs)
spring.jpa.open-in-view: false  // Disable to catch lazy loading issues early

---

6. Integration Patterns

backend-developer:

  • Handoff: Backend-developer defines business logic → java-architect implements with Spring Boot patterns
  • Collaboration: REST API design, database schema, authentication/authorization
  • Tools: Spring Boot, Spring Security, Spring Data JPA, Jackson
  • Example: Backend defines order workflow → java-architect implements with DDD aggregates and domain events

database-optimizer:

  • Handoff: Java-architect identifies slow JPA queries → database-optimizer creates indexes
  • Collaboration: Query optimization, connection pooling, transaction tuning
  • Tools: Hibernate statistics, JPA Criteria API, native queries
  • Example: N+1 query problem → database-optimizer adds composite index on foreign keys

devops-engineer:

  • Handoff: Java-architect builds Spring Boot app → devops-engineer containerizes with Docker
  • Collaboration: Health checks, metrics (Actuator), graceful shutdown
  • Tools: Spring Boot Actuator, Micrometer, Docker multi-stage builds
  • Example: Java-architect exposes /actuator/health → devops-engineer configures Kubernetes liveness probe

kubernetes-specialist:

  • Handoff: Java-architect builds microservice → kubernetes-specialist deploys to K8s
  • Collaboration: Readiness probes, resource limits, rolling updates
  • Tools: Spring Cloud Kubernetes, ConfigMaps, Secrets
  • Example: Java-architect uses @ConfigurationProperties → kubernetes-specialist provides ConfigMap

graphql-architect:

  • Handoff: Java-architect provides domain model → graphql-architect exposes as GraphQL API
  • Collaboration: Schema design, N+1 prevention with DataLoader
  • Tools: Spring GraphQL, GraphQL Java, DataLoader
  • Example: Order aggregate → GraphQL type with resolvers and subscriptions

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.