DEV Community

Cover image for 🧠 From Chaos to Clean Code: My Java Refactor Journey - Part 2 of 6
Gabriela Goudromihos Puig
Gabriela Goudromihos Puig

Posted on

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

πŸ”§ 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<>(); // ... } 
Enter fullscreen mode Exit fullscreen mode
@RestController @RequestMapping("/items") public class ModelRepoController { private Map<Long, Item> storage = new HashMap<>(); // ... } 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

πŸ”§ 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"; } 
Enter fullscreen mode Exit fullscreen mode

🫠 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)); } 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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(); } 
Enter fullscreen mode Exit fullscreen mode

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! πŸ‘€

Top comments (0)