A fork of our clean architecture boilerplate, this time using the Android Architecture Components

Overview

Build Status codecov Codacy Badge

Android Clean Architecture Components Boilerplate

Note: This is a fork of our original Clean Architecture Boilerplate, except in this repo we have switched out the MVP approach found in the presentation layer to now use ViewModels from the Android Architecture Components Library. The caching layer now also uses Room.

Welcome 👋 We hope this boilerplate is not only helpful to other developers, but also that it helps to educate in the area of architecture. We created this boilerplate for a few reasons:

  1. To experiment with modularisation
  2. To experiment with the Android Architecture Components
  3. To share some approaches to clean architecture, especially as we've been talking a lot about it
  4. To use as a starting point in future projects where clean architecture feels appropriate

It is written 100% in Kotlin with both UI and Unit tests - we will also be keeping this up-to-date as libraries change!

Disclaimer

Note: The use of clean architecture may seem over-complicated for this sample project. However, this allows us to keep the amount of boilerplate code to a minimum and also demonstrate the approach in a simpler form.

Clean Architecture will not be appropriate for every project, so it is down to you to decide whether or not it fits your needs 🙂

Languages, libraries and tools used

Requirements

Architecture

The architecture of the project follows the principles of Clean Architecture. Here's how the sample project implements it:

architecture

The sample app when run will show you a simple list of all the Bufferoos (Buffer team members!).

Drawing

Let's look at each of the architecture layers and the role each one plays :)

architecture

User Interface

This layer makes use of the Android Framework and is used to create all of our UI components to display inside of the Browse Activity. The layer receives its data from the Presentation layer and when retrieved, the received models are mapped using the Bufferoo Mapper so that the model can be mapped to this layer's interpretation of the Bufferoo instance, which is the BufferooViewModel. The Activity makes use of the BrowseBufferoosViewModel to retrieve data.

Presentation

This layer's responsibility is to handle the presentation of the User Interface, but at the same time knows nothing about the user interface itself. This layer has no dependence on the Android Framework, it is a pure Kotlin module. Each ViewModel class that is created implements the ViewModel class found within the Architecture components library. This ViewModel can then be used by the UI layer to communicate with UseCases and retrieve data. The BrowseBufferoosViewModel returns an instance of a Resource which contains data that can be used by the UI - this includes the ResourceState, data to be used by the UI and a message if required (for error states).

The ViewModels use an instance of a FlowableUseCase from the Domain layer to retrieve data. Note here that there is no direct name reference to the UseCase that we are using - we do inject an instance of the GetBufferoos UseCase, however.

The ViewModel receives data from the Domain layer in the form of a Bufferoo. These instances are mapped to instance of this layers model, which is a BufferooView using the BufferooMapper.

Domain

The domain layer responsibility is to simply contain the UseCase instance used to retrieve data from the Data layer and pass it onto the Presentation layer. In our case, we define a GetBufferoos - this use case handles the subscribing and observing of our request for data from the BufferooRepository interface. This UseCase extends the SingleUseCase base class - therefore we can reference it from outer layers and avoid a direct reference to a specific implementation.

The layer defines the Bufferoo class but no mapper. This is because the Domain layer is our central layer, it knows nothing of the layers outside of it so has no need to map data to any other type of model.

The Domain layer defines the BufferooRepository interface which provides a set of methods for an external layer to implement as the UseCase classes use the interface when requesting data.

architecture

Data

The Data layer is our access point to external data layers and is used to fetch data from multiple sources (the cache and network in our case). It contains an implementation of the BufferooRepository, which is the BufferooDataRepository. To begin with, this class uses the BufferooDataStoreFactory to decide which data store class will be used when fetching data - this will be either the BufferooRemoteDataStore or the BufferooCacheDataStore - both of these classes implement the BufferooDataStore repository so that our DataStore classes are enforced.

Each of these DataStore classes also references a corresponding BufferooCache and BufferooRemote interface, which is used when requesting data from an external data source module.

This layers data model is the BufferooEntity. Here the BufferooMapper is used to map data to and from a Bufferoo instance from the domain layer and BufferooEntity instance from this layer as required.

Remote

The Remote layer handles all communications with remote sources, in our case it makes a simple API call using a Retrofit interface. The BufferooRemoteImpl class implements the BufferooRemote interface from the Data layer and uses the BufferooService to retrieve data from the API.

The API returns us instances of a BufferooModel and these are mapped to BufferooEntity instance from the Data layer using the BufferooEntityMapper class.

Cache

The Cache layer handles all communication with the local database which is used to cache data.

The data model for this layer is the CachedBufferoo and this is mapped to and from a BufferooEntity instance from the Data layer using the BufferooEntityMapper class.

Conclusion

We will be happy to answer any questions that you may have on this approach, and if you want to lend a hand with the boilerplate then please feel free to submit an issue and/or pull request 🙂

Again to note, use Clean Architecture where appropriate. This is example can appear as over-architectured for what it is - but it is an example only. The same can be said for individual models for each layer, this decision is down to you. In this example, the data used for every model is exactly the same, so some may argue that "hey, maybe we don't need to map between the presentation and user-interface layer". Or maybe you don't want to modularise your data layer into data/remote/cache and want to just have it in a single 'data' module. That decision is down to you and the project that you are working on 🙌🏻

Thanks

A special thanks to the authors involved with these two repositories, they were a great resource during our learning!

Comments
  • Android Studio 3.2 Canary 14 Doesn't find any tests

    Android Studio 3.2 Canary 14 Doesn't find any tests

    Import the project into the latest canary for 3.2. You have to update a few dependencies like the android plugin and references to compile in the gradle files. compile needs to be changed to implementation.

    Once it's complete, go into any subproject and try to run the tests by right-click the root package and select Run Tests in .... You will see the output below:

    0 test classes found in package '<default package>'
    
    Process finished with exit code 254
    Empty test suite.
    
    opened by dmfrey 4
  • BrowseBufferoosViewModel doesn't survive configuration change

    BrowseBufferoosViewModel doesn't survive configuration change

    Steps to repro:

    1. Set a breakpoint or log in BrowseBufferoosViewModel.init
    2. Build & deploy
    3. Rotate device
    4. Observe that the log or breakpoint in BrowseBufferoosViewModel.init is hit for every rotation

    android.arch.lifecycle.ViewModels are meant to survive config changes.

    BrowseBufferoosViewModel will survive config changes if it's retrieved in BrowseActivity the normal way using ViewModelProviders.of. If you prefer to inject with dagger, take a look at this sample, then retrieve the ViewModel like so

    opened by vlazzle 2
  • How to implement onClick for RecyclerView?

    How to implement onClick for RecyclerView?

    What part of the application would need to implement onClick for users to be able to click on an item in the RecyclerView and navigate to a fragment/activity for the single model? Would you put it in the presentation layer or the mobile ui layer?

    opened by clj0020 1
  • Decoupling mobile-ui

    Decoupling mobile-ui

    https://github.com/bufferapp/clean-architecture-components-boilerplate/blob/15838f22b1acea74fbfbdb7612e8ed3cc38b3abc/mobile-ui/build.gradle#L67

    The module mobile-ui should depend only on the module presentation and not on all the modules.

    opened by ech0s7r 1
  • Refactor/restructure injection to match modularisation and allow multiple ViewModels

    Refactor/restructure injection to match modularisation and allow multiple ViewModels

    This pull request was started to support multiple ViewModels via a Provider as stated in #4. After reading https://medium.com/square-corner-blog/keeping-the-daggers-sharp-%EF%B8%8F-230b3191c3f I did some restructuring and refactoring regarding the dependency injection in general. If one would believe the aforementioned article then this approach should be more performant. I also had the idea to split up the modules to match the modularisation. That means that all dependencies from inside the data module are provided/bound by DataModule and so on. Let me know what you think.

    opened by anstaendig 1
  • I can't build project

    I can't build project

    Im use Android Studio 3.0 Beta 7 and Kotlin 1.1.51

    When I want to build project I getting an error

    Error:Execution failed for task ':cache:kaptDebugKotlin'.
    > Internal compiler error. See log for more details
    

    Gradle Console

    
    Configuration on demand is an incubating feature.
    Configuration 'compile' in project ':mobile-ui' is deprecated. Use 'implementation' instead.
    Configuration 'compile' in project ':presentation' is deprecated. Use 'implementation' instead.
    'kapt.generateStubs' is not used by the 'kotlin-kapt' plugin
    'kapt.generateStubs' is not used by the 'kotlin-kapt' plugin
    'kapt.generateStubs' is not used by the 'kotlin-kapt' plugin
    'kapt.generateStubs' is not used by the 'kotlin-kapt' plugin
    :cache:preBuild UP-TO-DATE
    :cache:preDebugBuild UP-TO-DATE
    :cache:compileDebugAidl
    :cache:compileDebugRenderscript
    :cache:checkDebugManifest
    :cache:generateDebugBuildConfig
    :cache:generateDebugResValues
    :cache:generateDebugResources
    :cache:packageDebugResources
    :cache:platformAttrExtractor
    :cache:processDebugManifest
    :cache:preDebugAndroidTestBuild UP-TO-DATE
    :cache:compileDebugAndroidTestAidl
    :cache:packageDebugRenderscript NO-SOURCE
    :cache:processDebugAndroidTestManifest
    :cache:compileDebugAndroidTestRenderscript
    :cache:generateDebugAndroidTestBuildConfig
    :cache:generateDebugAndroidTestResValues
    :cache:generateDebugAndroidTestResources
    :cache:mergeDebugAndroidTestResources
    :cache:mockableAndroidJar
    :mobile-ui:preBuild UP-TO-DATE
    :presentation:preBuild UP-TO-DATE
    :presentation:preDebugBuild UP-TO-DATE
    :presentation:checkDebugManifest
    :presentation:processDebugManifest
    :mobile-ui:preDebugBuild
    :presentation:compileDebugAidl
    :mobile-ui:compileDebugAidl
    :presentation:packageDebugRenderscript NO-SOURCE
    :mobile-ui:compileDebugRenderscript
    :mobile-ui:checkDebugManifest
    :mobile-ui:generateDebugBuildConfig
    :mobile-ui:generateDebugResValues
    :mobile-ui:generateDebugResources
    :presentation:compileDebugRenderscript
    :presentation:generateDebugResValues
    :presentation:generateDebugResources
    :presentation:packageDebugResources
    :mobile-ui:mergeDebugResources
    :mobile-ui:createDebugCompatibleScreenManifests
    :mobile-ui:processDebugManifest
    :mobile-ui:splitsDiscoveryTaskDebug
    :presentation:platformAttrExtractor
    :cache:processDebugResources
    :cache:generateDebugSources
    :cache:processDebugAndroidTestResources
    :cache:generateDebugAndroidTestSources
    :mobile-ui:preDebugAndroidTestBuild
    :mobile-ui:compileDebugAndroidTestAidl
    :mobile-ui:processDebugAndroidTestManifest
    :mobile-ui:compileDebugAndroidTestRenderscript
    :mobile-ui:generateDebugAndroidTestBuildConfig
    :mobile-ui:generateDebugAndroidTestResValues
    :mobile-ui:generateDebugAndroidTestResources
    :mobile-ui:mergeDebugAndroidTestResources
    :mobile-ui:splitsDiscoveryTaskDebugAndroidTest
    :mobile-ui:mockableAndroidJar
    :presentation:generateDebugBuildConfig
    :presentation:preDebugAndroidTestBuild UP-TO-DATE
    :presentation:compileDebugAndroidTestAidl
    :presentation:processDebugAndroidTestManifest
    :presentation:compileDebugAndroidTestRenderscript
    :presentation:generateDebugAndroidTestBuildConfig
    :presentation:generateDebugAndroidTestResValues
    :presentation:generateDebugAndroidTestResources
    :presentation:mergeDebugAndroidTestResources
    :presentation:mockableAndroidJar
    :presentation:processDebugResources
    :mobile-ui:processDebugResources
    :mobile-ui:generateDebugSources
    :mobile-ui:processDebugAndroidTestResources
    :mobile-ui:generateDebugAndroidTestSources
    :presentation:generateDebugSources
    :presentation:processDebugAndroidTestResources
    :presentation:generateDebugAndroidTestSources
    
    BUÄ°LD SUCCESSFUL in 9s
    55 actionable tasks: 55 executed
    Executing tasks: [:mobile-ui:assembleDebug]
    
    Configuration 'compile' in project ':mobile-ui' is deprecated. Use 'implementation' instead.
    Configuration 'compile' in project ':presentation' is deprecated. Use 'implementation' instead.
    'kapt.generateStubs' is not used by the 'kotlin-kapt' plugin
    'kapt.generateStubs' is not used by the 'kotlin-kapt' plugin
    'kapt.generateStubs' is not used by the 'kotlin-kapt' plugin
    'kapt.generateStubs' is not used by the 'kotlin-kapt' plugin
    :cache:preBuild UP-TO-DATE
    :cache:preDebugBuild UP-TO-DATE
    :cache:compileDebugAidl UP-TO-DATE
    :cache:compileDebugRenderscript UP-TO-DATE
    :cache:checkDebugManifest UP-TO-DATE
    :cache:generateDebugBuildConfig UP-TO-DATE
    :cache:generateDebugResValues UP-TO-DATE
    :cache:generateDebugResources UP-TO-DATE
    :cache:packageDebugResources UP-TO-DATE
    :cache:platformAttrExtractor UP-TO-DATE
    :cache:processDebugManifest UP-TO-DATE
    :cache:processDebugResources
    :domain:compileKotlin
    Using kotlin incremental compilation
    :domain:compileJava NO-SOURCE
    :domain:processResources NO-SOURCE
    :domain:classes UP-TO-DATE
    :domain:jar
    :data:compileKotlin
    Using kotlin incremental compilation
    :data:compileJava NO-SOURCE
    :data:processResources NO-SOURCE
    :data:classes UP-TO-DATE
    :data:jar
    :cache:kaptGenerateStubsDebugKotlin
    Using kotlin incremental compilation
    :cache:kaptDebugKotlin
    w: warning: Supported source version 'RELEASE_7' from annotation processor 'android.arch.persistence.room.RoomProcessor' less than -source '1.8'
    w: 
    
    
    e: C:\Proje\clean-architecture-components-boilerplate\cache\build\tmp\kapt3\stubs\debug\org\buffer\android\boilerplate\cache\model\CachedBufferoo.java:7: error: Cannot find getter for field.
    e: 
    
    e:     private long id;
    e:                  ^
    
    w: C:\Proje\clean-architecture-components-boilerplate\cache\build\tmp\kapt3\stubs\debug\org\buffer\android\boilerplate\cache\db\BufferoosDatabase.java:5: warning: Schema export directory is not provided to the annotation processor so we cannot export the schema. You can either provide `room.schemaLocation` annotation processor argument OR set exportSchema to false.
    w: 
    
    w: public abstract class BufferoosDatabase extends android.arch.persistence.room.RoomDatabase {
    w:                 ^
    
    e: java.lang.IllegalStateException: failed to analyze: org.jetbrains.kotlin.kapt3.diagnostic.KaptError: Error while annotation processing
    	at org.jetbrains.kotlin.analyzer.AnalysisResult.throwIfError(AnalysisResult.kt:57)
    	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules(KotlinToJVMBytecodeCompiler.kt:138)
    	at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:170)
    	at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:58)
    	at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.java:93)
    	at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.java:46)
    	at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:92)
    	at org.jetbrains.kotlin.daemon.CompileServiceImpl$compile$1$2.invoke(CompileServiceImpl.kt:386)
    	at org.jetbrains.kotlin.daemon.CompileServiceImpl$compile$1$2.invoke(CompileServiceImpl.kt:98)
    	at org.jetbrains.kotlin.daemon.CompileServiceImpl$doCompile$$inlined$ifAlive$lambda$2.invoke(CompileServiceImpl.kt:832)
    	at org.jetbrains.kotlin.daemon.CompileServiceImpl$doCompile$$inlined$ifAlive$lambda$2.invoke(CompileServiceImpl.kt:98)
    	at org.jetbrains.kotlin.daemon.common.DummyProfiler.withMeasure(PerfUtils.kt:137)
    	at org.jetbrains.kotlin.daemon.CompileServiceImpl.checkedCompile(CompileServiceImpl.kt:859)
    	at org.jetbrains.kotlin.daemon.CompileServiceImpl.doCompile(CompileServiceImpl.kt:831)
    	at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:385)
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    	at java.lang.reflect.Method.invoke(Method.java:498)
    	at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:346)
    	at sun.rmi.transport.Transport$1.run(Transport.java:200)
    	at sun.rmi.transport.Transport$1.run(Transport.java:197)
    	at java.security.AccessController.doPrivileged(Native Method)
    	at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    	at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
    	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
    	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)
    	at java.security.AccessController.doPrivileged(Native Method)
    	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    	at java.lang.Thread.run(Thread.java:745)
    Caused by: org.jetbrains.kotlin.kapt3.diagnostic.KaptError: Error while annotation processing
    	at org.jetbrains.kotlin.kapt3.AnnotationProcessingKt.doAnnotationProcessing(annotationProcessing.kt:90)
    	at org.jetbrains.kotlin.kapt3.AnnotationProcessingKt.doAnnotationProcessing$default(annotationProcessing.kt:42)
    	at org.jetbrains.kotlin.kapt3.AbstractKapt3Extension.runAnnotationProcessing(Kapt3Extension.kt:205)
    	at org.jetbrains.kotlin.kapt3.AbstractKapt3Extension.analysisCompleted(Kapt3Extension.kt:166)
    	at org.jetbrains.kotlin.kapt3.ClasspathBasedKapt3Extension.analysisCompleted(Kapt3Extension.kt:82)
    	at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM$analyzeFilesWithJavaIntegration$2.invoke(TopDownAnalyzerFacadeForJVM.kt:96)
    	at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:106)
    	at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$default(TopDownAnalyzerFacadeForJVM.kt:83)
    	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:377)
    	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:68)
    	at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:96)
    	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:368)
    	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules(KotlinToJVMBytecodeCompiler.kt:133)
    	... 30 more
    
    
    :cache:kaptDebugKotlin FAILED
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':cache:kaptDebugKotlin'.
    > Internal compiler error. See log for more details
    
    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
    
    * Get more help at https://help.gradle.org
    
    BUÄ°LD FAILED in 9s
    
    15 actionable tasks: 7 executed, 8 up-to-date
    
    
    opened by mustafakibar 1
  • Upgrade gradle version as well as some dependencies versions

    Upgrade gradle version as well as some dependencies versions

    Project wouldn't compile with current Android Studio and gradle version. Upgraded gradle plugin, then some other dependencies in order to comply with the newer gradle version. It compiles, and tests pass. *App doesn't work, I think the backend is to blame (it responds "Squarespace - Website Expired")

    opened by pedrorg18 0
  • Why is BufferooEntity in the data layer?

    Why is BufferooEntity in the data layer?

    I could be wrong here but I thought the domain layer should not be aware of anything in the data layer, and I that the "entities" are actually at the lowest layer inside the domain layer.

    So from my understanding the domain layer can have access to the entities but it should not know anything about the data layer version of an entity. So I'm confused as to why the BufferooEntity is at the data layer instead of the domain layer. Is it a naming mistake or am I not understanding something? As far as I can tell the names are the wrong way around and it's the Bufferoo that should be at the data layer and the BufferooEntity should be at the domain layer. Aside from the name they are identical.

    opened by mvescovo 0
  • Java 1.7 support

    Java 1.7 support

    The requirements state Java 1.8, which requires anrdoid api 24. If this project truly requires 1.8, then will it not work on all api's below 24 which run java 1.7?

    opened by edwardotis 0
  • saveBufferoos is called even when data is retrieved from cache

    saveBufferoos is called even when data is retrieved from cache

    In the following code saveBufferoos is called even when data is retrieved from cache (db)....for relatively large amounts of data this can be pretty time consuming.

        override fun getBufferoos(): Flowable<List<Bufferoo>> {
            return factory.retrieveCacheDataStore().isCached()
                    .flatMapPublisher {
                        factory.retrieveDataStore(it).getBufferoos()
                    }
                    .flatMap {
                        Flowable.just(it.map { bufferooMapper.mapFromEntity(it) })
                    }
                    .flatMap {
                        saveBufferoos(it).toSingle { it }.toFlowable()
                    }
        }
    
    opened by joreilly 2
  • CompositeDisposable dispose vs clear in FlowableUseCase

    CompositeDisposable dispose vs clear in FlowableUseCase

    Have adapted some of this code for my own project and one issue I ran in to was around use of CompositeDisposable.dispose() in FlowableUseCase for case where I need to update the subscription. In my case at least switching to clear resolved the issue. It looks like calling dispose has effect of not allowing subsequent use of disposables.

    opened by joreilly 3
  • @PerActivty scope

    @PerActivty scope

    First off, thanks for all the great work that went into this repo.

    I just wanted some clarification with the purpose of @PerActivity. To explain further, after a configuration change the BrowseBufferoosViewModel instance returned by the framework will be the same one (same memory location) as before the config change happened (i.e. the instance is retained across configuration changes). This is one of the benefits of using the new ViewModel Architecture Component. It may be desired for other objects that are not tied to the Android framework to have this same behavior (i.e. an object that prevents the user to move to another screen if a network request is ongoing while a config change is happening). Dagger can be leveraged to achieve this by using scoping. Is this what you are trying to achieve with @PerActivity or are you just indicating that the module is providing Activity specific dependencies?

    P.S. I realize that if we want an object to be retained across config changes, we can make it a dependency of the ViewModel in question, but this may lead to overly complicated constructors.

    opened by emmano 0
  • Indirect dependencies

    Indirect dependencies

    Hello @hitherejoe ,

    I have a question about dependencies. Currently, Remote module depends on Data, and Data module depends on Domain and because of that If we want to get information from Remote with Models that actually should be only in Remote we have to create a duplication of that model at each layer.

    Example: We have Remote module for the API that has method getRepositoryByPlatform(platform: Platform) and our Platform is simple Enum class enum class Platform { IOS, ANDROID } without duplication Platform class would be in Domain layer. But in this case if we need to specify @SerializedName for example, we would need to add Gson dependency to Domain layer, that looks incorrect from my point of view. And because of that creating Platform representation model at each layer looks like an overhead to me.

    So the question is how do you handle such cases?

    opened by Dwite 5
Owner
Buffer
Helping people build their business on social media since 2011
Buffer
An android boilerplate project using clean architecture

Android Clean Architecture Boilerplate Welcome ?? We hope this boilerplate is not only helpful to other developers, but also that it helps to educate

Buffer 3.6k Jan 4, 2023
Kotlin Multiplatform lifecycle-aware business logic components (aka BLoCs) with routing functionality and pluggable UI (Jetpack Compose, SwiftUI, JS React, etc.), inspired by Badoos RIBs fork of the Uber RIBs framework

Decompose Please see the project website for documentation and APIs. Decompose is a Kotlin Multiplatform library for breaking down your code into life

Arkadii Ivanov 819 Dec 29, 2022
Boilerplate code for implementing MVVM in Android using Jetpack libraries, coroutines, dependency injection and local persistance

MVVM Foundation This projects aims to speed up development of Android apps by providing a solid base to extend Libraries Jetpack Fragment Material3 :

Gabriel Gonzalez 2 Nov 10, 2022
Built with Jetpack compose, multi modules MVVM clean architecture, coroutines + flow, dependency injection, jetpack navigation and other jetpack components

RickAndMortyCompose - Work in progress A simple app using Jetpack compose, clean architecture, multi modules, coroutines + flows, dependency injection

Daniel Waiguru 9 Jul 13, 2022
To illustrate the clean architecture and modularisation with other components.

CleanNews A news app that provides data from mediastack API using clean architecture, kotlin coroutines, architectural pattern (MVI) with Mavericks. .

Yves Kalume 4 Feb 13, 2022
Android-Boilerplate - Base project for android development with new technology

Android-Boilerplate Base project for android development with new technology, in

Muhammad Rizky Arifin 1 Aug 15, 2022
A Kotlin library for reactive and boilerplate-free SharedPreferences in Android

KPreferences A Kotlin library for reactive and boilerplate-free Shared Preferences in Android. With KPreferences you can use Kotlin's marvelous delega

Mohamad Amin Mohamadi 19 Dec 16, 2020
An Android template project (in Kotlin) with boilerplate and current patterns.

android-starter-v4 An Android template project (in Kotlin) with boilerplate and plumbing, exploring current architecture patterns. A bit too much for

Matthias Urhahn 14 Nov 4, 2022
👋 A common toolkit (utils) ⚒️ built to help you further reduce Kotlin boilerplate code and improve development efficiency. Do you think 'kotlin-stdlib' or 'android-ktx' is not sweet enough? You need this! 🍭

Toolkit [ ?? Work in progress ⛏ ?? ??️ ?? ] Snapshot version: repositories { maven("https://s01.oss.sonatype.org/content/repositories/snapshots") }

凛 35 Jul 23, 2022
Clean MVVM with eliminating the usage of context from view models by introducing hilt for DI and sealed classes for displaying Errors in views using shared flows (one time event), and Stateflow for data

Clean ViewModel with Sealed Classes Following are the purposes of this repo Showing how you can remove the need of context in ViewModels. I. By using

Kashif Mehmood 22 Oct 26, 2022
Reapp is everything you need to build amazing apps with React: a collection of packages that work together, our UI kit, and a CLI that scaffolds your app and includes a server and build system.

What is it? Reapp is everything you need to build amazing apps with React: a collection of packages that work together, our UI kit, and a CLI that sca

reapp 3.4k Nov 20, 2022
A FDPClient fork , It aims to add more modules.

LightClient A FDPClient fork , It aims to add more modules. You can download development version at Github-Actions , Release at Release Only running o

Ad973_ 3 Aug 26, 2021
A high-performance fork of Paper/Airplane designed for large servers.

Pufferfish A highly optimized Paper/Airplane fork designed for large servers requiring both maximum performance, stability, and "enterprise" features.

Pufferfish Studios LLC 399 Jan 7, 2023
Minecraft Server Software specially designed for Thicc SMP. Here on GitHub without the private patches, just a normal hybrid JettPack-Pufferfish-Empirecraft fork

AlynaaMC A private, custom server software for Thicc SMP and a fork of Pufferfish. Here on GitHub with patches from JettPack, Airplane and Pufferfish

ThiccMC 14 Dec 31, 2021
A fork from Paper and unofficial Airplane continuation for RedeObscurity.

Obscurity A fork from Paper and unofficial Airplane continuation for RedeObscurity. Features Downloads This fork is in a state of development. If you

null 0 Jan 6, 2022
WolfxPaper - A Paper fork designed for Wolfx Survial, may useful for some Semi-Vanilla Server

WolfxPaper A Paper fork designed for Wolfx Survial, may useful for some "Semi-Va

TenkyuChimata 1 Jan 19, 2022
Minecraft 1.18.2 Backport of Petal, a performance-oriented fork of Purpur intended to increase performance for entity-heavy servers by implementing multi-threaded and asynchronous improvements.

Sakura Performance Minecraft JAR Sakura is a performance-oriented fork of Purpur intended to increase performance for entity-heavy servers by implemen

etil.sol 14 Nov 23, 2022
A smart colored time selector. Users can select just free time with a handy colorful range selector.

Colored Time Range Selector A smart colored time range selector. Users can select just free time with a handy colorful range selector. Screen Shots Fe

Ehsan Mehranvari 154 Oct 3, 2022