Flutter TDD Clean Architecture Course [3] – Domain Layer Refactoring

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
our number trivia app is moving along nicely in the previous part we created an entity repository contract which is an abstract class and the first use case get concrete number trivia all using test-driven development today we are going to add another use case which will uncover a nice opportunity for refactoring the code hello welcome to reso coder where you're getting prepared for real app development by building better faster more stable apps so subscribe and hit the bell if you want to grow your coding skills and as usual be sure to check out the written tutorial from the link in the description where you can also find all of the code written in this video all of the links and go through this lesson at your own pace first things first let's refactor this get concrete number trivia which we have added in the last part using test-driven development so let's actually in addition to opening this get concrete number trivia file also open its test file so over here you can see that we have a method called execute but did you know that dart supports something called callable classes and this is perfect for use cases because when you think about it if we go over to the test all that a use case does is that it has an execute method wouldn't it be much nicer to just call it something like this use case to parentheses right just like a regular method the execute is really redundant here well this is possible with a method called call and we are already doing this in the spirit of test-driven development because we have first updated the test code now this test code doesn't even compile anymore because there is no such method and after we've modified this test we can now move on to the production code and all we have to do is to rename this execute method to call it's as simple as that and now we've made this test to pass because the call method can be either called as a regular call method but it can be also called without specifying the name of the call method and now all we have to do is to use the keyboard shortcut for running all tests which you have hopefully setup in the previous part or you can also always go here in in the debug tab in vs code select dart run all tests and it should still pass just fine all right but this is obviously not all that we will do in this part because we also want to add another use case that is get random number trivia that's because in addition to getting trivia for a concrete number we can also get trivia for a random number and the numbers API we are using for this number trivia app has actually a different API endpoint for concrete and random numbers so this means we are getting ahead of ourselves a bit because we are not dealing currently with the data sources we are still in the domain layer not in the data layer but just so we know the numbers API here is the API URL so Bob Loblaw calm and then forgetting regular numbers you have like specified numbers so 42 for example and then diagrams you a number but for the random numbers you have API rock on four slash random and it chooses or generates random number for you so we will not generate random numbers directly in the get random number use case which we are about to create we're just going to really again just get the data from the repository should we have to generate random numbers that would obviously go into the get random number trivia use case which we are going to import in just a bit because that's actually business logic generating random numbers is yeah really simple business logic but it's still a business logic however we are not gonna have to do that because there is a completely different endpoint which does the work for us on the back end so to say but before we create the get random number trivia use case as clean coders we surely want our code to have a predictable interface an interface simply means the methods and fields that are public and exposed by classes so the current interface of the get concrete number trivial use case is that it exposes the call method and when you think about it every single use case in our app or in any kind of other app should expose a call method it doesn't matter if it gets data from a number trivia API or if it sends the Space Shuttle to the moon or to the Mars or whatever it does a use case should always have a call method and one way to enforce such a method or a stable interface of class is to rely on the implicit we are gonna call it word of the programmer sadly and maybe it's just me but I would say that programmers aren't well known for remembering things heck I even watched some of my awl tutorials because I've already forgotten how to do things I've made a tutorial on so I have to rewatch my own tutorials and with that there is the another way of ensuring that a certain interface is present on a class and that is through abstract classes in dart because dart doesn't support interfaces it has only abstract classes and basically any class can be implemented as an interface that's something specific to Dart in Java or in Catalan you would have an interface but in dart you have abstract class and that way when the abstract class the base class for every use case will define that it should have a call method it will be impossible to forget that the method should be called call and instead create and execute method as we did before because it will be enforced by the abstract class which is implemented so let's create such an abstract class for enforcing the interface of this class right now we're going to put it into the core folder under the use cases subfolder because this applies to all of the use cases across all of the features of our app that's why it goes into the core folder so let's create a new file under use cases we're going to call it use case Dart pretty simple and inside of here we want to have an abstract class use case and now bear with me here I am going to explain everything in just a little while so it will have two type parameters the first one is type and then params so parameters and this type is the return type off what else then the call function so as you know from the already implemented get concrete number trivia the return type should be future which holds either a failure or number trivia so we go over here and we're going to call it call now let's import it once we've named the function because before naming the function you cannot import anything so let's import everything here but of course he won't return number trivia but it will return type because we are in the core folder we can now rely that all of the use cases will work with number trivia we have to let the use cases which implement this base use class specify their own return type whatever that may be the failure can be sort of hard coded here so to say it's not really hard coded because failure is also an abstract class now this params type is something peculiar to this abstract base use case class it's not all that needed right now because we aren't actually gonna add any functionality to this use case class just yet so we technically do not need this prompts but why it's actually a good idea to leave it in here even though we do not need it currently is that if you wanted to do something with the parameters so for example this int number is a parameter for the call method and you wanted to log them in this call so you would have the call looking something like this so it would not be completely an abstract class without implementation but it would have some sort of an implementation so you would just want to log it so print and how would you access the number parameter passed into the call method of the get concrete number trivia well you would have a problem you cannot access the parameter passed into the concrete class that's where these params come in when we specify params forums you can now operate with these parameters and of course we do not entirely need it just yet we're now going to be really utilizing it in this app this is probably the only thing which we are gonna do which we don't currently need we are now going to follow the you ain't gonna need it principle because we are not really trying to future prove an implementation which is a bad thing but trying to future proof and interface is actually in my opinion good thing alright so now let's go to get concrete number trivia and we do not need to change anything in the test for this class because we are just really going to only implement use case and specify that the type should be number trivia and what's up with the params well we know that the params of the call method is just a single integer called number so we technically could just specify an INT here and it would be cool and then of course because the parameter in the use case base class is not named parameter and not optional name parameter we would have to change this to be also non optional nun named parameter and let's also add the override annotation for good measure so that will work just fine but to make it a bit more clean again we are going to just create a dumb data holder class which will be called params and this will be the case for all of the use cases and the params class will hold all of the parameters for the call method so in this case it will hold only the integer number so let's create class params which will extend equatable so let's import equatable and it's gonna have just one final int number and it's gonna be in the constructor and it's going to be a named parameter so let's do it like that let's make it required and then let's also pass it to the super constructor of equatable so super number was going on with dart analyzer was restore it so super constructor and as in the number and now before we modify the code which can be actually tested because up until now we've been all in doing again with code which cannot be at all tested we're going to go to the test and now the use case should be called with params and specify params which come from the get concrete number trivia dart file and it gets a number so again it will be the T number this does not compile so let's go to the implementation we are going to instead of a number except params here from spur arms and then to make it all we're going to call the repositories method get entry number trivia using the params that number which is present over there now the test seems to be hopefully fine but it's not oh that's right because we have made these promised to be a named argument but in the class in the production code we do not have it named so actually let's make it not named because it doesn't really need to be named when there is just one argument params name and it doesn't make any kind of sense it's just redundant and with that we have the test passing we can run it or not passing just yet it's just compiling but it's also passing as we can see it best just fine and now we have a stable interface which every single use case in the app must conform to with all of this work done creating another use case for getting the random number trivia will be extremely simple and straightforward so in the spirit of test-driven development let's create the test first so under test and use cases under the domain layer test we're going to create a new file get random number trivia test and what we can do is to just copy the test forget concrete number trivia you should never copy code in production but for tests that different tests do not really have to be all that refactored you can have some duplication in tests but in production code that's exactly the opposite of course you should strive to not have duplication even in tests but it's not as bad as with production code you can have a certain amount of duplication it doesn't really matter so we will still have the Mach number trivia repository we are now going to deal with get concrete number trivia brinstead get random number trivia again we're gonna get errors right off the bat because this class doesn't currently exist yet but that's fine because we are doing DVD then get random number trivia will accept the repository as a parameter and when it comes to the test we do not need the test number because it's gonna operate with a random number we do not need to specify it ourselves we're gonna leave the type returned by the repository to be the T number trivia that's called we're going to also rename the test because it should not get trivia for the number from the repository because there is no number to get the trivia for it's gonna be gotten for random number so the test will just say should get trivia from the repository then the method called on the repository will not be get concrete number trivia but get random number trivia which doesn't accept any parameters or any arguments and it's still going to return the successful right side of the eater because left side is failure right side is success so to say and this successful side of either will contain the T number trivia and when it comes to calling the use case now it gets a little interesting because we have params right but get random number trivia use case will not get any para más in because there's no point in passing in parameters when it doesn't need to know about the number for which it should get the trivia because the number will be generated in the API so it seems that we can just delete these params from being passed in and we do not get any errors right but that's only because the use case is dynamic and that's because the use case doesn't currently exist so before we continue let's just create a blank class of get random number trivia use case under domain use cases so create a new file get random number trivia the dart and it's gonna be really simply class get random which will implement use case which will return number trivia and now comes the interesting stuff because use case is second type parameter is params so what are we going to specify as the type for params when get random number trivia will not get any problems because it doesn't need to get any number for which it should get the trivia well we can create a class no params and let's just also make it extend equatable just so that two instances of no params will be always equal because they don't contain any fields and now we can specify no params here and now it writes here that we have an error because we do not override one method and before we implement this method of course we are going to finish writing the test so in the test we can now see that after we import get random number trivia we can no longer just have an empty call for the use case because it expects one argument and there will be no params which specifies that there are no prompts of course the third part of the test can remain almost unchanged because we still expect that the result will be the right side of the either so the success containing T number trivia but what we should verify instead of get concrete numbers Rivia on the repository it should verify that get random number trivia has been called and then before we can run the test which will of course fail completely we have to get rid of this error that gate ran the number true yeah use case cannot accept the repository as an argument for the constructor so let's go to get random number trivia and let's fix that we're going to have a repository what's actually copied that from get concrete number trivia because it's gonna be exactly the same so it's gonna have the repository in here and of course the constructors name will be get random number trivia and now this use case test does not have any apparent errors so we can run it but it's going to of course fail and if we take a look at that obviously the failure will be that expected right dynamic but it received no that's because we don't currently return anything so let's actually implement the production code for which we have written this test so inside get random number trivia we know that we want to return a weight so let's make this asynchronous so a weight repository that get random number trivia and with that we can rerun the test and it should pass and it definitely does so that's awesome the last thing which we are gonna do is by taking a look at this know params class it's probably a good idea to move it over to the use case core file this kind of thing can be shared across multiple features because surely this get random number trivia use case is not the only use case which will not need any params so because of that we're going to cut this no promise out of here and paste it over to the use case core file import equatable there and now all the code will still hopefully work which is neat to import no Brahms in the test if we rerun the test we can see that it still works as it did before and now let's just fix all of the imports so we're going to hit f1 fixed imports this is just fixed import extension for V s code you can find it over here so dart import just download that and you will be able to also convert all of the imports to be relative imports and not absolute imports and with that we've just successfully implemented the whole domain layer of this number trivia app because we have the entity we have the repository contract abstract class and we have all of the use cases fully implemented and what's most important fully tested in the next part we're gonna start working on the data layer which contains the repository implementation and also data sources so if you don't wanna miss that next part and also many more tutorials like this definitely subscribe to this channel and also join the notification squad by hitting the Bell button to make sure you grow your flutter coding skills because here on reso coder I am determined to provide you with the best app development tutorials and resources out there if this video helped you with finally implementing and understanding the domain layer and also with test-driven development give it a like and also share it with our developers who will surely benefit from it to follow me on Instagram I go under the name reso coder everywhere if you want to get some behind-the-scenes news leave a comment if you have anything to say if you have any questions I try to really answer all of the appropriate questions to my full abilities and see you Internet [Music]
Info
Channel: Reso Coder
Views: 30,280
Rating: undefined out of 5
Keywords: resocoder, tutorial, programming, code, programming tutorial, clean architecture, software development, flutter clean ui, flutter clean architecture, flutter clean code, flutter testing tutorial, flutter tdd, flutter test driven development, flutter crash course, flutter course, flutter, flutter tutorial, flutter dependency injection, flutter state management, flutter bloc library, flutter unit test, flutter mvp, flutter mvvm
Id: Mmq72a0h4jk
Channel Id: undefined
Length: 24min 25sec (1465 seconds)
Published: Mon Sep 02 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.