Capstone: A Real Java Application

Wrap-Up & Next Steps

15 min Lesson 10 of 13

Wrap-Up & Next Steps

You have reached the final lesson of the Java Programming course. Over the previous nine capstone lessons you designed an architecture, modelled a domain, built a data layer with JDBC, enforced business rules, wired up an application interface, hardened the system with proper error handling and validation, wrote a real test suite, and packaged the application into a runnable JAR. This lesson is about consolidating that experience and charting a deliberate path forward as a professional Java developer.

What You Built — and Why It Matters

The capstone project was intentionally modest in scope but professional in structure. Every decision reflected real-world trade-offs:

  • Layered architecture — separating domain, repository, service, and interface layers keeps each concern testable and replaceable independently.
  • Domain-first modelling — building record-based value objects and rich domain entities before touching the database forced you to think about the problem, not the technology.
  • Repository pattern over raw JDBC — hiding SQL behind an interface means you can swap the data store (H2 → PostgreSQL → JPA) without touching business logic.
  • Checked exceptions at the boundary, unchecked inside — surfacing errors meaningfully at API boundaries while avoiding exception plumbing in core logic is the industry standard.
  • JUnit 5 + Mockito — testing services in isolation with mocked repositories gives fast, reliable feedback without a live database.
  • Maven + executable JAR — reproducible builds with a single mvn package command and a self-contained artefact that runs anywhere with a JRE.
Small project, transferable patterns. Every pattern you used here — layered architecture, repository abstraction, domain modelling, test doubles, checked-vs-unchecked exception strategy — is the same pattern used in large enterprise codebases. Scale changes the quantity, not the shape.

Common Mistakes to Reflect On

Before moving forward, do an honest retrospective on your capstone code. Ask these questions:

  • Do any service methods reach past the repository and touch raw JDBC? If so, the layer boundary is leaking — push that SQL down.
  • Are any domain classes public with no-arg constructors and public setters? That makes them anemic and easy to put in invalid state. Prefer constructor injection and records or builder patterns.
  • Are you catching Exception broadly and swallowing the stack trace? Catch the narrowest type you can handle; log or rethrow everything else.
  • Do your tests actually fail when you break something? If every test passes after you delete business logic, the tests are not testing the right things.
  • Is the main method doing business logic? It should do nothing but wire dependencies and start the application.
Anemic domain model is the most common anti-pattern in Java enterprise code. Classes that are just bags of getters/setters with all logic in "Service" or "Manager" classes are hard to test, easy to corrupt, and violate encapsulation. Push behaviour into the class that owns the data.

Immediate Next Steps: Going Deeper in the Java Ecosystem

The skills you have now are the foundation. Here is a prioritised roadmap for what to study next, with honest guidance on when each topic becomes relevant:

1. Spring Boot (highest priority)

Spring Boot is the dominant Java application framework. It replaces manual JDBC and wiring with declarative configuration, an embedded web server, JPA/Hibernate ORM, security, and production-ready ops endpoints. The patterns you learned (dependency injection via constructor, layered architecture, repositories) map directly to Spring idioms.

// Spring Boot repository — same pattern, zero boilerplate public interface ProductRepository extends JpaRepository<Product, Long> { List<Product> findByActiveTrue(); Optional<Product> findBySkuIgnoreCase(String sku); } // Spring Boot service — same structure as your capstone service @Service @Transactional public class ProductService { private final ProductRepository repo; public ProductService(ProductRepository repo) { this.repo = repo; } public Product create(CreateProductCommand cmd) { if (repo.findBySkuIgnoreCase(cmd.sku()).isPresent()) { throw new ConflictException("SKU already exists: " + cmd.sku()); } return repo.save(new Product(cmd.sku(), cmd.name(), cmd.price())); } }

Notice that the constructor-injection style you practised, the service/repository split, and the custom exception strategy all carry over directly. Spring Boot is not a rewrite of your knowledge — it is an upgrade of the plumbing.

2. Java Persistence API (JPA) and Hibernate

Once you understand how JDBC works (you do now), JPA makes sense. It maps objects to tables automatically, manages transactions, handles lazy loading, and generates common queries. The risk is developers using JPA without understanding SQL — the N+1 query problem being the classic consequence. Your JDBC background gives you the instinct to profile and optimise.

3. RESTful APIs with Spring MVC or JAX-RS

Exposing your service layer over HTTP is the most common Java job requirement. A @RestController in Spring maps HTTP methods to your existing service calls. The service layer you built remains unchanged — the controller is just another application interface.

@RestController @RequestMapping("/api/products") public class ProductController { private final ProductService service; public ProductController(ProductService service) { this.service = service; } @PostMapping @ResponseStatus(HttpStatus.CREATED) public ProductResponse create(@RequestBody @Valid CreateProductRequest req) { Product p = service.create(new CreateProductCommand(req.sku(), req.name(), req.price())); return ProductResponse.from(p); } }

4. Advanced Testing Practices

Your current test suite covers unit tests. The next level is integration tests — tests that load a real (but in-memory) database and verify that the full stack from controller to database works correctly. In Spring Boot this is @SpringBootTest with an H2 data source. Beyond that, contract testing (Pact) and load testing (Gatling) are enterprise standards.

The test pyramid: most tests should be fast unit tests at the base; fewer, slower integration tests in the middle; even fewer end-to-end tests at the top. Invert this and your CI pipeline becomes too slow to be useful.

5. Reactive Programming with Project Reactor

For high-throughput, I/O-bound applications (APIs that call many external services in parallel), the blocking thread-per-request model becomes a bottleneck. Spring WebFlux and Project Reactor bring non-blocking I/O using Mono<T> and Flux<T> — the Java equivalent of async/await. This is an advanced topic worth approaching after Spring MVC is comfortable.

6. Docker and Cloud Deployment

Your executable JAR is already cloud-ready. The next step is containerising it with Docker so it can run on any infrastructure without environment drift:

# Dockerfile for a Spring Boot / plain Java JAR FROM eclipse-temurin:21-jre-alpine WORKDIR /app COPY target/myapp-1.0.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]

From there, Kubernetes orchestrates containers at scale, and cloud providers (AWS Elastic Beanstalk, Google Cloud Run, Azure App Service) can deploy the image directly.

Professional Habits That Separate Senior from Junior

Technical knowledge is necessary but not sufficient. The habits below consistently mark the difference between a developer who ships working software and one who ships correct software:

  1. Read the source. When a library behaves unexpectedly, open its source on GitHub rather than guessing. Java is open-source — the answers are there.
  2. Understand the JVM, not just Java. Know what garbage collection does, how the JIT compiler works, and how to read a flame graph. This knowledge lets you debug performance problems that are invisible to developers who see only the language.
  3. Version control discipline. Commit logical units of work, write meaningful messages, branch per feature, and never force-push shared branches.
  4. Code review both ways. Submit code for review and review others. Reading someone else's approach is one of the fastest ways to grow.
  5. Measure before optimising. Use a profiler (VisualVM, async-profiler, JFR) to find real bottlenecks. Premature optimisation is still the root of much wasted effort.
  6. Documentation as a first-class artefact. Write Javadoc for public APIs, keep a README that explains how to build and run, and document architectural decisions in an ADR (Architecture Decision Record).
Build in public. Put your capstone project on GitHub. Write a README that explains the design decisions, not just the commands to run it. Future employers and collaborators read the commit history and the README before they read the code.

Recommended Resources

  • Effective Java, 3rd edition by Joshua Bloch — the definitive guide to writing correct, maintainable Java. Read it twice at different stages of your career.
  • Clean Architecture by Robert C. Martin — the layering principles behind your capstone, generalised across languages.
  • Java Concurrency in Practice by Brian Goetz — the authoritative text on the Java memory model and concurrent programming.
  • Spring Boot Reference Documentation (docs.spring.io) — comprehensive and well-maintained official docs.
  • Baeldung (baeldung.com) — practical, code-first Java and Spring articles.
  • JEP index (openjdk.org/jeps) — follow Java Enhancement Proposals to understand where the language is going.

Closing Thoughts

Java's reputation as a verbose, ceremonial language belongs to the era before Java 8. Modern Java — records, sealed classes, pattern matching, text blocks, structured concurrency — is expressive and productive. The language is on a six-month release cadence and improving steadily. Staying current is part of the job.

More importantly, the engineering discipline you practised throughout this course — designing before coding, separating concerns, testing deliberately, handling errors explicitly, and packaging reproducibly — is language-agnostic. Those habits will make you effective in any codebase and with any technology stack you encounter next.

Congratulations on completing the Java Programming course. Now ship something real.