Coder Social home page Coder Social logo

social-media's Introduction

Social-media

Is a new version of code for my Social media app with Clean Architecture. I used most of Clean code tips with android, SOLID principles and design-patterns..

❤️ Clean Architecture ❤️

  • I have written about how to architect android application using the Uncle Bob's clean architecture approach. and what's this architecture and why we should use an architecture here.
  • And this an old project but i made it again with Uncle Bob's clean architecture approach Let's go and see what's the new here.

Clean Architecture maximizes the use of SOLID principles and we used all of them let's see 🏃 :

⭐ Single Responsibility

Each software component should have only one reason to change – one responsibility. So whatever class you have or whatever function you have these functions and classes should always only have one single responsibility and one reason to change.

for example getPosts function ! 🤩

class RepositoryImp @Inject constructor(
    private var database: Database
) : Repository {
    // I have one responsibility and it's just get post from database and return list of posts
    override suspend fun getPosts(): List<Post> = database.getAllPosts()
    
    override fun getUser(): User {
        TODO("Not yet implemented")
    }
}

⭐ Open-closed

  • You should be able to extend the behavior of a component, without breaking its usage, or modifying its extensions.
  • For example in this project we have a Database interface and DatabaseFromFirebase class which is extend or implement Database interface methods. Now if we want to modify something or add a function for example we can do in (Child):baby: class.
  • Now you opened your Database interface to extention, anyone wants to add or modify something he will extend your Database interface and add what he want in his own child class 👶 (DatabaseFromFirebase class). and your class is closed to modification.
interface Database {
    suspend fun setUserDataInfoOnDatabase(user: User): Task<Void>
    suspend fun getCurrentUserData(id: String): User
    suspend fun getAllUsers(): List<User>
    suspend fun getAllPosts(): List<Post>
}

// this is your own implementation of the Database interface do whatever you want here
class DatabaseFromFirebase @Inject constructor(
    private var databaseRef: DatabaseReference,
    ) : Database {
    
    override suspend fun getAllPosts(): List<Post> {
        return databaseRef.child(Constants.POSTS).get().await()
            .children.map {
                it.getValue(Post::class.java)!!
            }
    }
    override suspend fun setUserDataInfoOnDatabase(user: User): Task<Void> {
        return databaseRef.child("users").child(user.id).setValue(user)
    }

    override suspend fun getCurrentUserData(id: String): User {
        TODO("Not yet implemented")
    }

    override suspend fun getAllUsers(): List<User> {
        TODO("Not yet implemented")
    }
}

⭐ Liskov Substitution

If you have a class of one type, and any subclasses of that class, you should be able to represent the base class usage with the subclass, without breaking the app.

  • We do that here when we inject RepositoryImp() from RepositoryImp (Child) 👶 Type whith provideMainRepository function which is return type of it Repository(Parent):man:.
    @Singleton
    @Provides
    fun provideMainRepository(
        database: Database 
    ): Repository = RepositoryImp(database) //function return type is Repository 'Parent' and this able to return RepositoryImp instead  
  • Now the parent class(Repository) 👨 is replaceable by their subclasses (RepositoryImp) 👶👶 and that without altering the behavior so that again

⭐ Interface Segregation

  • It’s better to have many smaller interfaces than a large one, to prevent the class from implementing the methods that it actually doesn’t need.
  • Don't force him 💪 to implement it 😂
  • Note we can do that by making a default body for this method in Kotlin like this:
interface RepositoryAuth {
     fun notImportantForAll(){}
}

⭐ Dependency Inversion

Components should depend on abstractions rather than concrete implementations. Also higher level modules shouldn’t depend on lower level modules.

  • See This example :
interface Database {
    suspend fun setUserDataInfoOnDatabase(user: User): Task<Void>
    suspend fun getCurrentUserData(id: String): User
    suspend fun getAllUsers(): List<User>
    suspend fun getAllPosts(): List<Post>
}

class DatabaseFromFirebase @Inject constructor(
    private var databaseRef: DatabaseReference,
    ) : Database {

    override suspend fun setUserDataInfoOnDatabase(user: User): Task<Void> {
        return databaseRef.child("users").child(user.id).setValue(user)
    }

    override suspend fun getCurrentUserData(id: String): User {
        TODO("Not yet implemented")

    }

    override suspend fun getAllUsers(): List<User> {
        TODO("Not yet implemented")
    }

    override suspend fun getAllPosts(): List<Post> {
        return databaseRef.child(Constants.POSTS).get().await()
            .children.map {
                it.getValue(Post::class.java)!!
            }
    }
}


class DatabaseFromCustomApi : Database {

    override suspend fun setUserDataInfoOnDatabase(user: User): Task<Void> {
        TODO("Not yet implemented")
    }
    override suspend fun getCurrentUserData(id: String): User {
        TODO("Not yet implemented")
    }
    override suspend fun getAllUsers(): List<User> {
        TODO("Not yet implemented")
    }

    override suspend fun getAllPosts(): List<Post> {
        TODO("Not yet implemented")
    }

}
  • Now We can depended on abstractions (Database interface) and not on concretions (like Firebase or Custom Api) by this way. The Datebase interface now is a replaceable with its childern classes and we will make our reposiory class take Database interface as argument like this: ❤️
class RepositoryImp @Inject constructor(
    private var database: Database                      //abstractions (firebase or your custom api)
   // private var refDatabase: DatabaseReference       // concretions (just for firebase)
) : Repository {
    
    override fun getUser(): User {
        TODO("Not yet implemented")
    }
    
    override suspend fun getPosts(): List<Post> = database.getAllPosts()
    
}
  • ❤️ Now it's to easy if we want to convert from firebase to custom api and vice versa because our repository don't now what's firebase or what's api, Because it's take atractions not concretions .

social-media's People

Contributors

kareemaboelatta avatar

Stargazers

Noor Serry avatar  avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.