1 00:00:07,290 --> 00:00:07,770 Hello. 2 00:00:08,350 --> 00:00:16,350 In this lecture, we're going to talk about Question 29, what is getting caching is a mechanism that 3 00:00:16,350 --> 00:00:18,940 allows storing some data in memory. 4 00:00:18,990 --> 00:00:24,480 So next time it is needed, it can be solved faster to understand it better. 5 00:00:24,540 --> 00:00:26,520 Let's consider this class. 6 00:00:27,210 --> 00:00:34,650 This class is responsible for retrieving a personal object from some repository using the person's first 7 00:00:34,650 --> 00:00:35,820 and last name. 8 00:00:36,360 --> 00:00:40,590 This code is very simple, but we must be aware of one thing. 9 00:00:40,950 --> 00:00:44,460 We don't know what this data source is exactly. 10 00:00:44,700 --> 00:00:50,520 And in our real life project, accessing the data from an external source may be slow. 11 00:00:50,920 --> 00:00:58,290 Maybe the class implementing the repository interface connects to some bulky database or retrieves data 12 00:00:58,380 --> 00:00:59,640 from some API. 13 00:01:00,180 --> 00:01:06,870 It won't be the case that every call to this external data source takes some considerable time, and 14 00:01:06,870 --> 00:01:11,610 if many calls are executed, the application may start to work slowly. 15 00:01:11,910 --> 00:01:13,050 We don't want that. 16 00:01:13,680 --> 00:01:15,420 How can we make it better done? 17 00:01:15,750 --> 00:01:23,430 Well, one solution could be this if we already accessed the data for some particular first and last 18 00:01:23,430 --> 00:01:28,730 name, for example, John Smith, we could store it in the application memory. 19 00:01:28,740 --> 00:01:35,520 And next time when we want to find John Smith will access his data immediately instead of asking the 20 00:01:35,520 --> 00:01:38,040 external system to provide it again. 21 00:01:38,460 --> 00:01:40,770 This mechanism is called caching. 22 00:01:41,130 --> 00:01:48,210 We store some data in a cache, so a piece of memory of the application making it available immediately. 23 00:01:48,630 --> 00:01:51,570 Let's implement a very simple caching mechanism. 24 00:01:52,170 --> 00:01:55,020 We'll start with defining a class. 25 00:02:02,120 --> 00:02:09,380 As you can see, I mostly discuss generic so it can store and type in our case, it will store objects 26 00:02:09,530 --> 00:02:10,790 of type person. 27 00:02:11,250 --> 00:02:16,250 Now we need some kind of container to store the casperson objects. 28 00:02:16,760 --> 00:02:19,520 What data structure would be the best for us? 29 00:02:19,850 --> 00:02:24,380 We'll want to retrieve them by providing first and last names. 30 00:02:24,770 --> 00:02:32,360 So perhaps the best choice would be a dictionary in which to pull off two strings for both names would 31 00:02:32,360 --> 00:02:35,810 be the key, and the person object would be the value. 32 00:02:44,640 --> 00:02:51,360 I used a value to TOPO for the key, because for dictionary keys, we want to have value based equality 33 00:02:51,360 --> 00:02:52,170 comparison. 34 00:02:52,680 --> 00:02:59,820 If I use regular kepu, which is a reference type two to taphouse holding the same first and last name 35 00:02:59,940 --> 00:03:02,040 would not be considered the same key. 36 00:03:02,130 --> 00:03:09,280 Both the dictionary, so our cash would not work as expected that we wanted to keep the cash generic. 37 00:03:09,300 --> 00:03:13,260 So the dictionary archetype should also be parameterized. 38 00:03:21,480 --> 00:03:25,410 As you can see, I also admit the not no constraint. 39 00:03:25,890 --> 00:03:29,730 I did it because the dictionary keys should never be known. 40 00:03:30,330 --> 00:03:32,190 Now about the get method. 41 00:03:32,490 --> 00:03:35,760 First of all, it should take a key as a parameter. 42 00:03:37,770 --> 00:03:43,770 Remember, in our case, this key will be the we're holding the first and last name. 43 00:03:44,280 --> 00:03:48,660 We will need them to retrieve the proper person object from the repository. 44 00:03:49,260 --> 00:03:56,670 If this dictionary already stores the value of a given key, it means it already has been read and cached 45 00:03:56,820 --> 00:04:02,280 and we can simply return it without sending and the request to the external system. 46 00:04:08,600 --> 00:04:11,420 But if in this dictionary, there is no such key. 47 00:04:11,660 --> 00:04:14,090 This means the value is not yet cashed. 48 00:04:14,480 --> 00:04:17,540 We never asked for it and we never retrieved it. 49 00:04:18,050 --> 00:04:22,970 This must be the first time when someone asks for it and we need to access it somehow. 50 00:04:23,300 --> 00:04:29,600 In the case of the people controller, it would be read from the repository, but we can't do it like 51 00:04:29,600 --> 00:04:30,140 this. 52 00:04:35,380 --> 00:04:42,460 This can't work because the cash class is generic, and it must work not only for people read from some 53 00:04:42,460 --> 00:04:45,520 specific repository, but anything else too. 54 00:04:45,970 --> 00:04:52,360 In other words, we must also provide some generic mechanism for reading the values, at least for the 55 00:04:52,360 --> 00:04:55,660 first time, so they can be gun stored in the class. 56 00:04:56,230 --> 00:05:00,580 The simplest solution is to pass a funk to the get method. 57 00:05:00,910 --> 00:05:04,600 This funk will return an object of the value type. 58 00:05:04,990 --> 00:05:10,990 It will be up to the color of the get method to provide a specific method of retrieval of data. 59 00:05:11,530 --> 00:05:18,040 In our case, the people control will be using the cash and it will pass a function reading the person 60 00:05:18,040 --> 00:05:19,510 objects from the database. 61 00:05:19,690 --> 00:05:20,740 Do they get it? 62 00:05:30,830 --> 00:05:33,290 We can now simplify this code. 63 00:05:37,260 --> 00:05:40,980 What we ask for devalue under the given key for the first time. 64 00:05:41,160 --> 00:05:42,360 It is not, it clashed. 65 00:05:42,570 --> 00:05:49,590 We must it for the first time using the function that is provided as a parameter after it's read for 66 00:05:49,590 --> 00:05:53,010 the first time, we can stop it in class and return it. 67 00:05:53,520 --> 00:05:57,840 Next time, we'll ask for the value identified by this key. 68 00:05:58,110 --> 00:06:03,660 We won't need to go to the external data source will simply return the cost value. 69 00:06:04,440 --> 00:06:07,710 Let's now use the cash class in the paper controller. 70 00:06:08,130 --> 00:06:13,800 First of all, we should declare and initialize the private cash field in this class. 71 00:06:22,390 --> 00:06:29,890 Now we can use the cash in the good by name method, for now, this method doesn't use it and it goes 72 00:06:29,890 --> 00:06:33,430 to the repository every time we ask for this specific person. 73 00:06:34,000 --> 00:06:35,650 Let's try to use the cash. 74 00:06:39,520 --> 00:06:41,750 The first parameter will be the key. 75 00:06:41,800 --> 00:06:45,490 So the Tapu consisting of first and last name. 76 00:06:49,140 --> 00:06:55,830 The second parameter is a function that we allow us to access this person's data for the first stone. 77 00:06:56,190 --> 00:06:58,500 So basically what we've been doing here? 78 00:07:03,760 --> 00:07:06,370 Let's test if it works as expected. 79 00:07:06,670 --> 00:07:13,150 If it does, the good by name muttered from the repository should be called only once when we try to 80 00:07:13,150 --> 00:07:15,970 access the John Smith object twice. 81 00:07:19,250 --> 00:07:22,610 So here I am trying to access the same person twice. 82 00:07:23,120 --> 00:07:25,310 Let's put the breakpoint in the repository. 83 00:07:28,250 --> 00:07:32,240 If everything works correct, we should hit this breakpoint only once. 84 00:07:35,590 --> 00:07:42,730 So here is the first and hopefully the only time when we reach to the repository, let's click continue. 85 00:07:44,930 --> 00:07:45,980 And that's it. 86 00:07:46,280 --> 00:07:53,480 We didn't see this break point for the second dome, which means the cached value has been used in a 87 00:07:53,480 --> 00:07:54,920 real world application. 88 00:07:55,070 --> 00:08:02,000 We could ask for John Smith hundreds of times and instead of asking the database for his data, this 89 00:08:02,000 --> 00:08:08,780 many times will only ask once we implemented a super simple cache ourselves. 90 00:08:09,350 --> 00:08:12,620 Of course, we could make this cache more complex. 91 00:08:13,130 --> 00:08:20,210 For example, we don't ever remove anything from the cache now, and it may happen that during the execution 92 00:08:20,210 --> 00:08:27,050 of the program, it will grow extremely big and will finally drain our application of free memory. 93 00:08:27,740 --> 00:08:34,010 Usually, some kind of clean up mechanism is added that removes the data that is older and then some 94 00:08:34,010 --> 00:08:35,030 specific time. 95 00:08:35,330 --> 00:08:41,120 Also, this cache is not thread safe, so it shouldn't be used in multi-threaded applications. 96 00:08:41,870 --> 00:08:46,880 There are, of course, some existing libraries that provide the caching mechanisms. 97 00:08:47,240 --> 00:08:53,510 For example, we could use Norgaard to install Microsoft Extensions Caching Memory Package. 98 00:08:53,960 --> 00:08:57,560 It works very similarly to the cache we implemented. 99 00:08:57,950 --> 00:09:03,530 This is how people control would look like if we used Microsoft's implementation of the cache. 100 00:09:05,630 --> 00:09:12,260 As you can see, it's almost exactly the same as our cold, and I highly recommend using this package. 101 00:09:12,710 --> 00:09:19,310 Nevertheless, I wanted to show you how to implement a cut on our own so you understand how it works 102 00:09:19,310 --> 00:09:23,630 under the hood from other cooking tools you should be aware of. 103 00:09:24,020 --> 00:09:28,100 One of the most commonly used third party tools is called release. 104 00:09:28,460 --> 00:09:34,670 It provides more functionality than a regular cash, and it's known for its excellent performance. 105 00:09:35,360 --> 00:09:39,320 Before we wrap up a word of caution, caching is great. 106 00:09:39,380 --> 00:09:46,580 But for some scenarios only if we don't retrieve the data identified by the same key repeatedly, but 107 00:09:46,580 --> 00:09:49,010 we keep using different keys all the time. 108 00:09:49,280 --> 00:09:51,080 It doesn't really give us anything. 109 00:09:51,500 --> 00:09:56,960 You can always check cache success rate by adding a simple field to cache. 110 00:10:05,700 --> 00:10:11,670 This counter will be incremented each time we use the cash, the data instead of retrieving it from 111 00:10:11,670 --> 00:10:12,750 the data source. 112 00:10:13,110 --> 00:10:17,670 You can track its value during debugging and see if your cash is successful. 113 00:10:18,060 --> 00:10:23,130 The higher the counter goes, the better your cash is performing in your application. 114 00:10:23,640 --> 00:10:26,580 So use caching when it really makes sense. 115 00:10:27,300 --> 00:10:33,720 Caching is most often used to retrieve data from some external sources, but remember that even the 116 00:10:33,720 --> 00:10:36,390 data are calculated locally can be cached. 117 00:10:36,720 --> 00:10:43,530 For example, if your program does some performance costly mathematical or graphical operations that 118 00:10:43,530 --> 00:10:50,670 take a lot of time, you could consider cashing those results to also remember that the underlying data 119 00:10:50,760 --> 00:10:54,540 can change after it has been first retrieved by the cache. 120 00:10:54,960 --> 00:10:58,740 It means the cache will be providing us with stale data. 121 00:10:59,100 --> 00:11:03,750 That's why caching is best when the underlying data doesn't change often. 122 00:11:04,230 --> 00:11:10,050 In this case, it's usually enough to have some mechanism that removes the piece of data from the cache 123 00:11:10,170 --> 00:11:12,690 after some specific time has passed. 124 00:11:13,290 --> 00:11:18,540 During the interview, you could be asked What are the benefits of using caching? 125 00:11:19,080 --> 00:11:26,220 Caching can give us a performance boost if we repeatedly retrieve data identified by some key. 126 00:11:26,640 --> 00:11:33,390 It can help not only with data retrieved from an external data source, but even calculated locally. 127 00:11:33,570 --> 00:11:39,570 If the calculation itself is heavy, for example, it is some complex mathematical operation. 128 00:11:40,260 --> 00:11:43,110 What are the downsides of using caching? 129 00:11:43,620 --> 00:11:46,200 Cache occupies the applications memory. 130 00:11:46,470 --> 00:11:53,340 It may grow over time, and some kind of cleanup mechanism should be introduced to avoid out of memory 131 00:11:53,340 --> 00:11:54,240 exceptions. 132 00:11:54,720 --> 00:11:59,310 Such mechanisms are usually based on the acceleration time of the data. 133 00:11:59,790 --> 00:12:05,850 Also, the data in the cache may become stale, which means it is charged at the source. 134 00:12:06,030 --> 00:12:09,600 But the old version is cached and used in the application. 135 00:12:09,990 --> 00:12:15,840 Because of that, testing is most useful when you're doing data that doesn't change often. 136 00:12:16,350 --> 00:12:18,510 All right, that's it in this lecture. 137 00:12:18,810 --> 00:12:21,990 Thanks for following along and see you in the next one.