I have done exactly what you showed here for several years and I have always called it a decorator. I see your point about the difference between the 2 patterns and despite the fact that theoretically there's a difference, I guess most ppl will continue to call it a decorator. Now I would like to give you and idea and challenge you to go to the next level, can you show how to implement a repository with selective caching as well as cache invalidation scenarios but also putting in place a nosql or search index. The idea is, some calls go directly to the db, no cache, no index, others have caching only, no invalidation, others do have invalidation and finally also those that talk to the search Index every time there's a change. I have done a few things like that myself but I would like to know and learn from you. Thanks for the video, even though this is common in the industry it's always important to ask ourselves why we do it. 👍
Thanks for the video! How does this work when you come to unit test the cached version ? You'd need to make an abstract base class so you can mock it out or use the real inner ProductRepository right?
@@Tamer_Ali Depends. It's tricky. Especially if you have filters. However, sometimes, having the first page cached can be useful to improve the user experience.
Risk of using both implementations is when you need to invalidate cache. E.g. you use the db implementation to update a record, yet the cahed implementation will still return the old record
Hey Gui, what about situation when one of the methods is reusing another one from repository/service? I have a situation whehre one method is taking data from an external API (huge amount unfortunately, corpo style -_-) Another one is about to search one specified case out of the whole set, so instead of asking the API I would prefer to use the cached one if it is already cached. Both methods are in the same class, so how can I call the cached service/cached data from the implemented service?
Are they in the same class and part of the same interface? Can you have the Proxy do that? So, the second method can search the cache, if it's not there, check the first method's cache, if still can't find it, ask the API?! Does it make sense?
How do you invalidate the memorycache if the record is obsolete? I would like to reduce the database calls. Does a facade pattern mixed with proxy a possible solution for this?
Nice explanation differentiating the decorator and proxy pattern. But consider a case where there 4 interfaces and each interface is having around 5 methods. Assuming only one method in interface can be cached. In this case, 4 new implementations should be created but only one method should be cahnged. All the remaining methods should be called from the main class. How can we avoid this case. Is there an easy way where I can just add new implementation for the method which needs caching .
Yes, you are right. The first question that I would raise, is if that interface shouldn't be segregated (the I in SOLID). The Decorator implementation can let you do that if you go through the inheritance root. refactoring.guru/design-patterns/decorator/csharp/example Not my favourite approach to be honest.
Should the cache be registered as a singleton rather than scoped? My concern is that using a scoped lifetime might result in the cache being recreated for each new logical operation within the application, which seems inefficient
I don't think most people see how important this is. Amazing thanks!
Absolutely!
I have done exactly what you showed here for several years and I have always called it a decorator. I see your point about the difference between the 2 patterns and despite the fact that theoretically there's a difference, I guess most ppl will continue to call it a decorator.
Now I would like to give you and idea and challenge you to go to the next level, can you show how to implement a repository with selective caching as well as cache invalidation scenarios but also putting in place a nosql or search index. The idea is, some calls go directly to the db, no cache, no index, others have caching only, no invalidation, others do have invalidation and finally also those that talk to the search Index every time there's a change.
I have done a few things like that myself but I would like to know and learn from you.
Thanks for the video, even though this is common in the industry it's always important to ask ourselves why we do it. 👍
Thanks for your comment.
I've cache invalidation on my list. Let me think how I would share that in a way that makes sense for this channel 😉
Love videos like this. Great explanation of the difference between the decorator and proxy pattern.
Thank you 🙇 glad you liked it
Thanks for the video! How does this work when you come to unit test the cached version ? You'd need to make an abstract base class so you can mock it out or use the real inner ProductRepository right?
Very nicely explained. Thanks!
Glad you liked it
Thanks a lot Gui. keep going
could you talk about cache invalidation in one of your upcoming videos?
Hey! It's on the pipeline 😉
@@gui.ferreira paginated list should be cached too?
@@Tamer_Ali Depends. It's tricky. Especially if you have filters. However, sometimes, having the first page cached can be useful to improve the user experience.
Risk of using both implementations is when you need to invalidate cache. E.g. you use the db implementation to update a record, yet the cahed implementation will still return the old record
That's why Caching is hard. Cache invalidation and data consistency are difficult.
Hey Gui, what about situation when one of the methods is reusing another one from repository/service?
I have a situation whehre
one method is taking data from an external API (huge amount unfortunately, corpo style -_-)
Another one is about to search one specified case out of the whole set, so instead of asking the API I would prefer to use the cached one if it is already cached.
Both methods are in the same class, so how can I call the cached service/cached data from the implemented service?
Are they in the same class and part of the same interface?
Can you have the Proxy do that? So, the second method can search the cache, if it's not there, check the first method's cache, if still can't find it, ask the API?! Does it make sense?
How do you invalidate the memorycache if the record is obsolete?
I would like to reduce the database calls.
Does a facade pattern mixed with proxy a possible solution for this?
Nice explanation differentiating the decorator and proxy pattern.
But consider a case where there 4 interfaces and each interface is having around 5 methods. Assuming only one method in interface can be cached.
In this case, 4 new implementations should be created but only one method should be cahnged. All the remaining methods should be called from the main class.
How can we avoid this case. Is there an easy way where I can just add new implementation for the method which needs caching .
Yes, you are right.
The first question that I would raise, is if that interface shouldn't be segregated (the I in SOLID).
The Decorator implementation can let you do that if you go through the inheritance root. refactoring.guru/design-patterns/decorator/csharp/example
Not my favourite approach to be honest.
@@gui.ferreira thank you for responding. Let me go through that blog
Should the cache be registered as a singleton rather than scoped? My concern is that using a scoped lifetime might result in the cache being recreated for each new logical operation within the application, which seems inefficient
Could you talk about cache stampede too if possible?
Taking note 🫡
@@gui.ferreira thanks
Which IDE is this?
JetBrains Rider :)
ruclips.net/video/wQG_LntcAQQ/видео.html
now we have dublicate methods
Why do you say that?
Thanks for this content!
Thank you 🙏