---
title: Use Dependency Injection
impact: HIGH
impactDescription: enables testability and loose coupling
tags: dependency-injection, testing, coupling, architecture, quality, kotlin
---

## Use Dependency Injection

Direct instantiation of dependencies inside a class creates tight coupling, making unit testing difficult and modifications risky. Dependency Injection (DI) enables mockability, switchability, and better overall architecture.

**Incorrect (hardcoded dependencies):**

```kotlin
class OrderService {
    private val db = DatabaseConnection() // Hardcoded dependency
    private val mailer = EmailService()   // Hardcoded dependency

    fun createOrder(data: OrderData): Order {
        val order = db.insert("orders", data)
        mailer.send(data.email, "Order created")
        return order
    }
}
```

**Correct (injected dependencies):**

```kotlin
interface Database {
    fun insert(table: String, data: OrderData): Order
}

interface Mailer {
    fun send(to: String, message: String)
}

class OrderService(
    private val db: Database,
    private val mailer: Mailer
) {
    fun createOrder(data: OrderData): Order {
        val order = db.insert("orders", data)
        mailer.send(data.email, "Order created")
        return order
    }
}

// Usage (manual or via Dagger/Koin/Hilt)
val service = OrderService(PostgresDatabase(), SendGridMailer())

// Testing with MockK
val mockDb = mockk<Database>()
val mockMailer = mockk<Mailer>()
val testService = OrderService(mockDb, mockMailer)
```

**Benefits:**
- Easy mocking and stubbing for unit tests
- Modular and reusable components
- Clear visibility of class dependencies
- Separation of concerns

**Tools:** Dagger-Hilt, Koin, MockK, PR review
