TOA Part 4: Working With UseCases

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
all right welcome back i'm excited to uh get started pick up a little bit where we got left off last week um let's uh let's talk about what that is let's move over to this other screen here so last week um i actually don't have the preview running let me run that preview last week we set up the design system for the app and then we took some extra time that we had to run or to set up like our login ui um so this was we'll see this preview come up in a second we basically built a screen uh that i had designed figma that's supposed to be like a login landing page that has like um some inputs enter like a username and password and log in i kind of thought after the fact about how i didn't love this because in thinking further along in the app i'm not really sure if i want it to be like username and password login or we wanted to add like a sign in with google or maybe either one um i actually think email and password makes more sense for this but i digress i think that we'll change up a couple of the phrasing in here um but that's fine we could totally do that but what we'll do today is we will basically try to build out the stuff that powers the screen and if we have time we might do some more ey stuff because there's a little more that i want to do to this screen but we've got our little low-tech checklist there in the bottom left to go over everything we're going to do so one thing i really want to do with this project even though i feel like i wing it every stream is i want to make sure that we're kind of good about like documentation and planning for each step that we try to do so i actually think it would be cool to sort of build out like an architecture diagram of how this screen is going to work and then we'll go through and kind of build a few things we need we'll need a login repository which will simulate like actually being able to log into the application right we'll have like our login use case if you're not familiar with use cases i'll talk through that when we get to it um that's something i don't do a lot but i really want to explore for this project i find it interesting um and then we'll build out like the login view model and then hopefully by the end of the stream we'll have a working login screen uh probably what we'll do is have it accept like we could do some error handling if we have time like no empty inputs but uh let's just say like for today we'll accept like any username and password will be valid to log in and we'll just make some sort of like dummy service that passes it all through but that's the rough idea um let me know if you have any questions uh but if not i think what we'll start with is sort of building out like the diagram um so i made like an empty space here on uh miro if you're unfamiliar with miro it's like an app for uh whiteboarding um but we can use this to kind of talk through the architecture and actually i realize you can share these so i think what i'm gonna do is i want this to be like a living document of all of the pieces in the app and how they come together are you going to build a dummy service or just return dummy data from the repo i'm not really sure that the differences in your mind those sound like the same thing to me just said different weights um i want to make like a legitimate login repo that says like i don't know like given an email and password like i don't know if we would want to return like a boolean or technically i think in a um yes or okay um then the latter i'm just going to create like something that returns dummy data i'm not going to make a server without logic um what i'm thinking of in short is like we'll make an interface called login repository and then we'll make a class called dummy login repository and the dummy login repository is just going to return true uh that's what i'm thinking we'll do for this sample but we'll have the interface set up so that one day if and when hopefully a win we want to have like a back end for this we just swap out that implementation but the rest of this structure as it exists should still work um if that makes sense that's what i think we'll go for um so i i have a thing on the bottom about use cases and maybe it makes a little more sense to talk about this first um because that's something that i don't do a lot but i think is interesting but let's let's get through what we know we're going to have first so the way this is going to be structured is like we're going to have ah and let's can i make this so it always fills it in let's be white so we're gonna have like our login screen okay this is our ui layer uh so this will be uh like just our ui stuff now if you are interested you can all actually do um exclamation point new vid and see um a youtube video i did recently comparing mvvm and mvi and actually for this short segment here i'm going to try to avoid the buzzwords well let's just talk about like the components we're going to need and how i think they should connect together so there's two things we need from the start which i could talk about without a lot of explanation is like we'll have our login screen and then we'll have our login view model and what this is going to do is let's see this is going to expose our login view state which we actually made in the previous stream uh which let me show you what that looks like real quick our login view state is like what is the current username and what is the password and actually what we would want to add is we would want to be like you know um when the user is logging in maybe we want to show progress right so we can have like a show progress boolean here um and you know we could add more to this you know maybe we want to disable the buttons while you're logging in uh we can add more to this view state later but that's what this is our view model is going to tell our screen uh rogue assassin thank you for the subscription um those of you who saw the intro video i actually got a great idea okay matt had a great idea that we should make the sub alert the wednesday sound but i didn't have time to do that today but maybe soon okay but our login view model is going to expose a login view state now we also need to talk about a connection that goes the other way which is from can i okay from the screen to the view model which this will be you know ui events so one way to think about this could be like um you know text changed button clicked these are things that the login screen will need to communicate to the view model and all we're going to do is say hey this happened and we're going to let the view model decide what to do with that information so that's the ah recap wild dog welcome to the street we're actually not that far in what we're doing now is we're talking about the login screen that we built last week this is all the ui stuff that we did and today we're going to do the work to actually like power this login screen and make it functional and we're starting off by sort of drawing a diagram of all the pieces involved and making this screen functional um and once we understand everything we need to make and how they're connected uh we can go ahead and start building those so that's actually uh where we're at so far um and i was just explaining we'll have like our login screen which is the ui we'll have our login view model and all these two things all these things do for each other is um the view model exposes like a view state i don't know how well y'all can see this or if i need to zoom in um that is much better uh i'll be and i'll have to move around a little bit the view model exposes a view state this will probably use like a state flow and then the screen will update the view model whenever there's some sort of ui event like text changes button clicks so now this actually gets into a thing that uh i'm not really sure how i want to handle um so let's let's talk about it so what i typically do is um i'll make another piece over here let's call this login repository and um just for clarity like what this is gonna do is we're gonna have like a function inside of here um that would be like login email password and then this could like for simplicity's sake let's say it returns like a boolean and you can't see this very well how do i want to do this let's make this wider center this okay i want this to be inside the box but i don't think i can do that i have okay but this is what our login repository does remove the fun no we're going to have fun here we're going to keep it um and so what i would typically do in my hex is we can add a connection here between the viewmodel and the repository okay and then we can say you know we call login with that email and password um nope where did i know that you have it i did this the other day how do i rotate this that's not what i want there we go that's what it is um this is what i would typically do and then we could say this is done but there's an interesting topic that comes up on android sometimes that i see other people use which is the idea of use cases and a use case is like another layer between say your view model and the repository and i think the overall argument is like this repository is going to have specific information about how you log in right but all the viewmodel cares about is okay i have these pieces of information and i need this back and one could argue that's what a repository does as an interface but some people say you need use cases let me find a really good post on this i'll drop this in chat but i read this one a while ago about why you need use cases and let's talk about it before we get started i'm building our own stuff so let's skip this diagram at the top real quick because it doesn't really have the same thing but these are the same questions i had when i get started it's like you know what are you supposed to do and then this idea why can't i directly call the repository from the presenter or the view model and you know isn't this overkill if you just have that and so that's kind of my thought going into this but this article tries to explain why you would do that and one of them being kind of in principle like you want the separation of concerns and i think they make an argument that um you don't really have that if you're going straight from your view model to your repository and let me see if i can find where they explain that um where is that um all over your head yeah um i'm trying to find an example about why they do this and i can't well one example or one idea that i thought was really good is this helps avoid like god classes so one example being let's say you have some code in your view model that interacts with two different repositories um now you've got two parameters on your view model and then your view model is going to be doing stuff that is like interacting with two repositories when really you only wanted to do one thing right so i think they clarify let me find the use case so they change it to just get user transactions use case which means it needs to know nothing about how transactions are found you know aka do this that come from a repository or whatever else but this is just a thing that needs to be happened we need to get to user transactions um so it's really just another layer uh like cp says it it makes logic a little more clear this way uh but it will feel like overkill uh for certain scenarios but i'm kind of interested in trying it out tonight and we'll see it we'll see how it goes um but let me talk about oh they talk about you know doing it anyways for consistency for protection from future changes um which is good something to keep in mind um oh this is also kind of what cp said in different words is it's got like quote-unquote the screaming architecture and that like this is very explicit about what's happening arguably a lot more explicit than just having it talk to the repository what i don't like about it is that typically we see use cases defined as like interfaces so that we can mock them well in our tests testing is another thing that helps you know if i if i don't have use cases i have to mock my entire login repository but if i switch that into like just a use case then i only have to modify my use case uh for a test but um yeah one thing i don't like is that they're typically interfaces um so that means you have like an interface and an implementation for every use case and i don't really know what's a good naming convention because i hate this i hate the impul connection um doing like impl for implementation but like i said i think we'll try it tonight and we'll see how it goes um so with that let's pull up our login repository even further let's get rid of this arrow let's pull that away for a second and let's just throw in another layer here that we're going to call okay we're going to call this login use case and effectively what this will do is this will pass information from there which then goes into here and so we'll just have this nice little layer but it will help us scale up if anything changes about you know logging in so this is the sort of flow that we're gonna go for today um ah trashcan is back with another cube solved this is the flow that we're gonna go towards today and then once i crank out this rubik's cube uh we will actually start building up those screens so let's do that real quick hi trashcan i hope you're doing well traffic did you see the uh the new pittsburgh knights decals that are coming out next week among other esports teams um i really hate like that i don't have enough light in this room to really see the colors well but we'll see how this goes oh and unrelated but for the other android folks who are in here um who are familiar with the kotlin programming language i learned that the official scrambler used by the world cube association is written in kotlin um i can like pull it up after i do this but i thought that was fascinating um all right let's see let's see what we can do here we've been staying under 30 seconds so i'm hoping i can stick to that once more uh no idea let's find out wait no oh no this is not going to be under 30 seconds i don't think oh no my my light is messing me up oh no this one was bad this one was bad my lighting screwed me up oh that was real bad my lighting like i messed up a couple colors because it looks really light on the screen but oh my my look ahead is pretty good but like so i looked well lit on the screen because like i have a ring light around the webcam and the screen is white but all of my lights are actually off in this room so i'm kind of like holding this under the webcam and red and orange look really similar uh to the end of this light uh let's see if i can do that again redeem an actual 30 second one for trash can maybe that should be my maybe i should clarify that thing but like i'll do it until i'm under 30 seconds i feel like 30 seconds is a good a good sign um okay let's see if we can do this again oh no oh wait sorry sorry those don't count all right there we go what is that what makes you think i have twenty dollars oh thank you for the bits trashcan i appreciate it i also i messed up an algorithm in there i could have shaved off like two seconds i'm upset but alas we'll get another one in soon all right so let's go back so i'm gonna um let me share this link with y'all in chat if you're curious but i'll probably put this in the repo somewhere and try to make this sort of a living thing as i uh navigate other screens and maybe we can simplify this um because because this pattern is something that will probably continue throughout every screen we work on um so maybe we don't need it maybe this can just be a sample of what the architecture will look like in the app oh my god you can if you want to i'll always stop but anyways i will keep going until someone redeems it but i have no problem switching gears twice we can go ahead and check off the arc diagram and if there's no objections from the android folks about um this sort of pattern let's dive in and you'll notice i planned on it and that the checklist is kind of in order of the way we would build things um if my use case is supposed to talk to the repo i need to build the repo first and then so on and so i can't build my viewmodel until i have that and then i can't connect these until the end so it's kind of built in order um so let's get started one thing we need actually is um i wonder so we had a login screen um issue i called it a landing page but we closed this last week because we built the ui for it to start building from the use case uh we could i guess technically i just wouldn't be able to build the use case implementation but i could build the interface and then i guess instead of having a dummy login repository i could just have like a dummy use case and you'd be doing that okay so you would do like use case view model repository or like just start with the use case and then go from there you um build the info and have a repo interfacing okay i see we could try it that way um hang out and you can help me uh oh good questions in here um wild dogger use cases facade pattern implementation to avoid injection of multiple repositories um yes in certain scenarios like um let me post the i don't know if i actually posted the link in chat for this uh blog post we were looking at but um it doesn't have to be that way but yes that was one example from this blog post um is the idea of you know avoiding injecting multiple dependencies and really just being able to focus on the use case that you need so that's one way to look at it even though in our case that we're about to build that's not going to be true i don't think um but it could be one day so let's throw this back in progress uh we won't close this until we finish out all of what we're doing uh so let's let's get started let's make a new branch uh we're gonna call this toa7 we'll do log in use case it's too late tim we're adding use cases for the sake of adding use cases um that's what i want to do because one thing i do like and this is kind of where i was on the fence is like i think consistency is important um but yeah so one other thing i took away from this post is sort of how they structured it so i noticed that they would put like um i think they do it a little differently but they put like a domain folder and then they put the information inside of there and then the use case inside of that i'm not sure how i feel about this folder structure it's something that we can think about you know like uh i have a at the root i have a ui folder and i have login inside of here one could argue that that shouldn't be the case that login should be its own folder and then i could have like a subset which is like login ui um what do you think chad do you like that better if my like root packages are like um at a feature level and then we split up the responsibilities within that or at the top level should we just have a minimal amount of folders and then we split out features inside of that i don't know if i can explain what i mean packaging per feature all right we could try that out dynamic features maybe one day i'm not gonna go down that rabbit hole for today um but okay so let's make a new package here let's call it login ui and we'll take our files from last week and then we'll throw that in there wait for everything to refactor and delete this one and we can probably clean this up but let's let's do that later um okay and then we'll make a new package inside of here let's do domain.use case use cases use case is fine um and let's make it so this will be an interface login use case so there's a couple all right so we got to think a little bit more specific about how um this is all going to work well the first thing is we know we're going to want a spending function called login it's going to take an email and a password i should actually to avoid confusion before i go down the line replace everywhere that i have username with email because i like that better so let me do that so i don't get confused elsewhere if you all don't mind i'm gonna do that real quick going to change that to email we're going to change this to an email changed um we're gonna change this to email um oops we're gonna change that and we're going to change this to email input okay we replaced everything uh i'm not going to rerun the emulator right now but that's fine so one thing i got to think about is what should the return type of this function be now i guess one could argue it kind of depends on like what's gonna happen next some people might make a login repository that say returns an authentication token because that could be something you care about um or maybe it returns account information one way we could sort of future proof that is we could make like a domain model called login response and then have that like give us whatever information we need um i kind of like that idea because then if something changes about logging in i just change my login response model um let's let's go down that rabbit hole and let's see let's start there where are you going to do it uh that is a good question what i do now is i have like a separate sort of component that i call a user provider and when the login completes i take the user provider and then i store that authentication token um and maybe that's what we'll want to do but i think we're kind of getting a little further than i want to for this particular stream i kind of want to just be able to power the login screen so i'm actually leaning towards let's make a class called login result let's say that it can have or login response let's say it could have an auth token but we won't do anything with it yet let's define this so this is the response or what do we want to call it this is the data class uh this is the information we want we expect to be returned from any successful let's close this emulator tab sorry we're not using that right now successful login request so and then param auth token we could say this is a unique token that will allow us to authenticate future requests inside the application this is something we know we will want eventually so let's roll with it let's call it that for net so our use case will want to return a login response but now this gets even trickier is value classes to avoid actually mixing up the email params for example um i've thought about it uh not sure if we want to use it here um we could encapsulate these into like a login request um if you like that let's try it let's see i'm down to try new things and we can always sort of revert um i don't think yeah i think that that when i will take i will do that if a function gets too many parameters like if this were requesting like five different things then i would put that into like a single param and then throw that a data class uh here i didn't think about it but um i kind of like it because it kind of again hints at i guess you're not really abstracting it away but if i want to say you know i need email password and something else then i'm set and i don't have to i will still have cascading changes and that everywhere that i use a login request i would need to modify it but i wouldn't have all these cascading method changes necessarily so i could see benefit to it um oh oh i thought you meant okay i thought you meant doing something like this i thought you were saying like login requests throwing this in here and then being like login request um i thought that's what you were describing um i hadn't thought about it let me take a quick look at uh the documentation for that because i haven't uh looked at that in a while they're called value classes is that the official name um or oh it's still inline classes of the documentation okay you know what i have seen this oh inline is deprecated but the title of the page is still inline classes make it make sense okay so there's an example here of using this so hmm what is okay so really this tim like if i do if i do this um is this not oh without so if i do this like what what's the benefit what am i getting out of this um is it like if i want to change it away from a string in the future i change it here um is it got it because they have to create an email class they can't just pass a string interesting okay i guess okay then i guess i thought we would fix that if we made like a login request thing but then we just have the same problem in a different spot interesting um i'm not against it uh you know i i guess i just hesitated because personally i've never used this but i could see a benefit of it um let's do it um i don't know if i'm gonna do this everywhere in the app that i consume like strings but uh i suppose for logging in it's an area where we might want that certainty okay um let's try it out let's roll with it if i hate it later i'll remove it but i don't think i will but now we're getting into yet another concern i have about um this flow which is thinking about error handling so let's say you know this i would expect this is the format of data i expect when i have a successful login but then there's a question of well logins can be unsuccessful either invalid credentials or like a networking error like i can't log in if i don't have internet and so then we also start to wonder well how do i how do i handle that who's responsible for that and something i like to do and what we actually did on the study guide app if you all remember is we had this sealed class in here called data response that was something to encapsulate both a success state and an error state so this had a generic type i want a data response of something and i'm either going to get success or i'm going to get failure but the nice thing is i can then just return data response everywhere that i go um so i don't know if this i actually think this is a common paradigm that a lot of apps use so i think that i'm going to continue to use that here so let's now i'm rethinking the package structure here here's what i'm going to do i'm going to make a package called core i'm going to make a package inside here called data and that's where i'm going to put that file i'm going to put that inside like our core data package because this is something that will affect the data layer all around the application and we can add a little more documentation here which is um i say uh you know what maybe i won't i think this is relatively self-documenting documenting so we're going to leave that but then also what i want to do after i talked about the refactoring so i want to put this ui package inside the core package how do i do that um i don't want to put it here move package to another package ha and then i can just do core refactoring that will change up a lot of stuff now we've got our ui components that's kind of weird that we have core ui core ignore it we'll clean that up later but let's let's keep focusing on login so we've got our login response we've got our login use case now this can return a data response for a login response this is a little interesting convention here but i like it and now that we've got it like i said i do want to keep up with documentation in this app so we're gonna try to document everything as we go but sometimes i gotta like work out all the thoughts and actually get it down before we can document it so uh this function consumes a user's email and password uh that's a good question let me think about that um let me think about that for a second and tries to log them in um return a data response that contains a login response if successful or an error if not um is this a response or a result because the use case doesn't know if a request is happening um well request is ambiguous here right request doesn't need to be you're right like so kotlin has a result class um that is the same idea uh i don't like it because there's some weirdness about it and that like um it doesn't provide you like um type safety in the same way so you see how this has like get or null so like if i check if it's successful and then i want to say okay it is successful so i expect to have a value um i can't do that and so then i end up having to like force unwrap it or something so that's why you still see people writing their own wrapper around it um but i suppose we could meet in the middle and we could change this to like data result um and they're like okay that's a little more clear like this is the result of some data request um but to see peace point like you know request is ambiguous like sure the use case doesn't know that a network request is being made but the use case knows that it's requesting to log in right like that's one other way of phrasing it so i think a response makes sense um but result also makes sense because i guess i'm not expecting a uh oh my god y'all are coming at me for all of my naming okay um this is all valid though uh outcome yeah i that's that's valid outcome is valid um and like on one hand i would love to use the built-in result class like i said this is what i don't like um because i can't like just name it result yeah all right that's fair why am i over complicating it i just have to make sure i watch my imports uh later on when i do this but that's fine okay but now let's talk about login response then so okay so let's think about login so what does my use case need to know so let's let's talk hypothetically i have a real service that returns a um words that returns an authentication token so if i do this what i would probably want to do is take that authentication token store it somewhere retrieve it later the use case should do that that's what we talked about earlier if we have multiple services the use case would just call them back um but so that but then the question could become well what does the use case actually need to return to the view model right um and i guess the view model all it's gonna need to know is i guess was it successful or not did we log in or did we not um that is a good question i typically would do validation i typically do it right inside the view model but um no but that's well belonging and i guess okay i think i i misunderstood validation in terms of like is it like a valid email and password like that i think makes sense inside the um this layer something that i would do is like i guess maybe not i'm thinking of like well what if they try to submit that's empty to me i typically do that check right in the view model i'll have like a private function called validate um but actually maybe what we should do is we could have a validate input use case that tells you if your input for logging in is valid or not um and then maybe return you know error messages if not or something um maybe that's another way of thinking about use cases but i'm actually thinking about this login one again and i'm thinking of what does it really need to return and doesn't need to return this oh see look this already reflected i don't want to copy that result here um yeah i want let's see a result um or could this really simply just return a boolean i guess it depends on whether or not this does validation but if we assume that this does not do validation it's probably fine for it to return a boolean because i just need to know if it logged in or not um i guess no it's more than that because if they don't log in i want to know why so now i'm back to wanting this result class because if it doesn't log in i can get the error message so okay i think this is good but then i think the only other question is well what do we actually want to call this login response um like do we want a login response or do we want like a login result um i've got so many different ideas now because um but it's a sealed class yeah that was another idea right so we could have like field class login result this could be like you know success this will have an auth token um but then we could also be like a little more then we could have like you know something specific like invalid credentials could be a login result um and then we could have like a fallback um which is like an error message this is one way of thinking about it um what do we think about this instead um we like it okay let's roll with it so let's just copy that down here to success um so the reason i didn't go with an exception is because i'm kind of thinking of like um if i have a networking error if i get like a 400 or something like i don't want to bubble up like the retrofit throwable but i could map it to my own throwable i guess possible results for an attempt to log login to user uh another thing to think about is like um how this comes into play with the ui layer which is um you know this doesn't have any information to it which means when the ui sees this it's going to need to look up what error message to display but then here i was implying that the error message is going to come from somewhere else and now i've got that classic weirdness of like i might get a string i might want to look up a string resource what do i do um so maybe like a simplified solution uh could just be to make like this another object and say if the ui sees this it shows a default error message and then maybe that for the intent of a login result i don't really care about the details i just want to know did it work or not if you can tell me why it didn't work that'd be great um but if not no worries classic um so we can say this will be returned if there was no account matching the requested credentials and then this will be returned for any unknown exceptions when attempting to log in let's start with this we might change it but i think this is uh a good way to start this one ah more good ideas should invalid credentials be nested in failure you could do that um one benefit to that would be oh my god you're all on the same you're all on the same wavelength i love it um all right i'm gonna let we're we're gonna do chat driven development um i'm also learning a lot about how other people do things that are not how i do them so we'll throw this in here this will be a failure um an unsuccessful yeah i think here the only things i would think about are like a scenario i would care about is say invalid credentials um otherwise i don't care but now if i call failure if i put failure at the root then what do we put here for do we want to call like unknown um all right i thought that was silly but now i typed it i don't hate it um generic t um i'm kidding i'm kidding let's go with unknown i think that's like super clear that's it's an unknown failure um okay we got a lot going on here but we did it so now we can forget our custom result class from earlier for now um and instead we'll log in with an email and password and we'll get a login result so as much as y'all ganged up on me i think that we got to a good place this is what a use case should be um a login result uh providing the hazard hi thank you for the follow you're right success would not even need the token um logan result um providing information and explaining whether or not the attempt to log in is successful here's rogue assassin but does an unknown failure imply a failure even when there is none no it implies that it failed and i just don't know why but it's a way of specifying a it's a way of specifying you know there was a failure but it could have failed for any reason that i don't really care about but i do care about invalid credentials because i might want to do something specific to that um specifically i can see at a ui layer i might show a different error message for invalid credentials than i would for a generic network exception and again we don't know that this means network exception but in practice that's what it's going to be so maybe that's one way to think about it but the idea is we're extracting away the idea that this is a network exception but in practice that's what is likely to bubble up to here so this an enum is valid uh i'm just kind of sealed classes are kind of kotlin and that's how i started but an enum is totally valid especially because none of these these are all objects none of them have detailed information this is effectively just another email but we've got our use case that contains this information okay we've got email password login result we really narrowed that down can't believe it took us an hour um let's throw in some more documentation really quick here actually maybe we don't need to this is kind of self-documenting um um so actually i thought about that the reason i didn't uh what cp said about properties to specify where the error happened the reason i didn't is because let's throw on our like product hats for when this is a real thing you never want to tell the user which credential was wrong because someone who is trying to be malicious uh can use that to narrow down why they have your credentials wrong like if you admit like oh this email is valid but your password's wrong you've now like narrowed down which of the things they need to crack uh so companies don't like to do that we would just like to say there was an issue with your email or password but i think that's a good middle ground and that's helpful yes exactly what wild dog said and i think that's helpful because from a practical standpoint um you know i want to know and then i'm going to like click on my password and be like oh i typed it in wrong um so here's a documentation question for y'all um another thing about use cases is they should only have one method it should do one thing and the name should describe what it does so my first question being where do i put the documentation this documentation may make sense on the longing method because it allows me to reference like the parameters um aha you are cutting me off i was going to do the invoke thing next um but you cut you beat me to it um yeah so if we use the operator fund invoke it makes it easier to call the use case or it makes it a little more pretty um so let's do that invoke um but so here's the i guess one of the things is like um these little brackets these are a way of referencing the actual parameter so if i refactor this it will refactor the comment automatically this is super nice um but if i were to put this documentation on the interface instead i lose that connection um but i think that it could go either way and this is why i mentioned it should only have um you might have different implementations of the login use case yeah um so well so larry i don't think you should i think that two functions defeats the purpose of a use case i think it's intended to really um shine on that single responsibility principle and that like it does one thing maybe for simplicity well in an implementation you could have like private functions to split up you know responsibilities but the use case interface should just have one function this problem will resolve itself when you move to a single data class as a use case input so you're saying if i did make this one single input then it wouldn't be a big deal it could just go on here i mean i guess we can um just put it right on the interface uh we'll say this use case we can even make it vague consumes any information required to log in the user and attempts to do so and like cool then we could just like get rid of all this and that's all we really need to say um i suppose this is one way to do it which isn't terrible so okay so um what do we now you can remove the comma because it doesn't add anything i mean that's fair that's fair um i think especially with because y'all hammered me so hard on naming conventions i think you're right like i find this to be very self-documenting and i do say that if your comment doesn't add anything new then it shouldn't be there um so yeah yeah it's a balance right like it's it's i think this is good i think like the reason i want to document it on streams is because i want someone to be able to open up a random file and figure out what it does and i want them to not have to be an experienced developer like really experienced to know it um the green color uh you know what i mean like everyone watching this or at least the people participating in chat um you're gonna open this you're going to look at it and it's going to be super clear uh but someone else might be like what the heck is this um even though like there's only 20 lines here like it might just help to say like this is what it does um i don't think it's nothing should we add all similar use cases in one class uh no um like i think that yes it can feel like there's a lot of use cases but i think that that's a good thing and that you're splitting up responsibilities but you can you could have use cases that um depend on that on each other right like here's let's think about this let's let's briefly walk through an example of how you could have multiple use cases but still kind of combine the work so let's say we had another one that we called um store token use case or something because we know that like at one point we're going to get like an auth token right and we're gonna need to like store that somewhere in preferences so um yeah daca is really cool for doc uh adding stuff so let's say we have these right i have a use case for login i have this other use case for storing tokens i think it's entirely valid to be like you know we could have a login use case symbol that could consume another use case right and then when this one runs we could say you know log in and then store a token use case i did not make it a property that book so each individual whoops each individual task or use case is going to be its own interface but when it comes to the implementation layer i think it's totally fine to sort of combine these concepts you can have a use case that references another um if that makes sense hopefully that's you know one way to avoid it right registration could depend on login um you know or like if you depending on like how and when you want to record analytics within your application um you could have like some sort of analytics use case that goes into your other use cases and we'll probably do this now that i've said it out loud but uh we're not there yet so let's just um get rid of all that but this is all really good this was a really great conversation and i think that it's enough to mark the use case portion so let's commit that code real quick um let's split these up into a couple pis uh login implementation that's what we'll call this one this screen we um design the app architecture and build out the necessary components to power our login screen um september 29th and if they're into prs i'll put all the links in later but uh let's throw use case in its own pr real quick let's commit this adding login use case for number seven and then we will move on to the repository if there are no other thoughts on the use case work that we've done so far do we put it in one file that's a good question uh let's talk about that i'm kind of voting no but um we can talk about it because i don't really like the alternative but let me make this uh pull request real quick and then we can talk about that we'll do that next i should have actually let's oh god we have a failure um wait what is the matching declaration name oh i never renamed the file let's rename this file real quick um yeah we can actually make it part of this pull request um let's close the other tabs so should it be in the same file uh you could uh log in use case simple um we could put it in the same file i think like that makes sense but personally i don't like it because it just adds like more complexity to the file um and then i'm not really sure why i would but what happens if i want different um implementations of a use case you know then maybe i want them in their own file and that's something we could do for the sample app so uh one way we could avoid how i hate the impl naming convention is like for we want to build like just test cases for the sample app right now right so i could put like a success login use case i could create this class put it in a different file um and then when this one's invoked we could just say return login result.success and like we could leave it at that man this is a temporary class to create a mock implementation of login use case that is always successful and like we'll remove this by the end of the stream but um we could use it for now tim brings up a good suggestion um you know default thing instead of thing impul another one i would like to use uh a different word to default is like the word production like production login use case which also means that it implies the existence of a debug login use case um and i think that that's valid right um uh yes you were the only one um because i think that like what i don't like about it is it really sells the idea that um and i think when you've been programming long enough you'll learn to love interfaces but when you're learning programming like it just makes interfaces feel like overkill because this is a tedious convention which also implies that i only have one implementation of the interface and then it's questionable like if i only have one implementation of the interface why is it an interface in the first place and those of us who have been coding for years like we know that but that is not like helpful to new to new developers at least it wasn't for me i hated this for years and because they tell us to do that in the blogs yeah so we'll call this success log in this case for now and we'll leave it to show we put in a different file i don't actually know if i fixed the detect issues let's run this in the terminal we did not it's going to yell at me for unused private members um here uh how do i do i want to just suppress that for this pr or do i want to remove them for this pr you know what we will satisfy the static analysis oh and then it's just i can't i can't do anything because it needs a thing okay uh we're just going to suppress for this pr um because i don't want to remove this i want it to be rel it's relevant to the pull request i want it to be in the pull request okay that worked um pixel detect so after this we can set up the repository and actually this the repository is where our new result class is going to come into play um but we'll do that after we push this um and the login use case um as a layer of abstraction for logging in a user um enhancement that's what we'll call this one i think credentials login use case um we could but actually like i think that um uh let's talk about that while this is running so you're saying you're right so you're saying we'll rename this interface here let's do it because i would like to add um okay why the impul and not that so here's the problem here's the problem because the interface is ultimately what's defining that we need credentials so a login with google a login with google use case would actually be an entirely different interface because the invoke function would look differently um wouldn't it yeah um but so but so this interface needs a way yeah that's kind of what i'm thinking it would be a separate use case down the line because i need a use case that can consume credentials right but the parameters are different and if we're using the invoke function here then that's going to be a problem unless theoretically i wanted to be hacky and i made a google one that ignored the parameters of the invoke function um so i think like it could be a separate use case i'm loving this battle um okay but like here's okay so but see if you think about this if i change this to just be an invoke um interface um the view model calls this how does the view model how does the credentials use case get its information because remember the view model doesn't know it's a credentials use case so how does the credentials use case get its information oh we need another sealed class he wants to make a login type oh man so we're saying let's let's type it out i want to see it i want to see it let's let's see if i hate it so we're saying we could do sealed class login type we could have credentials which will have an email password and then uh because i don't know what information i would need but i'll know i'll need it in the future is i'm just gonna make it an object but we could have like google well the use case is meant to be a facade what come on you all not you guys do not come on this is let me catch up with all this this is contentious um so wild dog you're right but the suggestion is that the use case would be the use case would be the uh the wrapper around the thing um to create a single use case with two class providers this um i'm not sure what jimmy means is like the problem but um well okay but here's here's what it would look like right so let let me let me finish this thought let me finish this thought if you don't mind so i want to finish it all the way through and i don't have to commit this if we don't like it but i'm going to give i'm going to give this a fair shot for cp because i think he's onto something and i think i could see how it will work in the future so we create a login type it's a sealed class that is either credentials or google's we have our login use case it takes a login type whoop not a login thread exception i didn't know that was a thing and it gives us a login result here's what our implementations look like let me talk through it all before we get all of that so the first one we have a credentials login use case um this could be we could even like and then we can say you know if i guess one thing we could think about is like um we could think about some type safety here we could say if is credentials you know um or whoops if is loginpipe.credentials uh we return something okay we do something based on that um the implementation parameter can be can i do that no i can't do that here um but my point being let let me simplify my point so we have the credentials use case right we have the google login use case and then what we're saying is we could have like um our production login use case and then this can the suit this can consume credentials login use case and a google login use case and then here we basically have inside our invoke would have a when login type and then here we would do the switch you're right like the next thing we would need is generics here um then we make a two factor off use case and then we just throw it inside our production use case okay near this but call it by who which one do i pass under the view model right like if if if i don't want a single combining use case okay but then then we're way back to okay but then we're back to saying i thought we were trying to argue that we could have whoops i went way too far um we could have one single use case like you suggested as a user i want to log in but it sounds like we can't do that we need as a user i want to log in with credentials and another one that is you know we'll make another interface later that is like our you know google login use case that doesn't take anything or it will take something um and then the view model would depend on both of these but i thought we were trying to argue that we wouldn't need to do this i'm so confused this is one of the things that's hard to talk to chat um but i can only have one invoke function so there cannot be there cannot be multiple ways of logging in unless i add all those layers that i just had 30 seconds ago and now i feel like i'm being trolled i was so passionate about this oh my god um executive decision we will call it credentials log in use case because that's what it does and we are going to um we are going to continue with this and you know what i will i will please the gods by calling this success credentials login use case but we are going to keep it at that then we'll move on okay i don't know arguing with cp that's gonna be a commit message on that one what a night lively lively chat here i'm loving it i'm also out of water um might have to go no you're not stalling i i think you had like a genuine um thought process there and like maybe i'm just not seeing it i know you had me on twitter or linkedin or something and like if you want to talk separately like maybe i'm just not seeing it but um if and when when we get to the google login uh we can talk about it further but let's focus on credentials for today and i'm going to mark log in use case it's done
Info
Channel: Adam McNeilly
Views: 123
Rating: 5 out of 5
Keywords: Android
Id: F4WajzYPh9s
Channel Id: undefined
Length: 83min 10sec (4990 seconds)
Published: Sat Oct 02 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.