Enterprise Level Application Architecture


In Android development, Data, Domain, and Presentation layers are often used to organize code and follow clean architecture principles. This approach enhances maintainability, scalability, and testability of your codebase.
Below is a detailed explanation of each layer in the Data-Domain-Presentation architecture:
1. Presentation Layer
This is the UI layer where the user interacts with the app.
Role:
Handles user input and displays data to the user.
Contains Android-specific components like Activity, Fragment, ViewModel, Jetpack Compose, or XML layouts.
Components:
UI Components:
Activity/Fragment: The main entry points for UI.
Jetpack Compose Views: Modern, declarative UI design.
XML Layouts: Traditional way to design UI.
ViewModel (from MVVM):
Acts as a bridge between the UI and Domain layers.
Holds and manages UI-related data in a lifecycle-conscious way.
Observes changes in data via
LiveData
,StateFlow
, orFlow
.
Example:
// Presentation Layer - ViewModel
class ProductViewModel(private val getProductsUseCase: GetProductsUseCase) : ViewModel() {
private val _products = MutableLiveData<List<Product>>()
val products: LiveData<List<Product>> get() = _products
fun fetchProducts() {
viewModelScope.launch {
val result = getProductsUseCase()
_products.postValue(result)
}
}
}
Key Points:
Stateless UI: UI components just display the data they receive.
Delegate business logic to the Domain layer and data retrieval to the Data layer.
2. Domain Layer
This is the business logic layer. It is independent of the Android framework.
Role:
Contains business logic and rules for the app.
Interacts with the Data layer and Presentation layer.
Facilitates clean separation by defining Use Cases.
Components:
Use Cases (Interactors):
Each use case performs a single operation (e.g.,
GetProductsUseCase
).Takes input, processes it, and returns output (data).
Entities:
- Plain data objects (POJOs) that represent the core business models.
Example:
// Domain Layer - Use Case
class GetProductsUseCase(private val productRepository: ProductRepository) {
suspend operator fun invoke(): List<Product> {
return productRepository.getProducts()
}
}
// Domain Layer - Entity
data class Product(
val id: String,
val name: String,
val price: Double
)
Key Points:
Does not depend on Android SDK.
Promotes reusability and easy testing.
3. Data Layer
This is the data management layer. It handles data retrieval, storage, and network operations.
Role:
Provides data to the Domain layer.
Fetches data from:
Remote Sources (e.g., REST API, Firebase).
Local Sources (e.g., Room Database, SharedPreferences).
Implements Repository Pattern to abstract data sources.
Components:
Repository:
Mediates between data sources and domain logic.
Decides whether to fetch data from remote or local sources.
Data Sources:
RemoteDataSource: API calls using libraries like Retrofit or OkHttp.
LocalDataSource: Database operations using Room or SQLite.
Models:
- DTOs (Data Transfer Objects) or entities for data layers.
Mappers:
- Convert data models (e.g., DTOs) into domain entities.
Example:
// Data Layer - Repository
class ProductRepositoryImpl(
private val remoteDataSource: RemoteDataSource,
private val localDataSource: LocalDataSource
) : ProductRepository {
override suspend fun getProducts(): List<Product> {
return try {
val productsDto = remoteDataSource.fetchProducts()
productsDto.map { it.toDomain() }
} catch (e: Exception) {
localDataSource.getCachedProducts()
}
}
}
// RemoteDataSource
class RemoteDataSource(private val apiService: ApiService) {
suspend fun fetchProducts(): List<ProductDto> {
return apiService.getProducts()
}
}
// DTO and Mapper
data class ProductDto(val id: String, val title: String, val price: Double)
fun ProductDto.toDomain() = Product(id, title, price)
Key Points:
Repository abstracts data sources from the Domain layer.
Mappers convert between layers (e.g., DTO → Domain Entity).
Focuses on network handling, caching, and other data operations.
Architecture Diagram:
Presentation Layer (UI)
└── ViewModel → Domain Layer (Use Cases)
└── Repository → Data Layer (Remote/Local Data Sources)
Benefits of This Architecture:
Separation of Concerns: Each layer has a single responsibility.
Testability: You can unit test each layer independently.
Scalability: Easy to add new features without affecting other layers.
Maintainability: Clean structure reduces coupling and makes refactoring easier.
Reusability: Domain layer logic can be reused across different apps or platforms.
Tech Stack:
Layer | Technologies |
Presentation | Jetpack Compose, ViewModel, LiveData, Flow |
Domain | Kotlin Coroutines, Plain Kotlin Classes |
Data | Retrofit, OkHttp, Room, Firebase, Hilt |
Github Repo: https://github.com/shaikhsiddik/EnterpriseArchitecture
Subscribe to my newsletter
Read articles from Shaikh Siddik directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Shaikh Siddik
Shaikh Siddik
As an experienced Android developer with 6 years of experience, I have developed a wide range of applications for various industries, including healthcare, telco, e-commerce, and more. My expertise includes: - Proficiency in Java and Kotlin programming languages - Strong knowledge of Android SDK, Android Studio, and Gradle - Experience with RESTful APIs and third-party libraries integration - Familiarity with agile development methodologies - Excellent debugging and troubleshooting skills - Ability to develop responsive UI/UX designs - Experience with Google Play Store publishing and distribution. I am a quick learner and always stay up-to-date with the latest trends and technologies in the Android development world.