Skip to main content

Refactoring Task

Overview​

This exercise addresses a design in which the OrderService directly creates and utilizes an InventoryService instance during order processing.
You will examine this structure from the perspective of dependency decoupling, abstraction, and injection, and propose refactoring strategies.

Initial Code​

The following example shows an OrderService class that handles order placement and directly reduces inventory by creating an InventoryService instance.
This tight coupling raises concerns around maintainability, reusability, and testability.

class InventoryService {
reduceStock(productId: string, amount: number) {
console.log(`εœ¨εΊ«γ‚’ζΈ›γ‚‰γ—γΎγ—γŸ: ${productId} Γ— ${amount}`);
}
}

class OrderService {
private inventory: InventoryService;

constructor() {
this.inventory = new InventoryService();
}

placeOrder(productId: string, quantity: number) {
console.log(`ζ³¨ζ–‡ε—δ»˜: ${productId} Γ— ${quantity}`);
this.inventory.reduceStock(productId, quantity);
}
}

Question 1: What are the structural problems in this code?​

Identify and explain the key design issues using the following points as a guide:

  • Tight dependency on implementation, making mocking or substitution difficult
  • Low reusability, resulting in poor decoupling and flexibility
  • Violations of DIP (Dependency Inversion Principle) and OCP (Open/Closed Principle)
  • Blurred responsibility boundaries, hindering testability and maintainability

Question 2: How can this structure be refactored to improve flexibility and maintainability?​

Provide a refactoring plan considering the following:

  • How can the dependent class be injected from the outside instead of instantiated internally?
  • How can we reverse the direction of dependency to achieve more modular design?
  • How can we support multiple implementations (e.g., MockInventoryService, RemoteInventoryAPI)?

Example: Candidate Design Patterns​

Pattern NamePurpose and Effect
ObserverDecouples components via event notifications, reducing direct dependencies
MediatorCentralizes coordination between services, avoiding direct inter-class references
Dependency InjectionAllows injection of dependencies from outside, improving flexibility and testability
Abstract FactoryEnables switching between object configurations by delegating creation logic

Optional Extensions​

  • If ShippingService or PaymentService were added, how would you restructure the dependencies?
  • If multiple implementations of InventoryService exist (e.g., local vs. remote API), how would you switch between them dynamically?

Suggested Output Format (for review or team discussion)​

  • List of structural issues (at least three)
  • Refactoring strategy and rationale for chosen pattern(s)
  • Conceptual design of the improved structure (e.g., injection method or dependency diagram)