Powerful Android Apps CLEAN Refactor

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello there welcome back as most of you know the purpose of this video is going to be to give you a very high level description of what my most recent refactor to the uh to the open api android app has been so this app is i think it's it's two years old by now it's gone through a couple kind of major refactors uh the last refactor i did on video this refactor was like pretty much a rebuild of almost the whole app at least from the the uh the back end sort of layer like the the views the fragments the activities the view models all that stuff remained actually never mind not the view models the view model has changed also pretty much just the fragments the activities that the the ui kind of layer is the only thing that really hasn't changed basically everything from view model and backwards so view model uh what the repositories the data sources all that stuff has been now refactored and i rebuilt it and really really cleaned things up and we're going to kind of go through a very high level uh description of exactly what i did in this refactor so actually on the open api android app source code page on github i did kind of a little bit of a an um a read me description here of what the refactor actually was so i'll just quickly kind of walk through this and then i'm actually going to talk more specifically about what i did so the first thing is i migrated from dagger to hilt hilt is great hilt is no longer in alpha in beta it's uh you know it's fully released version hilt is awesome it makes dependency injection way easier especially on android because of the things that you get out of the box for the android architecture components view model so you can do like constructor injection super easily into a view model you don't have to do that what is it the map multi bindings thing anymore we can completely forget about that it makes testing easier too so it generates test components um basically just makes everything way easier on android so if you're using android an android view model or like an android architecture components view model hilt is what you should be using it's just way easier so anyway did the hilt update uh next here's updated to navigation or update navigation component so now recently within the last month or so navigation component now supports multiple backstacks so if you have that bottom navigation bottom navigation bar that you know most apps have now it will maintain a backstyle con backstack on each entry in the bottom navigation now that being said i did do a video about this i talked about kind of what i thought was great about it and what maybe it was missing a little bit so i will hopefully remember to put a link up in one of these corners i don't even remember which corner it goes up into and uh you can you can see my sort of quote unquote review of the multiple backstacks thing so check that out but basically it's super simple like you update the navigation component version we don't need that custom navigation controller thing that we were using before that would like save the uh the nav host for each entry on the backstack all that stuff is gone you literally just update the version and it will maintain multiple backstacks it's super easy next on my list here is decoupling so in the previous iteration of the open api app i was sharing view models in a lot of the screens so like i think for all of the auth stuff like uh login act or login fragment register fragment launcher fragment forgot password fragment all four of those fragments for example were saving the same view model the thing that was great about that was if you like you know typed something into the login field and then said oh whoops actually i want to register you went to the register fragment and then decided oh whoops actually i do want to log in it didn't really matter because those fields would be saved because they were all sharing a view model so obviously passing arguments back and forth between those fragments was super simple because they're sharing the same view model um there was also a couple other fragments that were doing that in in the in the source code that were sharing a view model and just made like passing arguments super simple i decided to get away from that away from sharing view models because when it came to testing it's just way simpler to to be able to test a fragment in isolation and not have to worry about you know the different state things that could be coming from different fragments there's a little bit more code involved obviously because you have you know if you have four fragments and they're all sharing the same view model that's you know they're sharing the same view models way less code but if you have uh you know four fragments each with their own view model obviously there's going to be more code there but the advantage is it's decoupled no matter that fragment can stand alone it doesn't care about the other fragments it's not getting any sort of state or arguments from the other fragments unless they're being passed as a bundle argument um which i'll probably talk more about that later but it's just it's a better in my opinion this is a better way to build it so i i got away from the sharing of view models now the rest of this stuff is i think i'm just actually here let's let's just talk about um these bottom two down here this number seven number eight number four five six and nine i'm going to talk about more in the video and i'll show you examples because if i just talk about it unless you know clean architecture and like how i build out clean architecture it's not going to make sense to you so i'll just talk about number seven and eight here and then we'll come back and talk about the other ones with examples so number seven is migrated from shared preferences to data store that's you know obvious that's the recommended way to kind of uh persist uh certain things across application launches so just a pretty simple straightforward uh migration to datastore datastore is also great because you can emit flows from it so like if you have whatever you have that's stored into datastore you can get it and it will get emitted as a flow so it has a suspend function so like if you have it in your use cases it will you know try and get that argument wait and then until it can proceed to the next line so that's great because obviously you know everybody should be using co-routines in my opinion everybody should be using suspend functions they're great and datastore uses them so awesome next is a migration from kotlin synthetics to viewbinding so this is pretty much strictly just because if you go to android studio and you run your app and you're using collin synthetics to you know find you don't have to use find you by id anymore basically that's what collin synthetics did it made you able to create like this reference to whatever id that view component had so they've been deprecated so i just you know did the migration to view binding which is what android studio will tell you to do you'll get a little warning down your bottom left-hand corner down where your little run thing is and it will tell you to migrate to view binding pretty straightforward it's not it's not complicated so those are the ones that i'm going to talk about at the beginning and now let's talk about uh number four number five number six and number nine uh and this this is pretty much the kind of complete refactoring of the whole back end of the architecture that i was talking about in the beginning of the video actually before we actually start talking about it i just want to say that if you don't know what clean architecture is if you've never used clean architecture on android you've never watched my clean architecture course you've never watched my kotlin multi-platform course which is also using clean architecture this stuff will be a little confusing to you because i'm going to you i'm going at a very high level here my goal is not to teach you clean architecture in this video it's just to tell you how i refactored the course or the the code so if you don't understand clean architecture you want to know more which i suggest you should understand clean architecture because if you want to get a job they probably expect you to understand clean architecture principles go watch my course on clean architecture go watch my course on column multi-platform if you don't have a mac it doesn't matter you can still build the entire android client for the kotlin multi-platform app which is like probably 80 to 90 of the course and you understand clean art you'll learn clean architecture in that too that's a better course honestly like if you're gonna if you're trying to choose like if you know you want to learn clean architecture you don't know if you want to take the clean architecture course or the kotlin multi-platform course take the caller multi-platform course it's a better course it uses jetpack compose it's great go check it out okay so let's take a look at an architecture diagram first of all so like i said the entire kind of back end of the architecture of the app is really the big kind of rebuild of this refactor so now we have this sort of structure we have like our domain models which is our core business models we have a data source sort of section where we have our different data sources which for us that's going to be the room persistence library for the caching retrofit for the network and then we have interactors and these are the use cases now if you don't know what use cases are i can probably i should probably explain that a little better for you okay so here i have the sort of auth level i guess uh architecture of the app we have like we have like auth activity here at the top and inside auth activity is launcher fragments forgot password fragment login fragments and register fragments this is the same structure as we had before the refactor so nothing should be kind of surprising here so launcher fragment has no view model forgot password fragments has forgot password view model that's this right here login fragment has login view model and register fragments has log log register view model now like i said earlier too when i was talking about the refactor i got rid of the sharing of view models so these four fragments used to share view models now they all have their own sort of view model so each one of these fragments is a little different forgot password fragment for example that accesses a web view so if you remember watching the open api course that uses a webview that actually accesses open api.xyz to forget to send a password reset link login fragment says login view model and here's where we're going to start talking about use cases so the use case that can be executed in login fragment is the login use case so that's this one right here and then the use case that can be executed in the register fragment or the register view model is the register view use case so now you have a question i'm sure and um that question is well what the hell is the use case because before what we had was we had our view models and then we just had kind of all of the logic inside of the view model or actually never mind it was the repository pattern so i had i had like an auth repository and then inside that auth repository there was like all of the things that could happen in that off view model so basically i guess you would think of a use case yeah as uh the functions that used to be in the repository so essentially you've kind of broken it apart before it used to be like you know one repository where it had all the functions that could happen in that auth sort of section of the app now each of those functions is broken apart so you essentially have a more isolated system that you can test and we'll talk more about those use cases okay so what is a use case what does it mean to be a use case what is this if you don't know what clean architecture is let's just talk you know quickly about what a use case is so essentially a use case let's start with this let's start with this a use case is something that executes a set of business logic so let's go business logic there's a set of business logic that the use case is responsible for executing so what uh what kind of things does a use case need to function correctly well in our case we have two things there's going to be a caching data source for our use cases and not every use case can have you know a caching data source uh and also a network data source that's the other one that i'm gonna draw over here a net oh that was really terrible writing let's just get rid of that so a network data source so use case has you know arguments what are those arguments it can be a network data source and also a caching data source and you could have multiple caching data sources you could have multiple network data sources the point of this is just they are arguments they're things that a use case gets its data from or sends data to so for us the caching data source is the room persistence library as i talked about the diagram the network data source is retrofit so that's the the the rest framework that i set up on open api dot xyz so now that you've seen kind of what the structure the high level structure is going to be like maybe let's just take a look at the code so right away when you open the project you'll see the the package structure is very different you have sort of the these three high-level packages business di for dependency injection and then presentation uh di is pretty obvious that's just like your dependency injection your dagger modules your hilt modules so i'm going to just pretend that doesn't exist for now because i think it's pretty obvious the other two are business and presentation so if you take a look at the diagram that i showed you earlier we have two kind of main separators in this clean architecture diagram business and framework so that's the two layers of separation we have here we have business and then framework which i just named presentation so inside presentation is all of the ui stuff so like in auth you have auth activity then all of the fragments that are associated with that auth activity so if i open up you know forgot password we have forgot password fragments we have the events that can happen in that in that screen we have the state for that screen and then we have the view model and each one of these has the same thing launchers is an exception because nothing happens there but login will have the same so login events login fragment login state login view model registers register events register fragment register state register view model i think you get the idea here so that's kind of the main uh the main setup for the ui stuff we have auth which is the same as we had before the refactor uh or the same kind of separation anyway then we have main which has main activity the account stuff which is then broken up into three more packages so those are these each one of these has their own you know events fragments state and view model again events fragments state and view model this pattern goes on and on through the code it's all the same it makes uh it makes testing these fragments super easy because they can they can exist in isolation they don't depend on anything else and then we have that kind of special case uh which is the session package so we have our you know session manager then we have session events and session state so if you recall from sort of before the refactor we had a session manager before but we didn't have session events in session state so i've sort of improved upon that essentially the session manager you can think of it as a application level view model that's pretty much what it is it's a singleton it exists as long as the app is alive it handles sort of what happens when you want to log in what happens when you want to log out all that stuff has to happen at the highest level possible because if a user is logged out they don't have access to the app um so it's you know pretty obvious that has to be at the top so yeah like i said the ui stuff like everything in presentation hasn't changed that much um other than you know cleaning things up and then obviously no more sharing of view models but pretty much pretty similar and then of course actually sorry i i did um create the a bunch of new classes like each each one of these fragments has events so this is something you wouldn't have seen before if you've never watched my clean architecture course or anything so each screen has a kotlin sealed class that defines uh what events can happen in that screen so forgot forgot password fragment for example can have like okay send a reset link what happens if there's an error what happens if you want to remove a message from the queue which we'll talk more about that uh maybe i'll go to another example let's go to like let's go to like the blog let's go to the blog list screen so what what can happen in the blog list screen well you can just go take a look at the blog events we can have a new search we can do pagination so go to the next page uh updating the query so like that's when somebody types in the search bar they update that search query i'm updating the filter so that means you know ascending or descending order filtering on the date filtering on the author that's you know updating the filter well actually i broke that up into two things so the filter is the or no the filter is like whether you want to filter on the author or the date and then order is ascending or descending and i i created these kind of utility classes for to package all that up nicely um get filter and order or get order in a filter that's accessing datastore fires off a use case i think you get the idea basically just the events that can happen in that screen and then the view model for that uh for that screen so let's go into blog view model it ca it uh captures all those events so it has this ontriggerevent function where you have those blog events being passed in and then it just checks for what event that is so if it's the new search event you execute the search function if it's the next page event you execute the next page function and so on and so on the the respective event calls a specific function so now what about use cases so as i said each viewmodel has use cases that it's it's uh capable of executing so these use cases are just classes i'll i'll show one to you in just a second and then those use cases are passed as arguments to the view model so the the only two that are actually use cases are search blogs and get order and filter so these are two use cases that are possible to be executed in the blog list screen so let's just go down to on trigger events so like for example the new search event is fired it would it would fire off the search function let's go down and look for that search function here it is here so what happens when the search function gets called well we want to reset the page number so set page whatever the page is to one because it's a brand new search we want to clear the current list of data and then we want to execute that use case and then we listen for the emissions from that use case so if we want to get the loading state like you know whether the progress bar shows or hides while that use case is being executed if there's data returned we get that data and then if there's an error we get the error pretty straightforward basically every view model every use case execution looks exactly like this it emits a flow so you just listen to the flow you get data state coming in you then set the data state based on what you get from that flow so let's uh let's go to the use case let's go to one example of a use case just so you can like take a look and see what this looks like and again if you have not watched my clean architecture course or you have never heard of clean architecture you're really just gonna this is gonna be very confusing to you so i really highly suggest that if you don't know you should go watch either my clean architecture course or even better my kmm course and again if you don't have a mac it doesn't matter you can still build the entire android client um basically the only thing that you won't be able to do is build that final mac ui which doesn't matter at all and yeah just you know it i take you through that course and i teach you clean architecture if you don't know it or watch the clean architecture course uh it's up to you but i think the kmm one is better if you do that and you come back and watch this video or look even just look at the code on git go to the open api app look at the code on git you'll have a huge aha moment you'll just look at the code and you'll very clearly see oh it's clean architecture i see here's the ui here's the data sources here's the use cases here's the view models i see every i understand everything that mitch did now perfect so you know i suggest doing that all right so here we have the search blogs use case so what happens here well when i build a use case i try to build them as similar as possible like i follow the same sort of pattern so they look generally the same they'll have a custom name so like this one's called search blogs but they all have a function called execute now the execute function differs from use case to use case with respect to their arguments but i like to call it execute every time just to keep things you know as similar as possible so what do i need for this search blog blogs use case well like i said in my you know earlier diagram where i showed you like what is a use case takes data sources so here's your network data source here's your caching data source and then the execute function also requires arguments so like we need the authentication token if we're gonna hit the network hit the api we need to know what the search query is we need to know what the page number is the filter so like ascending descending uh that kind of thing uh and then or sorry the filter is date updated or author the order is ascending or descending and then um we have a flow that's being emitted now i honestly can't remember if i had flows in the repository before the refactor i think i did when i did the flows and channels refactor um but again if you don't know if you don't understand what's happening here it's pretty simple you just have a flow so it's a call and flow that is going to be emitting uh some kind of state so i have data state that's wrapping around a specific data type so this is a search blog's use case so we're going to be getting a list of blogs from the api that's why it's returning a list of blogs it's wrapping around the data state first thing you do in every use case is you emit the loading state that tells the ui okay time to show the progress bar and then you execute the business logic for this use case so you can see a bunch of stuff is in here like the first thing we're checking here is if the auth token is null if it's null i want to throw an exception and what will happen when i throw an exception well if i scroll down there is a try catch block if there is an exception thrown it will then emit an error uh specific to that particular use case so you could have uh you know got the message from the use case like i could have gone you know e dot message or got the error from the the exception it was thrown but i just want to keep it simple and i just said anytime there's an exception thrown just say unable to update the cash you know it um actually now that i think about it that's the wrong that's the wrong exception that top level exception that is being thrown up here if the auth token is null is not actually part of that try catch it gets caught down here in this catch which we'll call this function handle use case exception which just emits an error so you can see here it's going to emit an error based on some response or right here the message from that that's uh that exception so take a look at that if you want to kind of dig deeper into that but essentially all you need to know here is inside this use case it's a set of logic specific to this particular thing that i'm trying to do and the particular thing that i'm trying to do here is just get some blog posts from the network so when you're getting blog posts from the network first thing is obviously get them try and get them from the network so that's what this is doing right here if i'm able to get them from the network i want to cache them so that they are being cached and if all of that is all good then i want to emit from the cache which is what's happening here so it's kind of three things you you know get get the blogs from the network insert or update the cache and then emit them from the cache once they've been uh inserted and that's that's one example of a use case you can see that there's multiple things happening in here you're handling exceptions you're looking for specific error cases you're getting network data you're inserting into the cache you're emitting from the cache it's all everything that needs to happen in that that use case that's that's what's beautiful about these and then they're very easy to unit test because you have a set of logic that you need to confirm happens basically and i also wrote unit tests in the in the refactor and we'll um let's go take a look at a unit test now so since we just looked at the search blog's use case let's uh let's look at the search blog's unit test so go down to the test package down here you can see there's data sources and there's interactors all of the actual unit tests are in interactors data source is just the sort of fakes or yeah the fake data sets basically because you know in a unit test you're obviously not actually hitting the network you're not actually hitting the cache so you build fake versions of those data sources when you're doing your unit test let's go take a look so go into the blog section here and if we go to search blogs test let's see what this looks like so there's six tests inside of this class there's three success cases and three failure cases so the success cases are retrieved uh 10 blog posts retrieve three blog posts and then retrieve an empty list so what you want to do is you want to just confirm that if the use case returns you know does it get 10 blog posts from the fake data source does it insert them into the fake cache and then does it emit them that's really the things that you're testing and then make sure that no exceptions are thrown then for this one same thing except with three and then this one is you want to test to make sure that you know in the event that an empty list is returned from the network that everything doesn't break you still like insert nothing into the cache because there's nothing got retrieved from the network um it emits nothing because nothing was retrieved that's kind of the things that you you look at then you have a bunch of failure cases so i don't want to talk about each one of these tests let's just go through one of them so let's look at the first success case you know retrieve 10 blog posts so scroll down and let's look at this one so i called it success 10 blogs so because i'm using retrofit i used mock web server to set up a fake sort of network data source mock web server is really great although there's also other uh third-party libraries that are just as good like if you're using ktor there's a camera what i was using i was using something the other day and it does pretty much exactly the same thing but anyway what it allows you to do is set up like a fake http response uh so i'm saying make sure that it's successful and then return this data when a request is made so what is this data this is just um the same the same data that would have been returned uh from a successful uh network operation if it hit the network so i'm just i'm returning like literally json data i don't know why it's not there we go so search blogs uh responses i here have here success 10 blogs and it's literally json data the exact same json data that would be returned from the api if there was a successful response um so yeah let's let's look at what hap what else happens here so this is kind of the setup stuff we get the auth token we want to first confirm that there are no blogs in the cache um because we're starting from blank slate here right we have a fake cache we have a fake network data source the first thing you want to do is check that the cache is empty because in this use case that we're executing we're going to get 10 from the cash we're going to insert them into the we're going to get 10 from the network sorry we're going to insert them into the cache then we're going to we want to emit them from the cache so in order to confirm that it's working correctly we have to confirm that the cache was empty to begin with because if we if we just check after we get it from the network and after we insert into the cache we don't know what was in the cache to begin with so we want to make sure that we have a good baseline we confirm the cache is empty now let's execute the use case and see if it does what it's supposed to so no no blogs in the cache great now let's let's execute that use case um so for that uh if you're testing a flow they have a couple of really handy functions that they have one of them is to list so what this will do is it will you execute the use case and you call two lists on it and it will break up all the flow emissions into a list so for example the first emission if we look at our use case and scroll up to the top here the first emission is going to be loading so that's what we check we say okay is that first emission loading and assert that that's true if that's true then we then we move on second we want to make sure that the blogs were inserted into the cache so if we look here we scroll down it's going to execute that network operation it's going to get that data and then it's going to insert into the cache so we want to confirm that that did happen so what we can do is just query the cache and confirm that the size is 10 because remember at the beginning before the use case was executed we confirmed that the cache is empty so if we know that if now there is 10 items in that cache we know that the use case got the data from the network and inserted into the cache the next thing is confirming that the emissions are correct so if we look at our use case the next thing that happens here is we get the 10 cached blogs from the cache and then we emit them to the view model so we can check that here so we're checking the second omission checking that the data size of that list is 10 because remember we got 10 from the network make sure that the data in that list that is not null so like the fields in those objects are not null and then we just confirm or start out the fields we confirm that the objects are not null and then we confirm that they're actually blog post objects so technically you could have done this like 10 times because there's 10 entries but i think one is fine like if one's a blog post they're all going to be blog posts so you just check one of them make sure it's a blog post that way you know okay the amount of data is cracked they're not null they're blog posts probably everything worked correctly and then the last thing is you want to check that the final emission uh is the loading state is now set to false so you can see that my exclamation mark there is checking that this is this is false and that's a that's a successful use case so there's the set of logic we're making sure it works correctly and that's uh that's a great unit test now the last thing i want to talk about i actually don't want to talk about it anymore because this video is already 30 minutes but or it's probably close to 30 minutes but we'll talk about it anyway because it's part of the refactor and i know that people are going to ask me about it um so if you watch the open api course back in the day or whenever you watched it you know that i used to have a i think it was a i called it a state message uh state message uh stack or something or messaging stack or something and if there was a an error that happened somewhere in the view model or the repository a message got added to that message stack and then the ui looked at that stack and that was how it knew to like show toast dialogue snack bars all that stuff so this this kind of a system is something that i'm always trying to refine i haven't seen the perfect implementation of this system ever i think it's a it's not an easy problem to solve like the problem of what happens when you have an error in a use case or an error an error somewhere it doesn't matter where it is view model use case uh ui doesn't matter what happens when an error occurs and you have to show something to the the user like a dialogue snack bar toast um or capture input all of these things i've i've i'm yet to see a perfect solution to this problem so my newest iteration of the solution to this problem i added to this this refactor now let's let's talk about that so first of all um i realized that the messaging stack naming that i was using specifically the stack naming is not very good so instead i created a queue so i just like the java cue like if you go to the oracle documentation you look up a queue i created a kotlin version of that so it has mostly the same functions you know like adding removing uh remove elements peak offer pull all that stuff everything that a cue should do if you don't know what a q is and you don't know the difference between a q and a stack a q and they're basically opposites of one another a queue is a first in first out data structure so if um say you have an error you add it to the queue so you have another error you add it to the queue the the head of the queue is the one that was first in that's why it's called a first in first out data structure so it makes much more sense um for uh this sort of showing an error in the ui mechanism because the first error that happens is the one that the user should the user should see um it doesn't make sense that if there's ten errors the user would see the the uh newest one first the user should see the oldest one first so a stack data structure is they would see the oldest one first which doesn't make sense so bad naming on my part even though the functionality was correct in the previous uh open api code but anyway so i've refactored that at created this queue and now now we have this queue this q data structure gets added to each state in each screen so if we go to like the blog view model for example the state variable right here holds everything that the blog the blog fragment needs to operate correctly that's what we have this mutable live data thing so if i click on blog state let's take a look and see what's in here so we have loading so that's like whether the progress bar should show the blog list the query page is the query exhausted filter order and then so all this stuff should be pretty obvious to you you should understand that but then we have this q thing down here so the queue is how i just described it it's a it's a queue and every time there's an error whether it's in the view model the use case whatever it gets added to that queue and then basically in the fragments it pretty much does exactly what it did before before the refactor if there's something in the queue the the ui will show the thing that's at the head of the queue so if three errors are thrown all three get added to the queue the ui is it's a it's a live it's part of the state so it's live data it's going to show up immediately um when when something's added to the queue the thing in the at the head of the queue the oldest thing uh gets shown so if it's a dialog it will show that dialog the dialog is only then removed from the queue when the user interacts with the dialog so like if an error dialog shows up in order to remove it from that queue the user has to either click ok cancel or off of the dialog it will then get removed from the queue if the user rotates the screen nothing happens the dialog still shows because it hasn't been removed from that queue so this is a pretty you know it's a pretty reasonably good system handles it checks all the boxes if an error happens the user sees it if the if a rotation occurs or they send it to the background and come back that error is still going to be there until they interact with it and then it gets removed from the queue so like i said this my system is not perfect i'm constantly trying to refine this i like i said i have not seen a perfect implementation of this mechanism yet because there's so many variables there's like you know you can have a toast snack bar you can have simply logging something so like if an error happens you don't always want to show it to the user maybe you'd want to send it to crashlytics uh dialogues uh what else is there notifications maybe sometimes you want to show a notification and each one of these uh things have different criteria like a dialog has a title a description button so it could have an okay button a cancel button also dialogues can capture input uh a snack bar has a description it can have a button uh a toast has just text notification can have everything so like there's a lot of there's a huge amount of flexibility with that and so i haven't seen i haven't seen like the perfect system like i said i think in the refactor i only i think i only handle dialogues like i don't think i have uh let me just look here ui component type yo no never mind i have toast dialogues and uh and an are you sure dialogue but you know easily more stuff could be added to that so um i don't want to talk more about it because it's it's just going to get into the weeds too much so if you want to take a look at the code go ahead um or like i said watch my clean architecture course watch my kmm course all right we're almost done ladies and gentlemen if you've stuck around for this long good job you're insane because i've probably been talking for at least 30 minutes for sure the last thing i just want to talk about is real quick i did some very minor updates to the server side responses so like the stuff that you get when you make requests to the rest framework of the api i just kind of cleaned things up a bit basically you don't need to know anything there's nothing no changes that matter to you you'll just get more meaningful responses when you you know have a failure on one of your use cases or one of your network operations um i could have honestly said nothing and you wouldn't have even known so but i thought i would mention it anyway all right boys and girls that's gonna be it for the video hopefully it was helpful i know this was a highly requested video at least from the people in my discord channel you guys really wanted to see kind of a high level overview at least of this refactor um i'm i'm assuming most of you have not watched the clean architecture course or haven't watched the kmm course because i think if you did it would be pretty obvious like if you if you watch those courses and you went to just look at the way i refactored it you would say oh i see he made it clean architecture great and you would just you would just understand so that's i guess what i would finish with is if you did not understand what i was talking about today i highly recommend watching those courses they're very good they're my best courses by far and if you're looking for a job in android or even if you're a solo developer like building things cleanly is going to save you time and pain having use cases that set that execute sets of business logic makes it more unit testable testing things in isolation decoupling all these things are just great to know and like i said any job that you go to if you show them these skills they're gonna like them trust me i know i've talked to the people these are the things that they look for actually before i go let's uh let's take a look at the app that i'm probably gonna be building my next course since you guys are crazy and you've stuck around this long why wouldn't you stick around for another two minutes and take a look so this isn't set in stone yet but i'm thinking of doing a multi-module sort of clean architecture course i mean these days i'm going to build everything with clean architecture so just assume it's going to be clean architecture at this point so yeah it's a multi-module that's really the the core thing here though so it's accessing a dota 2 api which is a computer game if you guys didn't know what that is and here it shows a list of the uh heroes so these are like the guys that you could be it's pretty simple like there's some filtering up here so if i uh and the filtering is in real time so like if i filter you can notice that the list is kind of filtering in real time if i click this top button up here there's some filter options so if i want to filter on hero z to a a to z also notice the the um the list is being updated in the background live as i'm clicking these things uh we can filter on the win rates and then the primary attribute of that hero so if i want to see strength heroes and i want to see the they're the ones with the best win rate at the top i would do that then there we go and i could remove this text and see uh kind of the best win rate heroes the top and the worst at the bottom um yeah so that's pretty much just this one screen and then then we have a detail screen so if i click here it tells you then the stats of these heroes basically just some information that you pull from the api there's going to be there's unit testing clean architecture mvi jetpack compose navigation component [Music] i think i said unit tests already yeah it's good it's good and and if uh if you think that you if you think that multi-module stuff looks easy it is relatively easy but the the thought process of how you plan out your modules is not simple and it's it's it's not obvious at all what the best way to structure your modules are like should you modulize by feature should you modulize by layer should you do some kind of a hybrid model should you um which is what we do which i'll talk more about in the course or what i'm going to do um so yeah i mean that information alone i think is probably the most valuable but if you're interested in that it's probably that's the probably the course that i'm going to be building next and i'm going to stop talking now because the video is probably 40 minutes i've had enough you've had enough let's get out of here don't forget your [Music] engagement
Info
Channel: CodingWithMitch
Views: 7,384
Rating: undefined out of 5
Keywords: open-api.xyz, powerful android apps with jetpack architecture, powerful android apps, codingwithmitch, codingwithmitch open api, open api codingwithmitch, android clean architecture, codingwithmitch kotlin, android hilt, codingwithmitch mvi, android mvi
Id: EvYLJza-i74
Channel Id: undefined
Length: 38min 44sec (2324 seconds)
Published: Mon Jul 26 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.