DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Newsletter
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Stop Writing Database Migration Scripts: Declarative Schema Sync for Java
  • Testing Java and Spring Applications With Kotlin: Low-Risk to Adoption
  • A Spring Boot App With Half the Startup Time
  • Zero-Downtime Deployments for Java Apps on Kubernetes

Trending

  • RAG Architecture Patterns: Proxy, Caching, and Routing
  • Managing Technical Debt in AI-Generated Code
  • Top Gen AI Frameworks for Go in 2026: A Hands-On Comparison
  • The Self-Hosting Math Changed While We Were Still Arguing About Sovereignty

Draft This article hasn't been published, so readers can't see it.

In moderation This article is waiting for review, so readers can't see it yet.

Deleted This article has been deleted, so readers can't see it.

  1. DZone
  2. Coding
  3. Java
  4. Squid Game: The Clean Code Trials — A Java Developer's Survival Story

Squid Game: The Clean Code Trials — A Java Developer's Survival Story

Learn about clean coding techniques to refactor rigid Java methods, embrace patterns like Strategy, avoid anti-patterns, and craft future-proof software.

By 
Shaamik Mitraa
·
Jul. 01, 25 · Analysis
Post on X (opens in a new tab) Share on LinkedIn (opens in a new tab)
6.0K Views

Join the DZone community Save articles, join the discussion, and download Refcards and Trend Reports with a free account.

Join for free Already a member? Log in

"In the world of code, there are only two outcomes: evolve or perish."

Episode 1: The Red Light of Rigid Code

Scene: A vast ODC filled with desks, whiteboards, and terminals. The chairs are marked with red and green stickers. Software contestants sitting, trembling, gazing at a giant robot doll that watches them intently.

A loudspeaker booms:

"Your first challenge: implement a discount calculator. It must work today... and still work tomorrow."

Contestant #101, a confident junior developer, leans on the terminal and types:

Java
 
 public class DiscountCalculator {
    public double calculate(String customerType, double amount, String couponCode, int orderCount, LocalDateTime firstOrderDate) {
        double discount = 0;

        if ("REGULAR".equals(customerType)) {
            discount = amount * 0.1;
            if ("FEST10".equalsIgnoreCase(couponCode)) {
                discount += 10;
            }
        } else if ("PREMIUM".equals(customerType)) {
            discount = amount * 0.15;
            if ("FEST10".equalsIgnoreCase(couponCode)) {
                discount += 20;
            }
        } else if ("VIP".equals(customerType)) {
            discount = amount * 0.25;
            if (orderCount > 5 && firstOrderDate.isBefore(LocalDateTime.now().minusYears(2))) {
                discount += 50;
            }
        }

        if (discount > 100) {
            discount = 100; // cap
        }

        System.out.println("Discount: " + discount);
        return discount;
    }
}


The doll's eyes turn red. A siren blares.

Boom. Eliminated.

Why This Code Died: Exposing Anti-Patterns

1. God Class / God Method

One class or method tries to handle all responsibilities. That’s a sign it’s doing too much and is hard to maintain. 

Scene: Flashback — Contestant 101 in the waiting area.

Developer Mentor: "You stacked all logic in one method. You became the God... and the God fell."

  • Mixes validation, business logic, coupon logic, and logging.
  • Hard to test specific paths in isolation.
  • Not KISS (Keep It Simple & Stupid).

2. Magic Strings and Constants

Scene: Flashback — A string typo breaks production.

Developer Intern: "I typed 'PremIum' instead of 'PREMIUM'... 11,000 customers got no discount."

  • Strings like "REGULAR", "FEST10", "VIP" are error-prone and scattered.
  • No compile-time safety, hard to change later.

3. If-Else Tower (No Polymorphism)

Scene: Front Man shows an old dusty code file with 43 else-ifs.

Front Man: "The longer the tower, the harder it is to escape."

  • Adding a new type (e.g., “WHOLESALE”) means editing the method — violates OCP (Open/Close Principal.)
  • Code becomes unreadable.

4. Tight Coupling

  • Logic is tied to exact string values.
  • System.out in business logic — violates the separation of concerns.

5. Not Testable

  • How will you unit test VIP logic alone?
  • Everything is entangled.

6. No Reusability or Extensibility

  • You can't plug this into a different pricing engine.

Refactor: Code that Survives the Next Round

Scene: Developer's Resurrection

Mentor: "You're not out. Refactor. And survive."

Step 1: Create Enum for CustomerType

Java
 
public enum CustomerType {
    REGULAR, PREMIUM, VIP;

    public static CustomerType from(String value) {
        try {
            return CustomerType.valueOf(value.toUpperCase());
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid customer type: " + value);
        }
    }
}


Step 2: Use Strategy Pattern

Java
 
public interface DiscountStrategy {
    CustomerType type();
    double calculate(double amount, String couponCode, int orderCount, LocalDateTime firstOrderDate);
}


Implement a few strategies:

Java
 
public class RegularDiscount implements DiscountStrategy {
    public CustomerType type() { return CustomerType.REGULAR; }
    public double calculate(double amount, String couponCode, int orderCount, LocalDateTime firstOrderDate) {
        double discount = amount * 0.1;
        if ("FEST10".equalsIgnoreCase(couponCode)) discount += 10;
        return discount;
    }
}

public class PremiumDiscount implements DiscountStrategy {
    public CustomerType type() { return CustomerType.PREMIUM; }
    public double calculate(double amount, String couponCode, int orderCount, LocalDateTime firstOrderDate) {
        double discount = amount * 0.15;
        if ("FEST10".equalsIgnoreCase(couponCode)) discount += 20;
        return discount;
    }
}

public class VipDiscount implements DiscountStrategy {
    public CustomerType type() { return CustomerType.VIP; }
    public double calculate(double amount, String couponCode, int orderCount, LocalDateTime firstOrderDate) {
        double discount = amount * 0.25;
        if (orderCount > 5 && firstOrderDate.isBefore(LocalDateTime.now().minusYears(2))) {
            discount += 50;
        }
        return discount;
    }
}


Step 3: Make It Generic and Plug With Lambdas

Java
 
public class StrategyRegistry<T, R> {
    private final Map<T, Function<R, Double>> strategies = new HashMap<>();

    public void register(T key, Function<R, Double> strategyFunc) {
        strategies.put(key, strategyFunc);
    }

    public double apply(T key, R request) {
        return strategies.getOrDefault(key, r -> 0.0).apply(request);
    }
}


Scene: The Intern's Orientation 

(A new intern enters the Squid Game Arena's code lab, shaking with nervousness. Developer Mentor 218 greets him with a calm voice.)   

Intern:

“Sir… what is this StrategyRegistry thing? And… why use these lambdas and enums instead of just if-else?”

Mentor 218 (sips tea and opens laptop):

“Let me show you. This is how we survive chaos.”

What Is StrategyRegistry<T, R>?

It’s a generic plug-and-play engine that avoids the "god method" syndrome. You pass:

  • T: A key — in our case, CustomerType.
  • R: A request payload — here, DiscountRequest.

Each strategy is a function:

  • Function<DiscountRequest, Double>

And we store them in a map:   

  • Map<CustomerType, Function<DiscountRequest, Double>> strategies

Instead of giant if-else logic like:   

Java
 
if(customerType.equals("PREMIUM")) { ... }


We now just do:   

Java
 
registry.apply(customerTypeEnum, request);


Registering Discount Strategies Using Lambdas

Java
 
StrategyRegistry<CustomerType, DiscountRequest> registry = new StrategyRegistry<>();

registry.register(CustomerType.REGULAR, req -> {
    double discount = req.amount() * 0.1;
    if ("FEST10".equalsIgnoreCase(req.couponCode())) discount += 10;
    return discount;
});

registry.register(CustomerType.PREMIUM, req -> {
    double discount = req.amount() * 0.15;
    if ("FEST10".equalsIgnoreCase(req.couponCode())) discount += 20;
    return discount;
});

registry.register(CustomerType.VIP, req -> {
    double discount = req.amount() * 0.25;
    if (req.orderCount() > 5 && req.firstOrderDate().isBefore(LocalDateTime.now().minusYears(2))) {
        discount += 50;
    }
    return discount;
});


Why Use Functional Programming?

1. No New Classes for Every Variation

  • Avoids boilerplate like PremiumDiscountStrategy implements DiscountStrategy
  • Lambdas are lightweight and in-place

2. Easier to Test

  • Each lambda can be tested in isolation.
  • You can inject different behaviors in tests.

3. Open for Extension, Closed for Modification (OCP)

  • Add a new type without touching existing logic.
  • Register strategy on startup, config, or runtime.

4. Reusability and Modularity

  • Your registry becomes a plugboard. Great for rule engines!

Magic Strings: Death by Literal Comparison

The original code had:

Java
 
if ("FEST10".equalsIgnoreCase(couponCode)) ...


Instead of "FEST10" scattered everywhere:   

1. Create a property-based config:   

Java
 
discount.coupon.festive = FEST10


2. Bind it to a configuration class: If you are using a Spring Boot-like framework. 

Java
 
@ConfigurationProperties(prefix = "discount.coupon")
public class DiscountCouponProperties {
    private String festive;

    public String getFestive() {
        return festive;
    }

    public void setFestive(String festive) {
        this.festive = festive;
    }
}


3. Inject it where you define strategy:   

Java
 
String fest10 = couponProperties.getFestive();

registry.register(CustomerType.REGULAR, req -> {
    double discount = req.amount() * 0.1;
    if (fest10.equalsIgnoreCase(req.couponCode())) discount += 10;
    return discount;
});


Updated Registry Registration (More Generic and Clean)  

Java
 
@Autowired
DiscountCouponProperties couponProperties;

...

registry.register(CustomerType.VIP, req -> {
    double discount = req.amount() * 0.25;
    boolean loyal = req.orderCount() > 5 &&
        req.firstOrderDate().isBefore(LocalDateTime.now().minusYears(2));
    if (loyal) discount += 50;
    return discount;
});


Refactored Strategy class:

Java
 
public class DiscountStrategyRegistration {
 
    public static StrategyRegistry<CustomerType, DiscountRequest> createRegistry() {
        StrategyRegistry<CustomerType, DiscountRequest> registry = new StrategyRegistry<>();
		@Autowired
 		DiscountCouponProperties couponProperties;       

        registry.register(CustomerType.REGULAR, req -> {
            double discount = req.amount() * 0.1;
            if (couponProperties.getFestive().equalsIgnoreCase(req.couponCode())) discount += 10;
            return discount;
        });

        registry.register(CustomerType.PREMIUM, req -> {
            double discount = req.amount() * 0.15;
            if (couponProperties.getFestive().equalsIgnoreCase(req.couponCode())) discount += 20;
            return discount;
        });

        registry.register(CustomerType.VIP, req -> {
            double discount = req.amount() * 0.25;
            if (req.orderCount() > 5 && req.firstOrderDate().isBefore(LocalDateTime.now().minusYears(2))) {
                discount += 50;
            }
            return discount;
        });

        return registry;
    }
}


Final Refactored Calculator

Java
 
package com.example.javaonfly.antipattern.discount;

import java.time.LocalDateTime;

public class DiscountCalculator {
    private final StrategyRegistry<CustomerType, DiscountRequest> registry;

    public DiscountCalculator(StrategyRegistry<CustomerType, DiscountRequest> registry) {
        this.registry = registry;
    }

    public double calculate(String customerTypeStr, double amount, String couponCode, int orderCount, LocalDateTime firstOrderDate) {
        CustomerType type = CustomerType.from(customerTypeStr);
        DiscountRequest req = new DiscountRequest(amount, couponCode, orderCount, firstOrderDate);
        return Math.min(100, registry.apply(type, req));
    }


    public static void main(String[] args) {
        DiscountCalculator calculator = new DiscountCalculator(DiscountStrategyRegistration.createRegistry());
        double value = calculator.calculate("REGULAR",100,"FEST10",1,null);
        System.out.println("Discount calculated :: " + value);
    }
}
//output
Discount calculated :: 20.0


Scene Epilogue

Contestant 456: "So... you don’t write code for today?"

Front Man: "No. We write for tomorrow. For change. For chaos. And we survive."

Contestant 212: "What if change never comes?"

Front Man: "Then your clean code will never break. Isn’t that peace?"

Clean Code Checklist From Episode 1

Anti-Pattern Death Cause Cure
God Class All logic in one SRP: Break into strategies
Magic Strings Typos & unclear Enums and constants
SRP Violation One class, many jobs Delegate to strategy classes
OCP Violation Editing old code Plug strategy via registry
Unreadable Code Future devs hate it Descriptive interfaces
Hard to Test No unit slices Modular + Generic strategies

"Survive by writing clean code that’s ready for change — not written in fear of it."

Java (programming language) Spring Boot Strings

Opinions expressed by DZone contributors are their own.

Related

  • Stop Writing Database Migration Scripts: Declarative Schema Sync for Java
  • Testing Java and Spring Applications With Kotlin: Low-Risk to Adoption
  • A Spring Boot App With Half the Startup Time
  • Zero-Downtime Deployments for Java Apps on Kubernetes

Partner Resources

×

Comments

Loading comments

The comments didn't load

Please try again in a moment.

Likes

Loading

The next likes didn't load. Please try again.

The likes didn't load

Please try again in a moment.

See who liked this

Log in or join DZone for free to see who liked this article.

Log in Join for free
  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook