Project Architecture and Layering

By now, you've built Java programs that talk to databases. But if you don’t organize your code… chaos awaits! In this chapter, we’ll go beyond the "everything-in-one-file" phase and introduce a structure that’s scalable, testable, and professional.

Why Code Organization Matters

Without structure:

A clean architecture means you can:

Layers in a Java App

A typical layered Java application looks like this:

Layered Architecture

Let’s break that down:

Controller Layer (a.k.a. Web Layer)

Handles HTTP requests and responses. Think of it as the front desk.

Controller Example

Service Layer

Contains business logic. It decides what should happen when a user does something.

Service Example

Repository Layer (a.k.a. Data Access Layer)

Talks to the database using JPA or JDBC.

Repository Example

DTOs (Data Transfer Objects)

What Are They?

DTOs are simple objects used to carry data between layers (like from the client to your service, or from your service to the frontend). DTOs are not entities. They're stripped-down data carriers, often used for input/output.

Why Use DTOs?

Example DTO

DTO Example

Use it in your controller:

DTO Controller Example

Inside your service:

DTO Service Example

Bonus: Entity vs DTO vs ViewModel

ConcernEntityDTOViewModel
Used ForPersistence (JPA)Communication between layersFrontend/response shaping
ContainsDB-mapped fieldsOnly needed fieldsOnly displayed fields
Knows DB rulesYesNoNo

Example Refactor Challenge

You used to do this:

Old Code Example

Now do this:

Define a BookDto
Move logic to a BookService
Map fields from DTO → Entity in the service layer

This separation of concerns sets you up for cleaner testing and better architecture.

What’s Next

Your code is now modular. But how do you wire everything together cleanly and flexibly? Next, we explore Spring’s magic behind object creation and dependency injection—the real engine behind modern Java backends. Let’s dive in.