changed 6 years ago
Published Linked with GitHub

Android Architecture

Intro

Project architecture based on CLEAN architecture with feature based package structure. This approach helps to retain code consistency for a large code base and provides ability for splitting up project in modules.

Layer structure

Code consists of 6 layers:

  • Cache
  • Remote
  • Data
  • Domain
  • Presentation
  • View

The dependency structure is following:

Layers structure

For now all layers lay down in the same gradle module but there are plans to split them between distinct gradle modules after code migration will be finished.

In code each layer represented by root package.

Root packages

Feature by package

Layers package consists basically consists of base package with some base code and feature packages along with some layer specific packages. base package should have the same structure as the feature packages of this level.

Feature package of current level can depend on another feature packages of this level and on feature packages of levels that current level depends on.

Example:

class CourseInteractor @Inject constructor( CourseRepository, // course feature package LessonRepository // lesson feature package of domain level )

Models and mappers

You'll see a lot of models and mappers in this architecture but you shouldn't use all of them if you don't need to. For example if you have object like this

class Data( @SerializedName("name") val name: String )

that came from API in the same way, can be stored to db without changes and passed to view you can declare it in domain layer and skip all mappers and models on other layers.

Layers

Cache

Cache layer contains everything you need to work with local db storage. All packages are optional as the layer itself. So you should not create cache level for feature with no caching logic and in the same way you don't need to create mapper package or model package if data layer model can be stored without changes.

Cache packages

CacheDataSource

Cache data source implementation connects cache layer with data layer.

Naming convention: feature name + CacheDataSourceImpl suffix
Example: VideoCacheDataSourceImpl

dao

Package with dao implementations for each object.

Naming convention: object name + EntityDao suffix
Example: VideoEntityDao

mapper

Package with mappers to map from data layer models to cache models

Naming convention: object name + EntityMapper suffix
Example: VideoEntityMapper, CourseEntityMapper

model

Package with pojo classes that represents database entities.

Naming convention: object name + Entity suffix
Example: VideoEntity, VideoUrlEntity, CourseEntity

structure

Package with table schemes constants

Naming convention: object name + DbScheme

Dependency map

Cache dependendecy map

Remote

In global context remote layer serves the similar role to cache layer it's another data source. remote package has the same structure with feature base package and base package.

Remote packages

RemoteDataSource

Remote data source implementation connects remote layer with data layer.

Naming convention: feature name + RemoteDataSourceImpl suffix
Example: VideoRemoteDataSourceImpl

mapper

Package with mappers to map from remote models to data layer models

Naming convention: object name + Mapper suffix
Example: VideoMapper, CourseMapper

model

Package with pojo classes that represents request structures and will be parsed with gson.

Naming convention: object name + Request/Response suffix
Example: CourseRequest, EnrolmentRequest, CourseResponse

service

Package with retrofit services interfaces.

Naming convention: feature name + Service suffix
Example: EnrolmentService

Dependency map

Remote dependency map

Data

Main goal of data layer is to manages data within available sources.

Data packages

mapper

Package with mappers to map from data models to domain layer models

Naming convention: object name + Mapper suffix
Example: VideoMapper, CourseMapper

model

Package with pojo classes that represents data layer models.

Naming convention: object name
Example: Course, Enrolment

repository

Package with repositories interfaces implementations. Repository contains logic that manages data between sources.

Naming convention: feature name + RepositoryImpl suffix
Example: CourseRepositoryImpl

source

Package with source interfaces.

Naming convention: feature name + source type + DataSource suffix
Example: CourseRemoteDataSource, CourseCacheDataSource

Dependency map

Data dependency map

Domain

Domain layer contains all business logic of application.

Domain packages

exception

Package with bussiness logic exceptions. Those exceptions could be thrown from domain, data or sources levels and should be handled in presentation level.

Naming convention: case name + Exception suffix
Example: NotAuthorizedException

interactor

Package with bussiness logic. Interactor should unite common case logic. Interactor could be splat up in disctinct interactors that carries less logic.

Naming convention: case name + Interactor suffix
Example: CourseInteractor, CourseEnrolmentInteractor, CourseBillingInterctor

mapper

Package with mappers to map data from another domain packages.

Naming convention: target object name + Mapper suffix
Example: CourseContentMapper, CourseInfoMapper

model

Package with pojo classes that represents domain layer models.

Naming convention: object name
Example: CourseContent, CourseInfo, EnrolmentStatus

repository

Package with repositories interfaces.

Naming convention: object name + Repository suffix
Example: CourseRepository

resolver

Package with different resolvers and helpers in order to simplify interactors in some cases.

Naming convention: case name + Resolver suffix
Example: DeadlinesResolver

Dependency map

Domain dependency map

Presentation

Presentation layer connects view level with domain level and manages view states.

Presentation packages

mapper

Package with mappers to map data from domain or presentation layers. This can be useful to map view states.

Naming convention: target object name + Mapper suffix
Example: CourseContentItemsMapper

model

Package with pojo classes that represents models which is used in view states.

Naming convention: object name
Example: DeadlineState

Presenter

Presenter that manages current view state and fetches data from interactors.

Naming convention: feature name + Presenter suffix
Example: CoursePresenter

View

View contract.

Naming convention: feature name + View suffix
Example: CourseView

Dependency map

Presentation dependency map

View

View is the last layer in this architecture which consists of platform related implementations of displaying content. In global terms this layer characterize application. Along with view implementations it contains DI components needed to build application.

View packages

injection

Injection package contains everything related to dependency injection as components, modules and scopes. It structured in the same way as layer package with base package and feature packages. Usually feature package consists of:

  • FeautureNameDataModule module that provides data layer of feature (if exists) with repository implementation
  • FeatureNameModule module with presenters bindings and other feauture related components
  • FeatureNameRoutingModule module with feature specific routers
  • FeatureNameScope scope of feauture if needed
  • FeatureNameComponent component of feauture if needed

Usually there are a lot of features that have only FeatureNameDataModule that is included in another components.

mapper

Package with mappers to map data from domain or presentation layers to view level models.

Naming convention: target object name + Mapper suffix
Example: CourseContentItemsMapper

model

Package with pojo classes that represents models which is used in views, like RecyclerView adapter items and etc.

Naming convention: object name
Example: DeadlineState

routing

Package with routers specific to current feature, like branch routers or deeplink routers.

Naming convention: feature name + case name + Router
Example: CourseDeeplinkRouter

TBD

ui

Package with everything related to ui like activities, fragments, adapters, delegates, views etc.

Dependency map

View dependency map

Where should I put that code?

If after reading the previous paragraph you still have question: "Where should I put that code?" just keep in mind that code structure should be easy splittable by layers and by features.

All features diagram

As can be seen from this diagram code base is easy splittable and each code block can be extended to distinct gradle module and be reused in different target or application. Dashed arrows means optional dependencies.

All elements dependency map

All dependencies map

Select a repo