5

I have implemented Repository pattern with Unit of work but have some architectural issues.

For example, lets say I am creating a used car parts online store. While I have operations on my DB I also have operations I need to perform on remote API's from different scrap yards e.g. need to run searches, availability updates and more...

I decided to try unit of work and repository pattern

Did things mostly like Mosh Hamedani but for asp.net core 2.1 From videos like this one

Unit of work and repositories work OK and make sense so long as I am using EF(or something else to communicate with DB) but it doesn't make much sense if I am to get some of the data trough different web apis. (e.g. getting list of cars on the market from different APIs whose handling and retrial is similar but different - I am retrieving different implementations of the same interface by key)

First I don't like the fact that I have all instances for all repositories inside my unit of work but need only one in most of the cases. I know it helps to reuse context transaction without wrapping it in my own but still its silly having unnecessary instances.

Second Should I implement retrieval logic and handling for remote api's also inside a repository and unit of work or maybe ditch unit of work and do something else? Keep just repositories? (Someone once mentioned facade pattern which I'm not familiar with)

I tend to overengineer things and right now I'm very confused. Any insight is helpful.

Dino
  • 161
  • 1
  • 13

3 Answers3

5

The repository pattern serves just one purpose: abstracting SQL from your application code. The unit of work pattern exists simply to support and coordinate transactional operations with multiple repositories. EF and other ORMs handle all this for you. Specifically with EF, each DbSet is a repository and the DbContext is the unit of work. When you use an ORM like EF, that is your data layer, rather than some custom class library you might have traditionally created. You should absolutely not be implementing the repository/unit of work patterns on top of something like EF.

What you're looking for essentially an API gateway. In microservice architecture, each service deals with one discrete unit of functionality, which means a cross-cutting application that uses many if not all of these microservices would have a ridiculous amount of dependencies. The most typical approach is creating one or more API gateways, which essentially package up communication with all or a particular subset of your microservices. Your application talks directly to the API gateway only, and the API gateway coordinates communication with all the microservices necessary to facilitate the application's request. This further allows you implement layers like a message queue in a seamless way.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • Makes sense, I heard of it but never got the time to follow up on it till now. **Do you know where would be best to start?** Like links, videos, examples? I am a self thought dev so my knowledge is a bit unstructured with gaps which is why I'am trying to fill it as I go and I guess now is the time for micro service architecture. You helped me a lot Chris so thank you very much and I don't mean just on this question but on a couple others over the years. – Dino Jul 30 '18 at 21:41
  • _You should absolutely not be implementing the repository/unit of work patterns on top of something like EF_ - EF should be implementation details of repository your business layer declared. You definitely don't want to implement whole bunch of `DbContext/DbSet` if you decide to keep data in some xml files or put database behind some web API for example. – Fabio Jul 30 '18 at 21:59
  • Ok, I have read upon the micro service architecture and watched a couple of videos a little bit last night but it looks like more work and a little bit overkill for a small application? Am I missing something? As I understand I would need to separate functionality in standalone services that are able to function independent of each other then I would need to provide authentication service which would work as identity provider or something and somehow authenticate user on all of them which I am not entirely sure how to do it. Then there is also docker... Maybe I am overthinking things? – Dino Jul 31 '18 at 07:29
  • Simply, yes. However, you can follow the *spirit* of microservices without necessarily going all the way. First, authentication is only necessary if they're publicly exposed. If you keep them all behind your internal firewall and especially if the app is only communicating with the gateway and not each individual service, they don't necessarily need an authorization layer. Even then, you wouldn't authorize an individual user at each microservice, but rather a client (i.e. your application). You'd bestow the app a client id and secret, and then it would use that to authorize its requests. – Chris Pratt Jul 31 '18 at 18:01
  • Lastly, you can start small, creating this infrastructure basically just in code. In other words, each microservice may just be a class with methods mimicking what would be API endpoints on a real microservice. Your API gateway, likewise could also just be a class that takes the "microservice" classes as depdendencies and wraps them in a neat bow for the application's purposes. As long as you follow the design philosophy of microservices, this will lead to neatly ordered and abstracted code, and if you eventually do create full-fledged microservices, it will be much easier starting from there. – Chris Pratt Jul 31 '18 at 18:05
  • @chris-pratt So you are suggesting I could make a monolithic architecture but with the micro services in mind? That I should use a variant of service pattern where services would be like classes with abstraction for decoupling and are targeting business processes like micro services do. Setup like this would clearly indicate where is it going and what is it trying to become and when I decide to transition to full micro services architecture later on it would be much easier. I basically repeated what you said but I wanted to be sure I understood everything. Can you confirm? – Dino Jul 31 '18 at 23:14
  • Yep, that's the idea. Even a step in the right direction is better than nothing. – Chris Pratt Aug 01 '18 at 12:50
2

Though I agree with answer from Chris Pratt, I think it is necessary to create repositories in some cases even though you are using ORM like EF. I have explained this in details here.

With your question, I suggest you should continue with UoW and Repository as you are doing so far. As mentioned here UoW is more than transaction. EF implements this perfectly for you if you properly use DbContext.

About problems involving APIs from other sources in current repository and UoW, it should be separate. I suggest you create separate wrapper for consuming complexity of third party APIs. Call this anything you want; repository or External Api Wrapper or whatever...

Amit Joshi
  • 15,448
  • 21
  • 77
  • 141
  • I guess we had a similar idea. Ditched "unit of work" but retained repository because i like the granularity. Also wanted to control instances and transaction only when needed. Separated the remote API handling to a separate independent service and with abstraction made it look like an API. So now it looks like this e.g. `_vendorAPIManager.GetVendor(Vendor.JacksScrapyard).GetSaleItems()` – Dino Jul 31 '18 at 13:12
  • We both had a similar idea which is not bad at all but I'll have to go with Chris's idea as the accepted answer. Even though Chris's "start small" idea is in a way identical to ours, its trying to become much more at later stages whereas our would stay monolithic and his not. Thanks for everything I appreciate it. – Dino Jul 31 '18 at 23:40
0

I used the same Course and implemented my Unit of Work... but later, I changed my mind and removed the UoW class. DbContext is already implementing UoW & Repository patterns: From MS Documentation

DbContext Class

Represents a combination of the Unit-Of-Work and Repository patterns and enables you to query a database and group together changes that will then be written back to the store as a unit. DbContext is conceptually similar to ObjectContext.

I still added my own repositories. I agree with Chris that DbSet is a repository, but I could add more specialized methods by adding my own repositories.

In the video that you have linked, we are implementing UoW by putting all the repositories inside the UoW class. In my opinion this implementation is potentially violating some of the SOLID principles:

  1. It feels like we are violating Open/Closed Principle... because every time we add a new repository, we need to modify the UoW class to include the new Repository.
  2. It feels like we are violating Interface-Segregation Principle. ISP states that clients should not be forced to implement interfaces they don't use. The UoW contains an implementation of all the repositories... but then a consuming client does not need all these implementation, the client would probably just need one of them.
  3. It feels like we are violating Single Responsibility Principle, as the UoW is responsible for so many repositories.
Hooman Bahreini
  • 14,480
  • 11
  • 70
  • 137