WEBVTT 00:00.240 --> 00:02.340 Welcome to the second video of the section. 00:02.340 --> 00:07.370 Future design pattern in the previous video we've worked with the barrier concurrency button. 00:07.650 --> 00:08.220 In this video. 00:08.220 --> 00:10.590 We're going to take a look at the future design pattern. 00:10.680 --> 00:14.810 Well understand this description write unit tests and implement them. 00:14.880 --> 00:19.890 The future design pattern also called Promise is a quick and easy way to achieve concurrent structures 00:19.890 --> 00:21.590 for asynchronous programming. 00:21.630 --> 00:27.330 We'll take advantage of first class functions and go to develop features in short will define each possible 00:27.330 --> 00:30.920 behavior of an action for executing them in different go routines. 00:31.050 --> 00:36.210 No dot J.S. uses this approach providing event driven programming by default. 00:36.210 --> 00:41.760 The idea here is to achieve a foreign forget that handles all possible results in an action to understand 00:41.760 --> 00:46.260 it better we can talk about a type that has embedded the behavior in case an execution goes well or 00:46.260 --> 00:47.580 in case it fails. 00:47.610 --> 00:51.760 And this diagram the main function launches a future within a new go routine. 00:51.870 --> 00:55.250 It won't wait for anything nor will it receive any progress of the future. 00:55.290 --> 00:57.650 It really fires and forgets it. 00:57.680 --> 01:02.690 The interesting thing here is that we can launch a new future within a future and embed as many futures 01:02.690 --> 01:05.470 as we want in the same go routine or new ones. 01:05.480 --> 01:09.500 The idea is to take advantage of the result of one future to launch the next. 01:09.500 --> 01:11.520 For example have a look at this diagram. 01:11.720 --> 01:13.720 Here we have the same future. 01:13.880 --> 01:19.430 In this case if the execute function returned the correct result the success function is executed and 01:19.430 --> 01:25.210 only in this case we execute a new go routine with another future inside or even without a go routine. 01:25.220 --> 01:30.500 This is a kind of lazy programming where a future could be calling itself indefinitely or just until 01:30.500 --> 01:32.000 some roll is satisfied. 01:32.000 --> 01:37.070 The idea is to define the behavior in advance and let the future resolve the possible solutions. 01:37.070 --> 01:39.650 What are our objectives with the future pattern. 01:39.650 --> 01:44.030 We can launch many new guy routines each with an action and its own handlers. 01:44.030 --> 01:49.790 This enables us to delegate the action handler to a different go routine stack many asynchronous calls 01:49.790 --> 01:54.460 between them and a synchronous call that calls another asynchronous call and its results. 01:54.500 --> 01:59.360 We're going to develop a very simple example to try to understand how a feature works and this example 01:59.360 --> 02:03.040 will have a method that returns a string or an error. 02:03.110 --> 02:04.950 We want to execute it concurrently. 02:05.000 --> 02:09.740 We've learned ways to do this already using the channel we can launch a new go routine and handle the 02:09.740 --> 02:11.740 incoming result from the channel. 02:11.840 --> 02:16.460 But in this case we'll have to handle the result string or error and we don't want this. 02:16.460 --> 02:21.680 Instead will define what to do in case of success and what to do in case of error and farm forget the 02:21.680 --> 02:24.490 go routine acceptance criteria. 02:24.560 --> 02:26.830 We don't have functional requirements for this task. 02:26.840 --> 02:31.280 Instead we'll have technical requirements for it that negate the function execution to a different guy 02:31.280 --> 02:37.430 routine the function will return a String maybe or an error the handlers must already be defined before 02:37.430 --> 02:38.780 executing the function. 02:38.840 --> 02:40.670 The design must be reusable. 02:40.670 --> 02:43.070 Now we'll start with unit tests. 02:43.070 --> 02:48.710 So as we mentioned will these first class functions to achieve this behavior and we'll need three specific 02:48.710 --> 02:56.330 types of function type success funk funk string these success funk function will be executed if everything 02:56.330 --> 03:00.250 went well its string argument will be the result of the operation. 03:00.350 --> 03:05.500 So this function will be called by our go routine type fail funk funk era. 03:05.650 --> 03:08.470 The Fail funk function handles the opposite result. 03:08.570 --> 03:13.760 That is when something goes wrong and as you can see it will turn an error type execute string funk 03:14.000 --> 03:16.100 funk string comma error. 03:16.100 --> 03:21.250 Finally the execute string funk function is a type that defines the operation we want to perform. 03:21.320 --> 03:23.930 Maybe it'll return a String or an error. 03:23.930 --> 03:26.680 Don't worry if this all seems confusing it will be clearer later. 03:27.940 --> 03:29.910 So we create the future object. 03:30.010 --> 03:36.370 We define a success behavior we define a fail behavior and we pass and execute string funk type to be 03:36.370 --> 03:42.950 executed in the implementation file we'll need new type like before we'll create two files featured 03:42.990 --> 03:51.860 or go on future unschooled test or go open the future don't go file and type this but also create two 03:51.860 --> 03:59.320 tests in the test Dok Go file well defined functions by changing them as you would usually see in no 03:59.320 --> 04:06.730 doc J.S. code like this is compact and not particularly difficult to file at the functions the featured 04:06.730 --> 04:11.770 dot success function must be defined in the maybe string structure to accept a success func function 04:11.800 --> 04:16.170 that will be executed if everything goes correctly and return the same pointed to the feature object 04:16.360 --> 04:21.670 so we can keep chaining the failed function must also be defined in the maybe string structure and must 04:21.670 --> 04:27.460 accept a failed func function to later return the pointer we return the pointer in both cases so we 04:27.460 --> 04:30.650 can define the file and these excess or vice versa. 04:31.000 --> 04:36.400 Finally we use the execute method to parse and execute string func type a function that accepts nothing 04:36.400 --> 04:38.150 and returns a string or an error. 04:38.170 --> 04:40.840 In this case we return a String and nil. 04:40.840 --> 04:46.420 So we expect these excess func function will be executed and we log the result to the console in case 04:46.420 --> 04:51.430 that fail function is executed the test is failed because the fail func function shouldn't be executed 04:51.430 --> 04:58.400 for return nil error but we still lack something here we said that the function must be executed asynchronously 04:58.520 --> 05:03.620 in a different go routine so we have to synchronize this test somehow that it doesn't finish too soon. 05:03.620 --> 05:07.250 Again we can use a channel or a sink that weight group like I'm adding now 05:30.660 --> 05:34.090 done we've seen weight groups before in the previous channel. 05:34.470 --> 05:40.950 This weight group is configured to wait for one signal WG add 1 and success and fail methods will trigger 05:40.950 --> 05:45.140 the done method of the weight group to allow execution to continue and finish testing. 05:45.180 --> 05:46.800 That is why the White method is at the end. 05:47.250 --> 05:52.220 Remember that each done method will subtract one from the weight group and we've added only one. 05:52.260 --> 05:58.410 So our white method will only block until one done method is executed using what we know of making a 05:58.410 --> 05:59.920 success result unit test. 05:59.940 --> 06:05.040 It's easy to make a failed result unit test by swapping the T don't fail method call from the error 06:05.040 --> 06:07.280 to success so that the test fails. 06:07.290 --> 06:15.090 If a call to success is done let's make some changes in the failed result say this open future dot go 06:16.360 --> 06:21.970 and add this code our test seems ready to execute it. 06:22.360 --> 06:23.230 Let's try it out. 06:24.380 --> 06:25.730 Open the terminal and type. 06:25.730 --> 06:29.680 Go test hyphen V Well the test of failed. 06:29.710 --> 06:31.580 Yes but not uncontrollable Why. 06:31.740 --> 06:33.190 Why is this. 06:33.420 --> 06:38.340 We don't have any implementation yet so no success or fail functions are being executed either. 06:38.340 --> 06:43.320 Our White group is waiting forever for a call to the done method that will never arrive so it can't 06:43.320 --> 06:45.170 continue and finish the test. 06:45.210 --> 06:50.070 That's the meaning of all go routines or sleep deadlock in our specific example. 06:50.070 --> 06:53.330 It would mean nobody is going to call done so we're dead. 06:53.370 --> 06:54.530 How can we solve this. 06:54.540 --> 06:59.370 Well an easy way would be with a timeout that calls he done method after waiting a while for completion 06:59.730 --> 07:00.350 for this code. 07:00.360 --> 07:06.120 It's safe to wait for one second because he's not doing any long running operations will declare a timeout 07:06.120 --> 07:10.950 function within our test file that waits for a second name printed message sets the test has failed 07:11.310 --> 07:16.720 and lets the wait group continue by calling its done method as go to our file and declare the timeout 07:16.720 --> 07:24.480 method the final look of each sub test is similar to our previous example of the success result we had 07:24.490 --> 07:25.270 timeout here 07:28.550 --> 07:33.520 and comment the success part import time package. 07:33.840 --> 07:37.240 Sign it let's see what happens when we execute our tests again. 07:37.240 --> 07:42.020 Our test failed but in a controlled way look at the end of the fail lines. 07:42.040 --> 07:46.920 Notice how the elapsed time is one second because it's been triggered by the timeout as we can see any 07:46.930 --> 07:48.010 logging messages. 07:48.190 --> 07:51.790 It's time to pass the implementation according to our tests. 07:51.790 --> 07:57.430 The implementation must take a success func a failed func and then execute string func function in a 07:57.430 --> 08:03.100 changed fashion within the may be string type and launch is the execute string func function asynchronously 08:03.100 --> 08:08.500 to call success func or fail func functions according to the returned result of the execute string func 08:08.500 --> 08:13.570 function the chain is implemented by storing the functions within the type and returning the pointer 08:13.570 --> 08:18.880 to the type we're talking about our previously declared type methods of course let's open future dot 08:18.880 --> 08:27.410 go and make the changes in the code we needed two fields to store the success funk and failed funk functions 08:27.620 --> 08:31.730 which are named success funk and fail funk fields respectively. 08:31.730 --> 08:37.030 This way calls to these success and fail methods simply store their incoming functions to our new fields. 08:37.070 --> 08:42.370 There's simply setters that also return the pointer to the specific maybe string value these type methods 08:42.380 --> 08:47.600 take a pointer to the maybe string structure so don't forget to put an asterisk on maybe string after 08:47.600 --> 08:54.040 the func declaration execute take the execute string func method and executes asynchronously. 08:54.050 --> 08:56.410 This seems quite simple with a go routine right. 08:56.570 --> 09:01.780 So add execute function looks quite simple because it is simple. 09:01.970 --> 09:08.540 We launched the go routine executes the F method and execute string func and takes its result may maybe 09:08.540 --> 09:11.540 a string and maybe an error if an error is present. 09:11.570 --> 09:17.660 We call the field fail func in our maybe string structure if no error is present we call these success 09:17.660 --> 09:23.030 func field we use it go routine to delegate a function execution and error handling so I'll go routine 09:23.030 --> 09:30.740 doesn't have to have it let's run unit tests now open the terminal and type the command test great look 09:30.740 --> 09:33.120 at how the execution time is now nearly zero. 09:33.200 --> 09:35.280 So our time outs have not been executed. 09:35.390 --> 09:40.760 Actually they were executed but the tests already finished and their result was already stated. 09:40.760 --> 09:45.530 What's more now we can use our maybe string type 2 asynchronously execute any type of function that 09:45.530 --> 09:50.750 accepts nothing and returns a string or an error a function that accepts nothing seems a bit useless 09:50.750 --> 09:51.240 right. 09:51.470 --> 09:56.340 But we can use closures to introduce a context into this type of function. 09:56.480 --> 10:01.400 Let's write to set context function that takes a string as an argument and returns and execute string 10:01.400 --> 10:07.520 func method that returns the previous argument with the suffix closure so navigate to future not go 10:07.520 --> 10:14.940 file and add the code right over here so we can write a new test that uses its closure. 10:15.190 --> 10:23.920 Open the future dot go file and at the time that pile here the set context function returns and execute 10:23.920 --> 10:29.650 string func method it can pass directly to the execute function we call the set context function with 10:29.650 --> 10:33.590 an arbitrary text that we know will be returned that's uncommon. 10:33.590 --> 10:38.560 This portion lets execute our tests again. 10:38.560 --> 10:39.870 Now everything has to go well. 10:40.630 --> 10:47.530 Open the terminal and run it again it gave us no K-2 closure test shows the behavior that we explained 10:47.530 --> 10:51.510 before by taking a message Hello and appending it with something else. 10:51.550 --> 10:52.450 Closure. 10:52.450 --> 10:59.380 We can change the context of the text we want to return now scale this to an H TTP get call a call to 10:59.380 --> 11:04.240 a database or anything you can imagine it will just need to end by returning a string or an error. 11:04.330 --> 11:09.160 Remember however that everything within the set context function but outside of the anonymous function 11:09.160 --> 11:15.100 that we're returning is not concurrent and will be executed asynchronously before calling execute. 11:15.160 --> 11:20.350 So he must try to put as much logic as possible within the anonymous function in this video we successfully 11:20.350 --> 11:22.380 worked with function design pattern. 11:22.390 --> 11:23.020 Amazing. 11:23.170 --> 11:26.140 In the next video we'll look into the pipeline design pattern.