Tomorrow I have interview on kotlin android and today I am spent 8 hours onyour channel ❤❤😂😂
@OlegGolubev_yolo7 ай бұрын
gl hf
@ArthurKhazbs7 ай бұрын
Good luck!
@ZeeshanSyed-pq3gq7 ай бұрын
All the best Viraj
@bek_groider7 ай бұрын
gl
@robsonalvesdasilva80167 ай бұрын
GREAT!!! good luck!
@idrios7 ай бұрын
Man I appreciate your channel so much. It feels like Android development changes so much, so quickly but your tutorials are my go-to resource for keeping up with it, above even Google's own Android tutorials
For password verification, it is better to send a list of errors to show all the errors at once, rather than one after another.
@BitMavrick7 ай бұрын
Not gonna lie. Properly structured android app is quite hard. As a beginner, I am going through a lot of complexity. Thanks, Philipp, for making videos about such a topic.
@karolkulbaka85777 ай бұрын
Great overview of why do not use the google clean architecture
@geko10987 ай бұрын
This was my first introduction to use cases as code, and I think I got the concept from this video
@kolyakalyzhny7 ай бұрын
Hi, Philipp! Have you ever considered an idea of creating a video on using static types more extensively for enforcing business rules? For example, instead of using a validator use case which returns a boolean, we might, indeed, parse some input into a more structured data: like string to a valid email. Of course, parsing implies errors which should be enumerated by your type system, too. Consider algebraic data types like `Either`, `Validated` etc which are used in Haskell, Scala, Arrow.kt. The approach prevents many bugs at the compile time. I think popularizing such concepts would be of great benefit to the community. Here are some good resources: arrow-kt docs, Scott Wlaschin's talks, blog posts and his book "Domain Modeling made Functional", basic Scala, Haskell design patterns.
@DiegoNovati17 ай бұрын
To avoid the scenario number 3 I make the Domain module a Java library: there is no way to pass Android stuff or use Android libraries in the Domain layer, so it can just be only business logic. For the scenario number 4: all my use cases use loggers and analytics libraries (not directly but by repositories) so that for each use case I collect execution time and, in case of unexpected error, the parameters that created the error. For the scenario number 5: each use case returns an Either monad as result, the left value is the error (implemented as sealed interface) including the UnexpectedError when the data layer raised an unmanaged exception, and the right value is the successful result (NoResult or a Result class, it depends by the use case)
@bitwisedevs4697 ай бұрын
I think the formatting part can still be considered business logic as long as it is part of the business requirements? Usually such formatter can be function extension or inside utils. However I also put them in domain model since what I noticed usually is people not adding any logic in the domain model which makes it the so called anemic domain model as well as despite it is more like a UI logic I don’t want to do that formatting again for example in SwiftUI or UIKit with KMM. I think as long as that logic can also be done in platform independent approach then it is safe in the domain layer.
@PhilippLackner7 ай бұрын
Is something really domain logic if the only place where it makes sense to use it is presentation?
@bitwisedevs4697 ай бұрын
@@PhilippLackner it is still part of business requirements thus I think it is still okay to be in domain layer but no need to create use case for that as it will be too overkill. What I want from a domain model is having both formatted version and raw/original value of properties and as of now I see no problem or violation when doing that.
@Ayor887 ай бұрын
I guess you're a good teacher beacause I've watch many (if not all) of your previous videos and I made none of those 5 Use Case mistakes
@niknar2667 ай бұрын
One thing we're doing at my current project to get a little bit more out of usecases is let them be responsible for wrapping in kotlin Result like the last example to make sure errors are caught in the onFailure and appropriate error event are sent to the presentation later from the viewmodel I have a live template to save me the trouble of writing boilerplate for usecases too :)
@thelegend89907 ай бұрын
I trust you more than official Android docs. We wish to see more videos like you used to do where you apply all of architectural best practices in a mini project Thank you!
@ilpacolo7 ай бұрын
Amazing video !! i am working as Android dev and this is very helpful
@foivosstamopoulos97096 ай бұрын
Another great video. Thank you so much Philipp!!!
@PedroBarbosaRoman7 ай бұрын
I think there is also a space for using use cases containing platform specific libraries. I'm not a big fan of restricting use cases to only pure business logic, because sometimes a use case can do multiple things which depend on platform specific APIs, and so the use case should illustrate that intention through its name and parameters. If in a Multiplatform project we need a different use case from each platform we can then have an "expect" generic named use case (to use in common code) with "actual" implementation use cases that have their own dependencies on each platform.
@lindaporsius7 ай бұрын
Guilty, on all of the mistakes. But since I actually entered a mentorship-program with Philipp, I can at least recognize them and try to improve.
@Alchemist102417 ай бұрын
Please make a quick video about how to architect our platform related classes like work manager and services in the clean architecture approach.
@MrMindfullness5 ай бұрын
I am really excited to watch course material that I have enrolled for. But not sure where to find course I bought. Please help!
@germenwong7 ай бұрын
Hi Philip, thank you for bringing us how to use biometric technology in Android in the last video. I have really learned a lot, and if possible, I would like to see you introduce how to use speech recognition technology in Android
@زيد_اليماني7 ай бұрын
I watched the previous video about the best way to handle errors, and I then touched on the topic of the use case and how to make the view model responsible for displaying the message type to the user. When I glanced at the thumbnail of the clip, I thought there was another bug. 😂
@calixtoandrade9967 ай бұрын
excellent video Mr. Lackner Im totally agree with your point!
@santri.awon17 ай бұрын
recently i searching about usecase and you upload this video
@weslleycampos7 ай бұрын
I prefer use the operator fun invoke in the use cases.
@MajesticNut3 ай бұрын
What can you say about nested use cases?
@martinseal19877 ай бұрын
I think with your first example this is when you take clean code too far, there is no need for these to be in separate classes just making busy work
@PhilippLackner7 ай бұрын
Not necessarily, but then don't call it use case if you ask me :)
@martinseal19877 ай бұрын
@@PhilippLackner yh fair enough, I've never called anything a use case I don't like the concept
@lewi.steven7 ай бұрын
ValidateUserDataUseCase is not even use-case at the first place because use-case is system wide functionality of the application/software (just like when we define use-case in use-case diagram in UML). Do "ValidateUserData" is something that customer can do in the system ? "Login" and "Register" are. With that thought then Login and Register are the use-case class that can call Validator class to validate the request, or or you can have validation logic inside domain entity if you prefer rich domain model.
@martinseal19877 ай бұрын
So it seems "use case" is just a way to make programmers argue about nothing 🤔
@safionweb7 ай бұрын
Well explained.
@shadowpenguin34827 ай бұрын
2:20 the formatting implementation is also really strange. It would be much easier to have a single when expression here with some slight duplication, eg I found this one for file sizes (needs to be slightly adjusted from 1024 to 1000 though) fun fileSizeString(bytes: Double) = when { bytes >= 1 shl 30 -> "%.1f GiB".format(bytes / (1 shl 30)) bytes >= 1 shl 20 -> "%.1f MiB".format(bytes / (1 shl 20)) bytes >= 1 shl 10 -> "%.1f KiB".format(bytes / (1 shl 10)) else -> "$bytes B" }
@nitheeshks75822 ай бұрын
Can u tell how to handle with single line use cases..
@mohannadyoussef86837 ай бұрын
Amazing video as always
@george_sigalas7 ай бұрын
6:40 "The domain layer shouldn't contain any references to the data layer" that's where I get confused. Google says that the domain layer is responsible for encapsulating "business logic that is reused by multiple ViewModels" and in the docs it has examples where they use Repositories, which is clearly a data layer component. To me it feels like the domain layer exists solely for bridging the data layer with the rest of the app.
@calixtoandrade9967 ай бұрын
a repository is not from the data layer, is from the domain. The implementation of that repository is the data layer
@george_sigalas7 ай бұрын
@@calixtoandrade996 that clears up a lot actually. But why would the graph point to the data layer in the docs? That's so confusing.
@PhilippLackner7 ай бұрын
The android docs are indeed confusing regarding that. They're not really talking of domain in the sense of DDD (Domain driven design) The idea of this inwards pointing communication is that changes in the data layer don't cause changes in domain and presentation as everything just depends on domain and never data directly
@calixtoandrade9967 ай бұрын
What is intended to illustrate is that the domain layer is decoupled from the data layer (since they are two separate layers) and that it is from the Data layer where it obtains the information, so that, if in the future it is decided to change Retrofit for Ktor or some SDK for another, the only one harmed is the Data layer and not the domain, because the domain uses its own entities, abstractions of its repositories and other use cases. Therefore, the Data layer is responsible for mapping/providing the domain entities to the domain, so everything keeps working the same. I think part of the confusion is not differentiating the Data layer from the Data modules/libraries. They are two completely different things, a layer and a library or module. The domain will NEVER implement a data module/library, much less a UI module/library, because those modules depend on the framework. However, the Data and UI MODULES always consume the DOMAIN MODULES (again, the MODULES, not necessarily the LAYER). Of course, how else is Data modules supposed to map the remote/local models to the entities? or how is the viewModel supposed to work with the useCases? So, the architecture is one way because UI calls on domain to get the information (the use cases, not the data sources and much less the repositories implementations), and domain calls on data to get it, but the responsible for implementing the Data modules/libraries is the feature or the app itself. That way, the domain receives the implementation of its abstractions.
@wcman0077 ай бұрын
Lmao this is like the teacher snitching on common mistakes in the test 😭😭😭
@L4szcZ7 ай бұрын
In example 5 there is easier solution you can change class name from useCase to validator ;)
@mackomako7 ай бұрын
If you leave it in domain layer it's still wrong. Either you move it to presentation layer or you return Error without string and map it in presentation layer.
@L4szcZ7 ай бұрын
@@mackomako it wasn't in domain as far as I remember and validator shouldnt be in domain btw.
@Mackovitch7 ай бұрын
For usecase #2, one would argue that the formatting of number of followers could be business logic as it pertains to the core of the business features of the app. Also, heavy formatting (almost unlike here) could make the presentation logic convulated (so what would be the best place: in the view model (via a mapper) ? in the UI component directly?) but I do agree that this is for the purpose of the UI and the resulting formatting would find its place in a UI model.
@abada-s7 ай бұрын
12:28 sometimes creating this abstraction makes all user cases code style be the same but I think it is not the right way to unify the code style
@jimpauloovejera25997 ай бұрын
Question: Can we use try-catch inside a use case?
@SensesVI7 ай бұрын
I'd think you always should. This way you can catch exceptions and ensure you throw a domain exception instead
@calixtoandrade9967 ай бұрын
I do not recommend it, because a single use case would be doing two things: executing its function and also handling the error. Let the error arrive to your viewModel. The error is a UI problem, not a domain problem. What I do is simply add the @Trowhs tag to my use cases so that whoever is going to use it knows in advance that this exception can be thrown. It is the problem of the viewModel or whoever is going to use it how to handle the exception.
@calixtoandrade9967 ай бұрын
if you want to throw a domain exception because your service returned something null when it really didn't have to be, then throw your domain exception from there. For example, in remote response the user may be null. Your domain requires that it cannot be null, therefore, if it arrives null from the service, throw your domain exception, for example: return remoteUser ?: throw User.NotFoundException. This way you avoid working with the null user in your datasources, respository and in your use cases, and again, let your viewModel be responsible for handling that error
@jaidynbelbin48637 ай бұрын
All good points, but for the last one, how would you recommend handling error messages that come directly from an API response? Sometimes I want to display that exact error message in a dialog, or below a text field or something, as it gives a specific reason why a user action failed, so propagating the message from the Data layer all the way up to the presentation layer, intact. A possible solution could be coordinating with the backend developer to send an error code instead, but sometimes that isn't possible, ie. if the backend is shared with a web application that doesn't use that system. Thanks!
@PhilippLackner7 ай бұрын
You can extend the error message wrapper with an optional String field for that, it just wouldn't support localization in that case (or at least make it less flexible)
@RonnyBubke4 ай бұрын
First of all the UseCase suffix is not necessary. Also capsuling a function into a class where no dependencies are needed is also not necessary. Makes it more complex. You should use operator function "invoke" if you need a class for injecting deps and name the class like a function (ValidateEmail). You can call the instance easily like a function ("validateEmail(...)"). Really good readable. Example 2 is wrong IMHO. There is no such thing like the representation layer and a dogmatic assignment. Historically the splitting of View and Logic (Presenter, VM, Controller) was because of testing issues. The View isn't really good testable because of the huge framework which it brings with it. Therefore ALL code, which is testable should be tested and the View should have as less conditions (logic) as possible. It was always the responsibility of the Presenter (VM, Controller) to map the Data from different sources into an format the View can understand (ViewState) and which needs no further mapping/conditions (if possible) to be able to test the logic. I recommend lectures from Kent Beck, Ian Cooper, Robert C Martin (Uncle Bob), Martin Fowler. With the abstractions you are absolutely right. The problem with testing use cases is explained by Ian Cooper (TDD, Where Did It All Go Wrong). You shouldn't test use cases. Test should never know them. Just call the public interface (for instance ViewModel - on...Clicked()) and check for the out coming ViewState. Only external dependencies like a Database or a Http-Layer (Retrofit) should be mocked. I personally use Koin as dependency framework, which allows to override dependencies. Perfect to replace a Retrofit datasource by a mocked one. Install the production Koin Module + Override definitions in the Test. E.g. in the Test you always test the full path and never call implementation details like Usecases or Repositories. Otherwise the Code isn't really tested and refactoring is mostly impossible. Watch Ian Cooper and try to understand him!!! A good indicator you do it wrong is when you use VisibleForTesting annotation. Testing in isolation doesn't mean to test the production classes independent of each other but running the Tests independent of each other ->> Kent Beck You think too much in Layers and belongings. These things are just there to bring order into the code. Technical depth is fine if you have a good feature test coverage. Spaghetti code is fine if your have a good test coverage. If you test like Kent Beck you can refactor each time and the test will tell you if your features are still work. Your code is frozen, when you test each class and it make zero sense. I hope this wasn't to offensive and will bring you to the next level. -> Watch Ian Cooper!!!
@chitye-aung7 ай бұрын
Awesome 🎉❤
@mesutemrecelenk54477 ай бұрын
Thanks phlipp. Can you subscribe a video about unit test.
@Emran.Hejazi2 ай бұрын
If you don't like use cases, then what you like to do for business logic?
@mikec42207 ай бұрын
15:13 "ViewModel should take this enum and map it to the corresponding string resources". I'm not sure this is a good idea, you make your view model dependable on android resources which makes it harder to unit test in isolation.
@karol-lisiewicz7 ай бұрын
Actually, it doesn't affect the testability of a ViewModel. The generated R.string contains only a numeric constant for each resource that you can refer to in your project. This does NOT mean that you need to use Robolectric to test your ViewModels - you still can just unit test them.
@mikec42207 ай бұрын
@@karol-lisiewicz thanks a lot for your reply, I tried in the past but the solution I came up with was not the most compelling. On another hand this is what the best view model practices on the official android developer site tell us: As they can potentially live longer than the ViewModelStoreOwner, ViewModels shouldn't hold any references of lifecycle-related APIs such as the Context or Resources to prevent memory leaks.
@ErikBongers4 ай бұрын
The most common mistake? Not checking the date of the video. The android api is quite the chameleon. Don't watch tutorials older than a week. They're obsolete.
@saeedmoradi68587 ай бұрын
Okay but what you use instead usecase???
@Mike-er2ih7 ай бұрын
Common sense.
@codewithfelix3940Ай бұрын
What happens if a use case has more than one public method
@mohamadshqeer88647 ай бұрын
Bro speak about devin
@fpetrovski7 ай бұрын
Easiest solution, just don't use "use cases".
@maximooze31967 ай бұрын
I only smell religion in this topic here lol
@Tuligarnio7 ай бұрын
If you do not provide an explanation on why you think so it's not possible to debate about it.
@maximooze31967 ай бұрын
@@Tuligarnio ok I wont. 🫠
@cbnewham56337 ай бұрын
well, a mistake in the first one is requiring a mix of upper, lower and a number and yet having a password min length of 9. There should be no restrictions other than a password length of 10 or 11 - preferably more (i.e.: a pass-phrase). Unmemorable passwords (must have an uppercase letter, a lowercase letter, a number, a special character, and only to be created when there is a full moon) with silly short lengths are far less secure than, say, a lowercase phrase of appropriately long length (which is easily remembered too). Anyway, I'll unpause and see what the mistake is that your are actually pointing out - but these kinds of stupid password requirements really get my goat and I wish developers would quit doing this.
@PhilippLackner7 ай бұрын
But it's simply not secure to have only a length requirement. If the hashed password db gets leaked, it's super easy to Crack them by just trying every word in the dictionary