WEBVTT 00:00.500 --> 00:01.170 Hi. 00:01.270 --> 00:07.840 We are now at the second video of this section Chain of Responsibility design pattern in the previous 00:07.840 --> 00:08.260 video. 00:08.290 --> 00:12.040 We looked at strategy design pattern in this video. 00:12.040 --> 00:16.750 We will develop a multi logo solution that we can change in the way we want. 00:16.750 --> 00:21.860 We will use two different console loggers and one general purpose logger. 00:21.970 --> 00:29.110 Our next pattern is called Chain of Responsibility as its name implies it consists of a chain and in 00:29.110 --> 00:34.030 our case each link of the chain follows the Single Responsibility Principle. 00:34.090 --> 00:40.210 The Single Responsibility Principle implies that the type function method or any similar abstraction 00:40.450 --> 00:45.940 must have one single responsibility only and it must do it quite well. 00:45.940 --> 00:52.720 This way we can apply many functions that achieve one specific thing each to some struct slice map and 00:52.720 --> 00:59.710 so on when we apply many of these abstractions in a logical way very often we can chain them to execute 00:59.800 --> 01:06.610 in order such as for example a logging chain a logging chain is a set of types that logs the output 01:06.610 --> 01:10.540 of some program to more than one Io dot writer interface. 01:10.600 --> 01:16.210 We could have a type that logs to the console a type that logs to a file a type that logs to a remote 01:16.210 --> 01:21.670 server you can make three calls every time you want to do some logging but it's more elegant to make 01:21.790 --> 01:24.640 only one and provoke a chain reaction. 01:24.820 --> 01:31.120 But also we can have a chain of checks and in case one of them fails break the chain and return something. 01:31.120 --> 01:35.560 This is how the authentication and authorization middleware works. 01:35.560 --> 01:41.050 The objective of the chain of responsibility is to provide to the developer a way to chain actions at 01:41.050 --> 01:42.220 runtime. 01:42.220 --> 01:48.190 The actions are changed to each other and each link will execute some action and pass the request to 01:48.190 --> 01:49.440 the next link. 01:49.600 --> 01:53.420 Here we have listed the objectives followed by this pattern. 01:53.740 --> 02:01.390 First is dynamically change the actions at runtime based on some input and secondly pass a request through 02:01.390 --> 02:04.950 a chain of processors until one of them can process it. 02:05.140 --> 02:07.800 In which case the chain could be stopped. 02:08.170 --> 02:13.330 Here we are going to develop a multi logger solution that we can change in a way we want. 02:13.330 --> 02:18.170 We will use two different console loggers and one general purpose logger. 02:18.220 --> 02:24.910 For this we need a simple logger that logs the text of a request with a prefix first logger and passes 02:24.910 --> 02:27.100 it to the next link in the chain. 02:27.160 --> 02:33.580 Next a second logger will write on the console if the incoming text has the word hello and pass the 02:33.580 --> 02:35.740 request to a third logger. 02:35.740 --> 02:40.840 But if not the chain will be broken and it will return immediately. 02:40.840 --> 02:47.220 Then a third logger type is a general purpose logger called writer her logger that uses an IO dot writer 02:47.230 --> 02:48.830 interface to log. 02:48.850 --> 02:55.210 Lastly a concrete implementation of the right or logger rights to a file and represents the third link 02:55.360 --> 02:56.810 in the chain. 02:56.950 --> 03:00.730 The implementation of these steps is described in the figure on your screen. 03:00.790 --> 03:05.430 It gives a clear flow and explanation of what we intend to do. 03:05.560 --> 03:10.380 Now we move on to see how we are going to write the unit test for this example. 03:10.420 --> 03:14.230 As you can see I have already created file chain. 03:14.230 --> 03:22.030 Dot go and change underscore test dot go let's open the chain dot go file the very first thing to do 03:22.030 --> 03:28.180 for the chain is as usual to define the interface a chain of responsibility interface will usually have 03:28.270 --> 03:30.520 at least a next method. 03:30.520 --> 03:34.630 The next method is the one that executes the next link in the chain. 03:34.720 --> 03:41.380 Of course the next method on our examples interface takes the message we want to log and passes it to 03:41.380 --> 03:42.950 the link in the chain. 03:42.970 --> 03:45.910 As I said earlier we need three loggers. 03:46.000 --> 03:52.840 So let me add the three loggers the first logger and second logger types have exactly the same structure 03:53.200 --> 04:00.420 both implement chain logger and have a next chain field that points to the next chain logger the right 04:00.420 --> 04:06.640 or logger type is equal to the first logger and second logger types but also has a field to write its 04:06.640 --> 04:07.560 data too. 04:07.690 --> 04:15.250 So you can pass any Io dot writer interface to it as we have done before will implement an IO dot writer 04:15.250 --> 04:18.750 struct to use in our testing in our test file. 04:18.820 --> 04:23.920 We defined the following struct let's save the file and go to change test Dot. 04:23.920 --> 04:25.860 Go first. 04:25.950 --> 04:30.710 We write the package name followed by the import statement and define the struct. 04:30.900 --> 04:37.380 We will pass an instance of my test writer struct to right logger so we can track what's being logged 04:37.380 --> 04:44.130 on testing the my test writer class implements the common right byte in comma error method from the 04:44.130 --> 04:46.010 IO dot writer interface. 04:46.020 --> 04:52.890 Remember if it has the right method it can be used as Io dot writer the right method simply stored the 04:52.890 --> 04:59.160 string arguments to the received message field so we can check later its value on tests. 04:59.160 --> 05:02.070 Now let's begin the first test function. 05:02.100 --> 05:09.500 Here's the code for it wait let me describe these few lines a bit as they are quite important. 05:09.640 --> 05:11.980 We create a variable with a default. 05:12.010 --> 05:16.410 My test write or type that we'll use as an IO dot writer interface. 05:16.420 --> 05:23.710 In the last link of our chain then we create the last piece of the link chain the writer logger interface. 05:23.860 --> 05:29.620 When implementing the change you usually start with the last piece on the link and in our case it is 05:29.620 --> 05:33.580 a writer logger the writer logger writes to an IO dot writer. 05:33.640 --> 05:38.440 So we pass my writer as Io dot writer interface. 05:38.440 --> 05:45.430 Then we have created a second logger the middle link in our chain with a pointer to the writer logger. 05:45.430 --> 05:51.820 As we mentioned before second logger just logs and passes the message in case it contains the word hello 05:52.270 --> 05:53.460 in a production app. 05:53.500 --> 06:00.520 It could be an error only logger finally the first link in the chain has the variable name chain. 06:00.560 --> 06:07.580 It points to the second logger so to resume our chain looks like first logger followed by second logger 06:07.790 --> 06:10.250 and then the writer logger. 06:10.400 --> 06:12.730 Let me add a few more lines of code here. 06:12.800 --> 06:20.700 So this is going to be our default setup for our tests continuing with go one point seven or later testing 06:20.700 --> 06:21.490 signatures. 06:21.540 --> 06:27.080 We define an inner test with this description three loggers two of them right to console. 06:27.180 --> 06:30.280 The second only if it finds the word hello. 06:30.300 --> 06:34.510 The third rights to some variable if the second found Hello. 06:34.590 --> 06:40.230 It's quite descriptive and very easy to understand if someone else has to maintain this code. 06:40.230 --> 06:45.480 First we use a message on the next method that will not reach the third link in the chain as it doesn't 06:45.480 --> 06:51.360 contain the word hello we check the contents of the received message variable that by default is empty 06:51.510 --> 06:54.690 to see if it has changed because it shouldn't. 06:54.690 --> 06:56.870 Next we use the chain variable again. 06:56.970 --> 06:59.510 Our first link in the chain and passed the message. 06:59.580 --> 07:00.600 Hello. 07:00.630 --> 07:04.730 According to the description of the test it should log using first logger. 07:04.740 --> 07:10.080 Then in second logger and finally in right or logger because it contains the word hello. 07:10.110 --> 07:13.470 And the second logger will let it pass the test. 07:13.490 --> 07:18.300 Checked that my writer the last link in the chain that stored the past message in a variable called 07:18.510 --> 07:22.220 received message has the word that we passed first in the chain. 07:22.560 --> 07:23.560 Hello. 07:23.640 --> 07:24.410 Let's run it. 07:24.480 --> 07:26.160 So it fails. 07:26.220 --> 07:29.880 Save the file and move on to the terminal type the command. 07:29.880 --> 07:31.900 Go test hyphen V. 07:32.130 --> 07:37.290 The test passed for the first check of the test and didn't for the second check. 07:37.290 --> 07:42.120 Well ideally no checks should pass before any implementation is done. 07:42.120 --> 07:47.760 Remember that in test driven development test must fail on the first launch because the code they are 07:47.760 --> 07:55.680 testing isn't implemented yet goes 0 initialization misleads us with this past check on the test. 07:55.680 --> 08:01.770 We can solve this in two ways first by making the signature of the chain logger to return an error that 08:01.770 --> 08:04.060 is next string error. 08:04.080 --> 08:07.390 This way we would break the chain returning an error. 08:07.410 --> 08:12.090 This is a much more convenient way in general but it will introduce quite a lot of boilerplate right 08:12.120 --> 08:12.900 now. 08:12.900 --> 08:20.130 And secondly by changing the received message build to a pointer a default value of a pointer is nil. 08:20.130 --> 08:25.890 Instead of an empty string we will use the second option now as it is much simpler and quite effective 08:25.890 --> 08:34.210 to so let's change the signature of my test writer struct open the change test dot to go file let let's 08:34.220 --> 08:38.330 modify the received message and add a pointer that is temp message 08:41.590 --> 08:47.470 check that the type of received message has the asterisk now to indicate that it is a pointer to a string. 08:47.470 --> 08:50.420 The right function needed to change too. 08:50.590 --> 08:56.260 Now we have to check the contents of the received message field because as every pointer It's initialized 08:56.260 --> 09:02.140 to nil then we have to store the message in a variable first so we can take the address in the next 09:02.140 --> 09:03.520 line on the assignment. 09:03.670 --> 09:08.410 M dot received message equals Ampersand temp message. 09:08.440 --> 09:11.910 So now our test code should change a bit too. 09:11.990 --> 09:19.020 Let's replace this code now we are checking that my writer daughter received messages actually nil. 09:19.020 --> 09:23.040 So no content has been written for sure on the variable. 09:23.040 --> 09:28.560 Also we have to change the second half to check first that the member isn't nil before checking its 09:28.560 --> 09:32.230 contents or it can throw a panic on test. 09:32.250 --> 09:33.750 Let's test it again. 09:33.750 --> 09:37.870 Save the file and move back to the terminal and run the test. 09:37.900 --> 09:42.600 Whoops we forgot to remove the comment and include the F.M. t package. 09:42.600 --> 09:43.970 Let's go back and do it. 09:44.760 --> 09:45.350 Cool. 09:45.480 --> 09:48.020 Save the file again and let's run the test again. 09:49.260 --> 09:55.680 It fails again and again the first half of the test passes correctly without implemented code. 09:55.710 --> 09:57.380 So what should we do now. 09:57.420 --> 10:03.690 We have to change the signature of the my right or type to make the test fail in both checks and again 10:03.720 --> 10:05.070 just fail in the second. 10:05.940 --> 10:09.790 Well in this case we can pass this small issue when writing tests. 10:09.810 --> 10:13.550 We must be very careful not to get too crazy about them. 10:13.620 --> 10:17.120 Unit tests are tools to help us write and maintain code. 10:17.220 --> 10:21.210 But our target is to write functionality not tests. 10:21.210 --> 10:28.210 This is important to keep in mind as you can get really crazy engineering unit tests now that we have 10:28.210 --> 10:29.530 written the unit test. 10:29.530 --> 10:32.110 Let us move on to the implementation. 10:32.110 --> 10:37.120 Now we have to implement the first second and third loggers called First logger. 10:37.120 --> 10:44.110 Second logger and writer logger respectively the first logger is the easiest one as described in the 10:44.110 --> 10:46.210 first acceptance criterion. 10:46.360 --> 10:53.130 We need a simple logger that logs the text of a request with a prefix first logger and passes it to 10:53.170 --> 10:55.110 the next link in the chain. 10:55.120 --> 10:56.320 So let's do it. 10:56.320 --> 10:59.020 Let's open our chain dot go file. 10:59.020 --> 11:04.190 I've already added these lines of code but we need to make a few changes here. 11:04.210 --> 11:08.480 Let's first modify the function f OK. 11:08.680 --> 11:10.990 The implementation is quite easy. 11:11.200 --> 11:18.790 Using the F.M. T dot print f method to format and print the incoming string we appended to the text 11:18.790 --> 11:26.320 first logger text then we check that the next change type has actually some content and pass the control 11:26.320 --> 11:29.550 to it by calling its next string method. 11:29.620 --> 11:34.210 The tests shouldn't pass yet so we'll continue with the second logger. 11:34.390 --> 11:37.840 So let's make similar changes to the second logger. 11:37.840 --> 11:43.950 As mentioned in the second acceptance criterion the second logger description is a second logger will 11:43.990 --> 11:51.040 write on the console if the incoming text has the word hello and pass the request to a third logger. 11:51.040 --> 11:54.340 First of all it checks whether the incoming text contains the text. 11:54.340 --> 11:54.810 Hello. 11:55.120 --> 11:59.560 If it's true it prints the message to the console appending the text. 11:59.560 --> 12:06.730 Second logger and passes the message to the next link in the chain check previous instance that the 12:06.730 --> 12:14.290 third link exists but if it doesn't contain the text Hello the chain is broken and it prints the message. 12:14.290 --> 12:16.510 Finishing in second logging. 12:16.840 --> 12:19.480 Now we'll finalize the writer logger type. 12:20.260 --> 12:21.740 Here's the writer logger. 12:21.940 --> 12:23.700 Let us modify it. 12:23.830 --> 12:26.790 Call the writer logger struct next. 12:26.790 --> 12:33.100 Method checks that there is an existing Io dot writer interface stored in the writer member and writes 12:33.130 --> 12:38.120 there the incoming message appending the text writer or logger to it. 12:38.290 --> 12:43.450 Then like the previous links check that there are more links to pass the message. 12:43.450 --> 12:46.090 Now the tests will pass successfully. 12:46.090 --> 12:49.680 Let's save this file and move on to the terminal. 12:49.720 --> 12:57.250 Now run the test the first half of the test print two messages the first logger message that breaks 12:57.250 --> 13:03.040 the chain which is the expected message for the first logger but it halts and the second logger because 13:03.040 --> 13:07.000 no hello word has been found on the incoming message. 13:07.030 --> 13:13.130 That's why it prints the finishing in second logging string the second half of the test receives the 13:13.130 --> 13:13.570 message. 13:13.700 --> 13:14.450 Hello. 13:14.450 --> 13:19.680 So the first logger prints and the second logger prints to the third logger. 13:19.690 --> 13:27.310 Doesn't print to console at all but to our my writer dot received message line defined in the test. 13:27.350 --> 13:31.430 Now before we end this video we need to ask one thing. 13:31.580 --> 13:33.350 What about a closure. 13:33.350 --> 13:38.930 Sometimes it can be useful to define an even more flexible link in the chain for quick debugging. 13:38.930 --> 13:44.170 We can use closures for this so that the link functionality is defined by the caller. 13:44.180 --> 13:46.590 What does a closure link look like. 13:46.610 --> 13:48.370 It's similar to the writer logger. 13:48.620 --> 13:51.100 Let's open the chain dot go file now. 13:51.200 --> 13:58.610 At the end of the file add these lines of code the closure chain type has a next chain as usual and 13:58.610 --> 14:00.160 a closure member. 14:00.170 --> 14:03.920 Look at the signature of the closure func string. 14:03.950 --> 14:10.190 This means it is a function that takes a string and returns nothing the next string method for closure 14:10.190 --> 14:15.730 chain checks that the closure member is stored and executes it with the incoming string. 14:15.950 --> 14:21.850 As usual the link checks for more links to pass the message as every link in the chain. 14:21.890 --> 14:23.720 So how do we use it now. 14:23.720 --> 14:26.780 We'll define a new test to show its functionality. 14:26.990 --> 14:32.210 Let's save this file and open chain underscore test dot go. 14:32.210 --> 14:34.970 And here we add this test function. 14:34.970 --> 14:41.190 The description of this test makes it clear to loggers second uses the closure implementation. 14:41.210 --> 14:45.470 We simply use to chain logger implementations and we use the closure logger. 14:45.470 --> 14:51.910 In the second link we have created a new my test writer to store the contents of the message. 14:52.220 --> 14:57.650 When defining the closure chain we defined an anonymous function directly on the closure member. 14:57.740 --> 15:04.250 When creating closure logger it prints my closure logger message with the incoming message replacing 15:04.490 --> 15:06.770 modulus s part. 15:06.770 --> 15:13.480 Then we store the incoming message on my writer to check later after defining this new link. 15:13.480 --> 15:16.760 We use the third link from the previous test. 15:16.810 --> 15:22.210 The closure is the fourth link and passed the message Hello closure logger. 15:22.210 --> 15:26.360 We use the word hello at the beginning so that we ensure that the message will pass. 15:26.380 --> 15:28.500 The second logger. 15:28.640 --> 15:34.160 Finally the contents of my writer dot received the message must contain the past. 15:34.160 --> 15:37.130 Text Hello closure logger. 15:37.250 --> 15:42.950 This is quite a flexible approach with one drawback when defining a closure like this we cannot test 15:42.950 --> 15:45.940 its contents in a very elegant way. 15:46.060 --> 15:51.680 Let us run the tests again so move back to the terminal and run the test command. 15:51.680 --> 15:55.820 Go test hyphen v look at the third run. 15:55.820 --> 16:01.670 The message passes correctly through the first second and third links to arrive at the closure that 16:01.670 --> 16:07.340 prints the expected my closure logger message Hello closure logger message. 16:07.560 --> 16:13.490 It's very useful to add a closure method implementation to some interfaces as it provides quite a lot 16:13.490 --> 16:19.400 of flexibility when using the library the handle func function which we used previously in the structural 16:19.400 --> 16:23.960 patterns is to define a handler for an H TTP. 16:23.960 --> 16:27.700 Now let me put it together what we learned in this video. 16:27.920 --> 16:34.220 So we learned a powerful tool to achieve dynamic processing of actions and State handling. 16:34.220 --> 16:39.820 The chain of responsibility pattern is widely used also to create finite state machines. 16:39.860 --> 16:41.510 That is FSM. 16:41.510 --> 16:47.060 It is also used interchangeably with the decorator pattern with the different that when you decorate 16:47.090 --> 16:52.550 you change the structure of an object while with the chain you define a behavior for each link in the 16:52.550 --> 16:55.200 chain that can break it too. 16:55.430 --> 17:01.700 In this video we saw in detail about chain of responsibility design pattern in the next video. 17:01.730 --> 17:04.490 We will be learning about command design pattern.