벡엔드에게 di (Dependency Injection) , daomodule, model, repository 설명해주려고해.
사실 나도 정확한 개념이 헷갈려. 알려줄래?
물론이죠! 😎
백엔드에게 설명하려면 Android 앱 아키텍처 관점과 백엔드 개발자가 이해하기 쉬운 비유를 같이 사용하는 게 효과적이에요.
✅ 빠르게 핵심 개념부터!
개념 |
한 줄 정의 |
Model |
실제 데이터 구조 (DB 테이블 대응 클래스) |
DAO |
DB에 접근하는 인터페이스 (insert, getAll 등 SQL 쿼리 메소드) |
Repository |
DAO + 다른 데이터 소스(API 등)를 통합해서 뷰모델에 제공 |
DI (Dependency Injection) |
객체를 직접 생성하지 않고, 외부에서 "주입"받는 구조 |
Module (Dagger/Hilt) |
DI가 어떤 객체를, 어떻게 만들지 정의한 "레시피" |
ViewModel (참고) |
UI 데이터 상태를 보존하고, Repository를 통해 데이터 요청 |
✅ 백엔드 개발자에게 이렇게 설명해보세요:
📦 1. Model
백엔드에서 말하는 DTO나 Entity 클래스와 같아요.
예: Device(name: String, category: String)
🛠 2. DAO (Data Access Object)
DAO는 SQL을 대신해주는 DB 접근 인터페이스에요.
마치 JPA의 Repository 같은 역할.
@Dao
interface DeviceDao {
@Query("SELECT * FROM device_table")
fun getAll(): List<Device>
}
🧩 3. Repository
여러 데이터 소스(DB, API, 캐시 등)를 묶어서 ViewModel에 제공해주는 계층이에요.
백엔드의 Service Layer와 비슷합니다.
class DeviceRepository @Inject constructor(private val dao: DeviceDao) {
fun getDevices() = dao.getAll()
}
💉 4. DI (Dependency Injection)
객체를 직접 생성하지 않고, 외부에서 주입 받아 사용하는 방식이에요.
Spring의 @Autowired, @Service, @Component와 같다고 보면 됩니다.
🔧 5. Module
Hilt나 Dagger에서는 DI에 필요한 객체 생성 방식을 정의하는 곳입니다.
@Module
@InstallIn(SingletonComponent::class)
object DaoModule {
@Provides
fun provideDeviceDao(db: AppDatabase): DeviceDao = db.deviceDao()
}
✅ 전체 흐름 예시
🔽 ViewModel
🔽
Repository
🔽
DAO ↔ Room DB
이 구조에서 Hilt가 각 객체를 알아서 생성하고 연결해줘서, 개발자는 그냥 @Inject만 붙이면 됩니다.
✅ 요약 키워드로 외우기
이름 |
역할 |
백엔드 비유 |
Model |
데이터 구조 |
DTO / Entity |
DAO |
DB 접근 메소드 |
JPA Repository |
Repository |
데이터 조합/가공 |
Service Layer |
DI |
의존성 주입 |
@Autowired |
Module |
DI 등록소 |
Bean 설정 |
필요하시면 DI 없이 만든 코드 vs DI 사용한 코드 비교,
또는 전체 구조 그림도 그려드릴 수 있어요 😊
좋아요! 👇
"DI 없이 만든 코드 vs DI 사용한 코드" 비교와
전체 구조 그림 모두 준비해드릴게요.
✅ 1. DI 없이 만든 코드 (직접 생성 방식, ❌비추천)
class DeviceRepository {
private val dao = AppDatabase.getInstance().deviceDao()
fun getDevices(): List<DeviceItem> {
return dao.getAllDevices()
}
}
class DeviceViewModel : ViewModel() {
private val repository = DeviceRepository()
fun loadDevices(): List<DeviceItem> {
return repository.getDevices()
}
}
❌ 문제점
- DeviceRepository를 만들 때마다 내부에서 dao를 직접 생성함
- ViewModel, Repository, DAO가 강하게 결합됨
- 테스트/유지보수 힘듦 (모킹 불가능)
✅ 2. DI 사용한 코드 (Hilt 기반, 추천 ✅)
// 1. DAO 모듈에서 제공
@Module
@InstallIn(SingletonComponent::class)
object DaoModule {
@Provides
fun provideDeviceDao(db: AppDatabase): DeviceDao = db.deviceDao()
@Provides
fun provideDeviceRepository(dao: DeviceDao): DeviceRepository = DeviceRepository(dao)
}
// 2. Repository
class DeviceRepository @Inject constructor(
private val dao: DeviceDao
) {
fun getDevices(): List<DeviceItem> = dao.getAllDevices()
}
// 3. ViewModel
@HiltViewModel
class DeviceViewModel @Inject constructor(
private val repository: DeviceRepository
) : ViewModel() {
fun loadDevices(): List<DeviceItem> = repository.getDevices()
}
✅ 장점
- ViewModel, Repository, DAO 간 결합도 낮음
- 테스트하기 쉬움 (Mock 주입 가능)
- 유지보수 쉬움 (Hilt가 객체 주입 관리)
✅ 3. 전체 구조 그림 (Hilt 기반 아키텍처)
[ View (Fragment/Activity) ]
↓
ViewModel (DeviceViewModel)
↓
Repository (DeviceRepository)
↓
DAO (DeviceDao)
↓
Room DB
[Hilt] 가 모든 걸 자동 주입해 줌
🔚 요약
비교 항목 |
DI 없이 |
DI 사용 |
객체 생성 |
직접 생성 (new) |
자동 주입 (@Inject) |
테스트 |
어려움 |
쉬움 (Mock 가능) |
유지보수 |
결합도 높음 |
느슨한 구조 |
코드 재사용성 |
낮음 |
높음 |
의존성 관리 |
수동 |
자동 (Hilt/Dagger |