Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Droidcon Webinar Series 2021

Droidcon Webinar Series 2021

What is clean architecture? Why is everyone talking about clean? And How to adopt it in a monolith app?

All about the nitty-gritty of Clean Architecture, different models and benefits. The talk will cover the essentials of adopting a clean architecture and its benefits.

Hitesh Das

March 20, 2021
Tweet

More Decks by Hitesh Das

Other Decks in Technology

Transcript

  1. //01 // 2 Hitesh Das Senior Engineering Manager Times Internet

    “Currently I am working in TIL Central Mobile App Team platform project initiatives and closely with the Dineout team leading Apps Development/Architecture.”
  2. //01 // 4 The GOD class Knows too much or

    does too much - Very famous in bad programming. - A huge class in terms of number of lines of code. - Creates tight coupling. - Increases the challenges in the code maintainability.
  3. //01 // 5 How to detect a GOD class? Main

    Characteristics - They are large and complex. - They heavily access data of other simpler classes, either directly or using accessor methods. - They have a lot of non-communicative behavior i.e., there is a low cohesion between the methods belonging to that class.
  4. //01 // 6 Cohesion and Coupling Low Cohesion High Coupling

    High Cohesion Low Coupling Bad Modularization Good Modularization
  5. //01 // 7 What’s in an Application? Uncle Bob’s view

    “... Group of use cases that describes the intent of the application and a group of plugins that give those use cases access to the outside world…”
  6. //01 // 8 What’s in a good architecture? Architecture is

    the shape of a system. It supports the behavior of the system while keeping its flexibility to most of the changes. Hence, a good architecture is scalable. More flexible and maintainable.
  7. //01 // 9 The Clean way At the heart of

    the Clean Architecture(CA) lies the Business Logic. No dependency with the outside world (UI, Libraries, Frameworks, Platform, Data Source etc. etc.) Abstraction & Separation of Concern
  8. //01 // 10 How to achieve this? The Dependency Rule

    - Inner layer does not know about the outer layers. - Dependency always move inwards
  9. //01 // 11 Dependency Inversion How to keep the Use

    Cases independent from the Repositories? - Abstraction - Implementation - Injection Use Cases Repository Use Cases RepositoryImpl Repository has-a implements Inject RepositoryImpl
  10. //01 // 12 The CA Layers - from Android Application

    point of view View View Model Entities Use Cases Abstractions Repository Network Source Disk Source Presentation Layer Domain Layer Data Layer Presenter
  11. //01 // 13 The Event-Data Flow UIModel UIModelMapper DomainModel DataModelMapper

    DataModel Presentation Layer Domain Layer Data Layer dependencies View ViewModel Use Case RepositoryImpl Repository
  12. //01 // 14 Layering your application Multiple approaches Single Module

    app presentation domain data Separate modules presentation domain data We can also split this single module approach into multiple feature modules where layers lies inside each feature module. We can also split this approach into a hybrid approach where feature is itself splitted into layers. (e.g feature_a_domain, feature_a_data) Has platform dependency. Separation can be made via custom lint rules Platform agnostic. Separation can be enforced by module dependency
  13. //01 // 15 Design Principles S - Single Responsibility Principle

    (SRP) - Ensures one, and only one, reason to be changed O - Open Closed Principle (OCP) - Enables adding new functionality without changing the existing code L - Liskov Substitution Principle (LSP) - Derived class must be completely be able to substitute its Base class I - Interface Segregation Principle (ISP) - Ensures interface members to have very high cohesion D - Dependency Inversion Principle (DIP) - Details should depend on abstractions SOLID
  14. //01 // 16 Design Principles Don’t repeat yourself Every piece

    of knowledge or logic must have a single, unambiguous representation within a system. - Divide your system into pieces. Divide your code and logic into smaller reusable units and use that code by calling it where you want. - Don't write lengthy methods, but divide logic and try to use the existing piece in your method. Less code is always good :) DRY
  15. //01 // 17 Design Principles Keep it simple stupid -

    Keep coding simple and straightforward. - Keep your methods small. - Each method should only solve one small problem, not many use cases. - If you have a lot of conditions in the method, break these out into smaller methods. This makes it easier to read and maintain. - It can help find bugs a lot faster KISS
  16. //01 // 18 The Implementation Presentation Layer data class UserViewDataModel(val

    name: String) class SomeView { private val viewModel = SomeViewModel(FetchUsersUseCase(UserRepositoryImpl(UserNetworkDataSource()))) fun loadUI() { val userListWithNameStartsWithA = viewModel.loadUsersList() // Show list in the view } } class SomeViewModel(private val fetchUserUseCase: FetchUsersUseCase) { fun loadUsersList(): List<UserViewDataModel> { return fetchUserUseCase.get().map { UserViewDataModel(it.name) } } } Domain Layer Mapper
  17. //01 // 19 The Implementation Domain Layer data class User(

    val userId: String, val name: String ) interface UserRepository { fun get(): List<User> } class FetchUsersUseCase(private val userRepository: UserRepository) { fun get(): List<User> { val rawUserList = userRepository.get() return filterList(rawUserList) } private fun filterList(rawUserList: List<User>): List<User> { return rawUserList.filter { user -> user.name.startsWith("A") } } } Data Layer Presentation Layer
  18. //01 // 20 The Implementation Data Layer data class UserDataModel(

    val userId: String, val name: String, val address: String, val dateOfBirth: String ) interface UserDataSource { fun loadUsers(): List<UserDataModel> } class UserNetworkDataSource: UserDataSource { override fun loadUsers(): List<UserDataModel> { TODO("Load list from network") } } class UserRepositoryImpl(private val dataSource: UserDataSource) : UserRepository { override fun get(): List<User> { return dataSource.loadUsers().map { User(it.userId, it.name) } } } Framework/Libraries Domain Layer Mapper
  19. //01 // 21 ? Why do we need so many

    layers Software is inevitable. Defects No Reuse Rewrites Too many GOD Classes Afraid to Change Increase Development times Side effects Change
  20. //01 // 22 What do we achieve? - Separation of

    concerns - Flexibility to change - Testability - Consistency - Faster Time to market - Maintainability
  21. //01 // 23 References Articles - https://www.linkedin.com/pulse/architecture-learnings-part-1-what-model-hitesh-das/ - https://www.linkedin.com/pulse/architecture-learnings-part-2-how-build-uiview-reacts-hitesh-das/ -

    https://www.linkedin.com/pulse/architecture-learnings-part-3-what-domain-hitesh-das/ - https://www.linkedin.com/pulse/architecture-learnings-part-4-understanding-popular-mvx-hitesh-das/ - https://www.linkedin.com/pulse/architecture-learnings-part-5-decoding-solid-principles-hitesh-das/ Resources - https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html - https://medium.com/@dmilicic/a-detailed-guide-on-developing-android-apps-using-the-clean-architecture-pattern-d38d71e94029 - https://proandroiddev.com/multiple-ways-of-defining-clean-architecture-layers-bbb70afa5d4a
  22. //01 // 24 Thanks Let’s take some questions Find me

    on - Linkedin : https://www.linkedin.com/in/hiteshdas1912/ - Twitter : @hiteshdas - Medium : https://dashitesh.medium.com/ - GitHub : https://github.com/hiteshdroid