🧠 From Chaos to Clean Code: My Java Refactor Journey – Part 2 of 6



This content originally appeared on DEV Community and was authored by Gabriela Goudromihos Puig

🔧 Step 1: Separating Responsibilities – From Spaghetti to Structure

The first class I refactored was a typical all-in-one mess: controller, business logic, and in-memory storage were all crammed into the same place.

@RestController
@RequestMapping("/things")
public class ControllerService {
    private List<String> list = new ArrayList<>();
    // ...
}
@RestController
@RequestMapping("/items")
public class ModelRepoController {
    private Map<Long, Item> storage = new HashMap<>();
    // ...
}

This class did everything β€” which is exactly what we want to avoid in domain-oriented architecture.

🔄 The refactor

Split the logic into four separate components:

  • ThingController/ItemController: exposes the HTTP API
  • ThingService/ItemService: handles the business logic
  • ThingRepository/ItemRepository: manages data access (in-memory for now)
  • Thing/Item: represents the domain entity

The logic stayed the same, but now it’s clean, testable, and aligned with Clean Architecture principles.

💡 Before: logic and storage were tightly coupled in the controller
💡 After: the controller simply orchestrates calls to the service

🔗 Check out the before and after in the repo.

🗂 Project structure after the refactor:

com.example.spaghetti
β”œβ”€β”€ controller
β”‚   └── ThingController.java
β”‚   └── ItemController.java
β”œβ”€β”€ service
β”‚   └── ThingService.java
β”‚   └── ItemService.java
β”œβ”€β”€ repository
β”‚   └── ThingRepository.java
β”‚   └── ItemRepository.java
β”œβ”€β”€ model
β”‚   └── Thing.java
β”‚   └── Item.java

🔧 Step 2: From β€œUseless Bean” to Simple Validation

In the initial version of the code, I had a leftover bean:

@Bean
public String uselessBean() {
    return "I am a useless bean";
}

🫠 It did absolutely nothing β€” until now.

Instead of deleting it, I replaced it with a ✨ simple validation rule:
✅ check if a name starts with an uppercase letter.

@Bean
public Predicate<String> nameStartsWithUppercaseValidator() {
    return name -> name != null && !name.isEmpty() && Character.isUpperCase(name.charAt(0));
}

I then injected it into the controller and used it to validate input before saving a new item.
No big framework, no annotation magic β€” just a good old @bean doing something useful.

📦 Where should this bean live?

Since this is a generic validation, not part of the domain logic itself, I moved it to a dedicated config package:

com.example.spaghetti
β”œβ”€β”€ config
β”‚   └── MainConfig.java

According to DDD principles, reusable and infrastructure-related beans like this one shouldn’t live inside your domain or application logic.
Placing it under config (or infrastructure.config) keeps your architecture clean and responsibilities well separated.

💡 Small win: the bean now enforces a business rule β€” and the code stays clean and reusable.

🧠 Even small refactors like this help keep things tidy and meaningful.

🔧 Step 3: Giving Purpose to the Utils Class

Previously, our Utils class had two static methods that weren’t actually used anywhere.

Now, we brought it to life by adding a new method that counts the number of letters in a given string:

public int countLetters(String input) {
    if (input == null) return 0;
    return (int) input.chars()
            .filter(Character::isLetter)
            .count();
}

This method helps us process input names more meaningfully.

In the controller, we call this method to log how many letters the submitted name has before saving it.

Small steps like this turn β€œunused helpers” into valuable tools for our application!

🚀 Conclusion: Setting the Stage for Clean Architecture and DDD

We’ve cleaned up the code by separating responsibilities and giving purpose to unused parts like the validation bean and utils. 🧹✨

This foundation makes our codebase cleaner and easier to maintain. 🏗🧱

Next, we’ll introduce Clean Architecture layers and apply proper domain modeling with DDD to take our design to the next level. 📐📚

Stay tuned! 👀


This content originally appeared on DEV Community and was authored by Gabriela Goudromihos Puig