最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

android - Where to map to domain from Data layer in MVVM Clean Architecture? - Stack Overflow

programmeradmin2浏览0评论

'm working on an Android application using the MVVM architecture with clean code principles. The app has three layers:

UI -> Domain -> Data (Repository -> Data Source)

From the data layer, I want to return a domain object to maintain separation of concerns. However, I'm unsure where to handle the mapping between the data transfer object (DTO) and the domain object—whether it should be done in the repository or the data source.

Here’s an example of mapping in the repository:

class MyRepository(private val dataSource: MyDataSource) {

    suspend fun fetchData(): Either<Failure, MyData> {
        return when (val result = dataSource.getMyData()) {
            is Either.Left -> result
            is Either.Right -> Either.Right(result.b.toDomain())
        }
    }

    interface MyDataSource {
        suspend fun getMyData(): Either<Failure, MyDataDto>}

    class MyRemoteDataSourceImpl(private val apiService: ApiService) : MyDataSource {

    override suspend fun getMyData(): Either<Failure, MyDataDto> {
        return try {
            val response = apiService.getData()
            if (response.isSuccessful) {
                response.body()?.let {
                    Either.Right(it)
                } ?: Either.Left(Failure.UnknownError("Response body is null"))
            } else {
                Either.Left(Failure.ServerError)
            }
        } catch (e: IOException) {
            Either.Left(Failure.NetworkError)
        } catch (e: Exception) {
            Either.Left(Failure.UnknownError(e.localizedMessage ?: "Unknown error"))
        }
    }}

With this approach, I feel like the repository is tightly coupled to the data source. If the data source changes and returns a different DTO, the repository would also need to be modified.

  • Other option would be mapping on data source, however with that approach data source will have a lot of to do, call api and mapping to domain(Data source dont know)

  • Third option would be mapping to repository then in repository map to domain. With that approach we could make some of separation however we must have two mappers.

  • Last option is a interface that DTo will extends with parameters and a mapper to domain.

Please let me know which option you think is the best

'm working on an Android application using the MVVM architecture with clean code principles. The app has three layers:

UI -> Domain -> Data (Repository -> Data Source)

From the data layer, I want to return a domain object to maintain separation of concerns. However, I'm unsure where to handle the mapping between the data transfer object (DTO) and the domain object—whether it should be done in the repository or the data source.

Here’s an example of mapping in the repository:

class MyRepository(private val dataSource: MyDataSource) {

    suspend fun fetchData(): Either<Failure, MyData> {
        return when (val result = dataSource.getMyData()) {
            is Either.Left -> result
            is Either.Right -> Either.Right(result.b.toDomain())
        }
    }

    interface MyDataSource {
        suspend fun getMyData(): Either<Failure, MyDataDto>}

    class MyRemoteDataSourceImpl(private val apiService: ApiService) : MyDataSource {

    override suspend fun getMyData(): Either<Failure, MyDataDto> {
        return try {
            val response = apiService.getData()
            if (response.isSuccessful) {
                response.body()?.let {
                    Either.Right(it)
                } ?: Either.Left(Failure.UnknownError("Response body is null"))
            } else {
                Either.Left(Failure.ServerError)
            }
        } catch (e: IOException) {
            Either.Left(Failure.NetworkError)
        } catch (e: Exception) {
            Either.Left(Failure.UnknownError(e.localizedMessage ?: "Unknown error"))
        }
    }}

With this approach, I feel like the repository is tightly coupled to the data source. If the data source changes and returns a different DTO, the repository would also need to be modified.

  • Other option would be mapping on data source, however with that approach data source will have a lot of to do, call api and mapping to domain(Data source dont know)

  • Third option would be mapping to repository then in repository map to domain. With that approach we could make some of separation however we must have two mappers.

  • Last option is a interface that DTo will extends with parameters and a mapper to domain.

Please let me know which option you think is the best

Share Improve this question edited Feb 6 at 11:08 Pratik Fagadiya 1,47212 silver badges26 bronze badges asked Feb 6 at 10:15 user1866731user1866731 4992 gold badges6 silver badges13 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 2

The best approach is to perform the mapping in the repository layer. This aligns with Clean Architecture principles and ensures proper separation of concerns.

Why Mapping Should Happen in the Repository

1. Separation of Concerns:

Data Source: Responsible for fetching raw data (e.g., API calls, database queries) and returning DTOs.

Repository: Orchestrates data flow, handles business logic, and maps DTOs to domain models.

Domain Layer: Contains pure business logic and domain models, independent of data sources.

2. Flexibility:

If you change the data source (e.g., switch from API to local database), only the repository needs to adapt the mapping logic. The domain layer remains unchanged.

3. Testability:

Repositories can be easily tested with mocked data sources and mappers.

Data sources can be tested independently without worrying about domain models.

4. Single Responsibility:

Data sources focus on I/O operations.

Repositories focus on coordinating data flow and mapping.

In my opinion, you should perform the mapping in the repository. The repository must be responsible for providing a fully created domain object, ensuring that the domain layer works with clean and structured data.

The way I understand Clean Architecture:

In Clean Architecture you would have your application-specific logic in another layer (application). You define Gateway interfaces in application and you implement those interfaces in your data layer.

In your case, you are usind repositories in your domain. That is closer to the structure and wording used in ddd.

Still, I would define a repository interface MyRepository and have different implementations, one for each data source. MyRemoteApiRepository, MyInMemoryRepository, MySqliteRepository.

Each implementation uses the DTO that best fits its respective data source technology, with the mapping to and from the domain model handled within the repository implementation.

This way the domain stays agnostic to the technology used in the implementation and you change the repository implementation when your data source changes. That can even be done at runtime.

发布评论

评论列表(0)

  1. 暂无评论