λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

빈 ꡬ멍 μ±„μš°κΈ°

[Clean Architecture][DIP] 클린 μ•„ν‚€ν…μ²˜μ— μ˜μ‘΄μ„± μ—­μ „ 원칙이 μ‹œμŠ€ν…œμ— λ―ΈμΉ˜λŠ” 영ν–₯

좜처 

ChatGPT


μ˜μ‘΄μ„± μ—­μ „ 원칙(Dependency Inversion Principle, DIP)은 SOLID 원칙 쀑 ν•˜λ‚˜λ‘œ, 클린 μ•„ν‚€ν…μ²˜(Clean Architecture)μ—μ„œ 맀우 μ€‘μš”ν•œ 역할을 ν•œλ‹€. DIPλŠ” μ†Œν”„νŠΈμ›¨μ–΄μ˜ λͺ¨λ“ˆ κ°„ μ˜μ‘΄μ„±μ„ 효과적으둜 κ΄€λ¦¬ν•˜μ—¬ μ‹œμŠ€ν…œμ˜ μœ μ—°μ„±κ³Ό ν™•μž₯성을 높이고, μ½”λ“œμ˜ λ³€κ²½μœΌλ‘œ μΈν•œ 영ν–₯을 μ΅œμ†Œν™”ν•˜λŠ” 데 κΈ°μ—¬ν•œλ‹€.

μ˜μ‘΄μ„± μ—­μ „ 원칙(Dependency Inversion Principle, DIP)

μ •μ˜

μ˜μ‘΄μ„± μ—­μ „ 원칙은 두 가지 μ£Όμš” κ·œμΉ™μœΌλ‘œ μ •μ˜λœλ‹€.

  1. κ³ μˆ˜μ€€ λͺ¨λ“ˆ(High-level Modules)은 μ €μˆ˜μ€€ λͺ¨λ“ˆ(Low-level Modules)에 μ˜μ‘΄ν•΄μ„œλŠ” μ•ˆ λœλ‹€. λ‘˜ λ‹€ 좔상화(Abstractions)에 μ˜μ‘΄ν•΄μ•Ό ν•œλ‹€.
  2. μΆ”μƒν™”λŠ” ꡬ체적인 것(Details, μ„ΈλΆ€ 사항)에 μ˜μ‘΄ν•΄μ„œλŠ” μ•ˆ λœλ‹€. ꡬ체적인 것(μ„ΈλΆ€ 사항)이 좔상화에 μ˜μ‘΄ν•΄μ•Ό ν•œλ‹€.

 

λͺ©ν‘œ

ꡬ쑰적인 μœ μ—°μ„±μ„ ν™•λ³΄ν•˜κ³ , λͺ¨λ“ˆ κ°„μ˜ μ˜μ‘΄μ„±μ„ 효과적으둜 κ΄€λ¦¬ν•˜μ—¬ λͺ¨λ“ˆμ˜ 독립성과 μž¬μ‚¬μš©μ„±μ„ λ†’μ΄λŠ” 것이닀.

클린 μ•„ν‚€ν…μ²˜μ—μ„œμ˜ μ—­ν• 

클린 μ•„ν‚€ν…μ²˜λŠ” 주둜 λ‹€μŒκ³Ό 같은 4가지 원칙을 λ”°λ₯Έλ‹€.

  1. μ—”ν„°ν”„λΌμ΄μ¦ˆ λΉ„μ¦ˆλ‹ˆμŠ€ κ·œμΉ™
  2. μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λΉ„μ¦ˆλ‹ˆμŠ€ κ·œμΉ™
  3. μΈν„°νŽ˜μ΄μŠ€ μ–΄λŒ‘ν„°
  4. ν”„λ ˆμž„μ›Œν¬ 및 λ“œλΌμ΄λ²„

μ˜μ‘΄μ„± μ—­μ „ 원칙은 μ΄λŸ¬ν•œ μ•„ν‚€ν…μ²˜ λ ˆμ΄μ–΄μ—μ„œ μ˜μ‘΄μ„±μ„ μ—­μ „μ‹œμΌœ, λΉ„μ¦ˆλ‹ˆμŠ€ 둜직이 ν”„λ ˆμž„μ›Œν¬, λ°μ΄ν„°λ² μ΄μŠ€, UI 등에 영ν–₯을 받지 μ•Šλ„λ‘ μ„€κ³„ν•œλ‹€.

DIPκ°€ μ‹œμŠ€ν…œμ— λ―ΈμΉ˜λŠ” 영ν–₯

1. μœ μ—°μ„±κ³Ό ν™•μž₯μ„± ν–₯상

  •  DIPλ₯Ό 톡해 μ‹œμŠ€ν…œμ„ κ΅¬μ„±ν•˜λŠ” λͺ¨λ“ˆ κ°„μ˜ μ˜μ‘΄μ„±μ„ μ œκ±°ν•˜κ±°λ‚˜ 쀄일 수 μžˆλ‹€. 이둜 인해 μ‹œμŠ€ν…œμ˜ μœ μ—°μ„±μ΄ μ¦κ°€ν•˜κ³ , μƒˆλ‘œμš΄ κΈ°λŠ₯ μΆ”κ°€ 및 κΈ°μ‘΄ κΈ°λŠ₯ μˆ˜μ •μ΄ μš©μ΄ν•΄μ§„λ‹€.
  • 예λ₯Ό λ“€μ–΄, νŠΉμ • λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό μ‚¬μš©ν•˜λŠ” μ½”λ“œκ°€ 직접 μ˜μ‘΄ν•˜λŠ” λŒ€μ‹  μΈν„°νŽ˜μ΄μŠ€λ₯Ό 톡해 κ°„μ ‘μ μœΌλ‘œ μ˜μ‘΄ν•˜κ²Œ ν•˜λ©΄, λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό ꡐ체할 λ•Œ μ½”λ“œ 변경을 μ΅œμ†Œν™”ν•  수 μžˆλ‹€.

2. λ³€κ²½ μš©μ΄μ„±

  • κ³ μˆ˜μ€€ λͺ¨λ“ˆ(λΉ„μ¦ˆλ‹ˆμŠ€ 둜직)κ³Ό μ €μˆ˜μ€€ λͺ¨λ“ˆ(λ°μ΄ν„°λ² μ΄μŠ€, UI λ“±)의 독립성을 μœ μ§€ν•¨μœΌλ‘œμ¨, ν•œμͺ½μ˜ 변경이 λ‹€λ₯Έ μͺ½μ— λ―ΈμΉ˜λŠ” 영ν–₯을 μ΅œμ†Œν™”ν•  수 μžˆλ‹€.
  • μ΄λŠ” μ½”λ“œ μœ μ§€λ³΄μˆ˜μ„±μ„ 높이고, λ³€κ²½μ˜ 리슀크λ₯Ό μ€„μ΄λŠ” 데 κΈ°μ—¬ν•œλ‹€.

3. μž¬μ‚¬μš©μ„± 증가

  • μΆ”μƒν™”λœ μΈν„°νŽ˜μ΄μŠ€λ₯Ό 톡해 λͺ¨λ“ˆ κ°„ 톡신이 μ΄λ£¨μ–΄μ§€λ―€λ‘œ, κ³ μˆ˜μ€€ λͺ¨λ“ˆμ΄ μ €μˆ˜μ€€ λͺ¨λ“ˆμ˜ μ„ΈλΆ€ κ΅¬ν˜„μ— μ˜μ‘΄ν•˜μ§€ μ•Šκ²Œ λœλ‹€. 이λ₯Ό 톡해 κ³ μˆ˜μ€€ λͺ¨λ“ˆμ€ λ‹€μ–‘ν•œ ν™˜κ²½μ—μ„œ μž¬μ‚¬μš©μ΄ κ°€λŠ₯ν•©λ‹ˆλ‹€.
  • 예λ₯Ό λ“€μ–΄, λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 λͺ¨λ“ˆμ€ νŠΉμ • μ›Ή ν”„λ ˆμž„μ›Œν¬μ— μ˜μ‘΄ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— λ‹€μ–‘ν•œ UI ν”„λ ˆμž„μ›Œν¬μ—μ„œ μž¬μ‚¬μš©ν•  수 μžˆλ‹€.

4. ν…ŒμŠ€νŠΈ μš©μ΄μ„±

  • DIPλŠ” ν…ŒμŠ€νŠΈν•˜κΈ° μ‰¬μš΄ μ½”λ“œλ₯Ό λ§Œλ“ λ‹€. μ˜μ‘΄μ„±μ„ μ£Όμž…λ°›λŠ” λͺ¨λ“ˆμ€ ν…ŒμŠ€νŠΈ μ‹œ Mock κ°μ²΄λ‚˜ μŠ€ν…μ„ μ‚¬μš©ν•˜μ—¬ λ…λ¦½μ μœΌλ‘œ ν…ŒμŠ€νŠΈν•  수 μžˆλ‹€.
  • μ΄λŠ” λ‹¨μœ„ ν…ŒμŠ€νŠΈμ˜ 신뒰성을 높이고, ν…ŒμŠ€νŠΈ 컀버리지λ₯Ό ν–₯μƒμ‹œν‚€λŠ” 데 μ€‘μš”ν•œ 역할을 ν•œλ‹€.

5. 결합도 κ°μ†Œ

  • DIPλŠ” λͺ¨λ“ˆ κ°„μ˜ 결합도λ₯Ό 쀄이고 응집도λ₯Ό λ†’μ΄λŠ” 데 κΈ°μ—¬ν•œλ‹€. λͺ¨λ“ˆμ΄ 좔상화에 μ˜μ‘΄ν•¨μœΌλ‘œμ¨, νŠΉμ • κ΅¬ν˜„μ— μ˜μ‘΄ν•˜λŠ” 문제λ₯Ό ν”Όν•  수 μžˆλ‹€.
  • μ΄λŠ” μ‹œμŠ€ν…œμ„ 더 μœ μ—°ν•˜κ³  ν™•μž₯ κ°€λŠ₯ν•˜κ²Œ λ§Œλ“€μ–΄ μ€€λ‹€.

 

μ˜μ‘΄μ„± μ—­μ „ μ›μΉ™μ˜ κ΅¬ν˜„ μ˜ˆμ‹œ

 

Java 예

// 좔상화(μΈν„°νŽ˜μ΄μŠ€) μ •μ˜
public interface PaymentProcessor {
    void processPayment(double amount);
}

// μ €μˆ˜μ€€ λͺ¨λ“ˆ
public class PayPalPaymentProcessor implements PaymentProcessor {
    @Override
    public void processPayment(double amount) {
        // PayPal 결제 처리 둜직
        System.out.println("Processing payment of $" + amount + " through PayPal.");
    }
}

// κ³ μˆ˜μ€€ λͺ¨λ“ˆ
public class ShoppingCart {
    private final PaymentProcessor paymentProcessor;

    // μƒμ„±μž μ£Όμž…μ„ ν†΅ν•œ μ˜μ‘΄μ„± μ—­μ „
    public ShoppingCart(PaymentProcessor paymentProcessor) {
        this.paymentProcessor = paymentProcessor;
    }

    public void checkout(double amount) {
        // λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 처리
        paymentProcessor.processPayment(amount);
    }
}

// μ‚¬μš© μ˜ˆμ‹œ
public class Main {
    public static void main(String[] args) {
        PaymentProcessor paymentProcessor = new PayPalPaymentProcessor();
        ShoppingCart cart = new ShoppingCart(paymentProcessor);
        cart.checkout(100.0);
    }
}



Kotlin 예

// 좔상화(μΈν„°νŽ˜μ΄μŠ€) μ •μ˜
interface PaymentProcessor {
    fun processPayment(amount: Double)
}

// μ €μˆ˜μ€€ λͺ¨λ“ˆ
class PayPalPaymentProcessor : PaymentProcessor {
    override fun processPayment(amount: Double) {
        // PayPal 결제 처리 둜직
        println("Processing payment of \$$amount through PayPal.")
    }
}

// κ³ μˆ˜μ€€ λͺ¨λ“ˆ
class ShoppingCart(private val paymentProcessor: PaymentProcessor) {
    
    fun checkout(amount: Double) {
        // λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 처리
        paymentProcessor.processPayment(amount)
    }
}

// μ‚¬μš© μ˜ˆμ‹œ
fun main() {
    val paymentProcessor: PaymentProcessor = PayPalPaymentProcessor()
    val cart = ShoppingCart(paymentProcessor)
    cart.checkout(100.0)
}

 

DIP의 이점과 μ£Όμ˜μ‚¬ν•­

이점

  • μœ μ—°ν•œ μ•„ν‚€ν…μ²˜ : DIPλ₯Ό 톡해 μ‹œμŠ€ν…œ ꡬ쑰λ₯Ό 보닀 μœ μ—°ν•˜κ²Œ μœ μ§€ν•  수 μžˆλ‹€.
  • ν™•μž₯μ„± : μƒˆλ‘œμš΄ κΈ°λŠ₯을 μ‰½κ²Œ μΆ”κ°€ν•˜κ³ , κΈ°μ‘΄ κΈ°λŠ₯을 λ³€κ²½ν•˜λŠ” 데 λ“œλŠ” λ…Έλ ₯을 쀄일 수 μžˆλ‹€.
  • ν…ŒμŠ€νŠΈ κ°€λŠ₯μ„± : λͺ¨λ“ˆμ„ λ…λ¦½μ μœΌλ‘œ ν…ŒμŠ€νŠΈν•  수 μžˆμ–΄ ν’ˆμ§ˆ 보증에 μœ λ¦¬ν•˜λ‹€.

μ£Όμ˜μ‚¬ν•­

  • λ³΅μž‘μ„± 증가 : μ§€λ‚˜μΉ˜κ²Œ 좔상화λ₯Ό μ‚¬μš©ν•˜λ©΄ μ½”λ“œμ˜ λ³΅μž‘μ„±μ΄ 증가할 수 μžˆλ‹€.
  • κ³Όλ„ν•œ 섀계 : ν”„λ‘œμ νŠΈμ˜ ν¬κΈ°λ‚˜ μš”κ΅¬μ‚¬ν•­μ— λ§žμ§€ μ•ŠλŠ” κ³Όλ„ν•œ μ„€κ³„λŠ” 였히렀 μœ μ§€λ³΄μˆ˜λ₯Ό μ–΄λ ΅κ²Œ ν•  수 μžˆλ‹€.