I have shown a more advanced approach to using the Repository Pattern in the Post: The Repository Pattern isn’t an Anti-Pattern; You’re just doing it wrong. Now, let me address the other typical concerns.
Typical arguments are going to be around these factors:
I find these arguments pretty lackadaisical. Anyone misusing a pattern with a bias can come up with a talking point for each one of those.
Concern #1 – It limits EF/ORM
It doesn’t have to. Its a pretty hard headed statement to say Repository only. It should be Repository First. If what you are trying to achieve needs something from your ORM specific expose it.
Don’t expose it from your Framework.Data.dll which contains the the Repository Pattern though. Make it extension methods or something specific in Framework.Data.EF.dll. This way if you ever change the implementation and remove that dll, you will get errors everywhere that used something custom.
This gives you a high level of re-usability between ORMs if you were ever to switch. Although, I couldn’t imagine I can see that happening anytime soon. I did although believe in many frameworks that are now completely deprecated.
Concern #2 – Queryable Vs Enumerable
Some Repository patterns will return Enumerables due to the desire to be flexible with other frameworks. This causes them to be slow and inefficient. Just return Queryables, you can always use .AsQueryable() on an Enumerable if needed.
Concern #3 – Domain Driven Design
I did not cover this specifically, and may cover this in the future. Repositories are built off of the Entities, but a true business layer would return domain objects. In my opinion, the business layer needs tools to use the Repositories and help you adapt to your domain objects. Using tools such as AutoMapper can adapt the domain objects coming in, and can project the objects with-in the query coming out.
Projection is something developers usually don’t use, but is extremely powerful. Using a projection, you can select your domain object directly from the query eliminating the need to even materialize the entity in the data layer. I personally do not like AutoMapper’s default for this, and usually will write my own custom expression tree to achieve this.
Concern #4 – Additional Complexity
This is a legitimate concern, but the larger the project you are doing the more it makes sense. If you’re working for a start-up then don’t worry about patterns.
What’s complexity to me is constantly using multiple steps to do CRUD operations, not centralizing common code and manually having to apply conventions through-out your code.
I was on a project and approaching the end of development. The BAs stated they needed a new functionality that they forgot to ask for. It was that anytime for any table a SSN was changed, we needed to insert a row into a table an trigger a batch operation overnight. SSN was used in a couple dozen tables, we already had 10 million lines of code that already have been QA tested.
This was a simple to add this feature, and I was told in the past similar projects it took months to add this feature. It took a day with this pattern. The code was decoupled and centralized.
Concern #5 – Querying multiple tables
If you are using Queryables out of your repositories, there is no reason why you cannot join or use multiple repositories in a single query. This is an implementation concern or design. The repository pattern does not stop you from doing this.
Concern #6 – I’m never going to change my DB or ORM
I wish my crystal ball was that clear. If you own your company, if you have a strong foot hold over technology in your company maybe you can make that claim with some certainty.
I was consulting to a client. First thing we did was a database evaluation: Postgres vs Sql Express. We landed on Sql Express. 75% into development we released our first installer, yes a thick client. The complaints started coming in. This takes too long to install, the file size is too big, etc.
I brought in a two core 1.3Ghz netbook, because legit we couldn’t find a machine close to our minimum spec. I turned off one core, and installed the application on it: 2 minutes.
“Well it took 10 minutes on mine”, said the PO.
Well stop looking up porn on your work computer, I thought.
The PO continued his debate, “Well the file size is too big, we need people in remote areas using 56k modems to be able to download it.”
The file size was 300MB. I took a deep breath, “Don’t you already ship out CDs to those places?”
After days of back and forth I finally nailed down the real problem. One of their clients refused to accept a product with Sql Express, and there was no talking them out of it. The PO was trying to blame the tech team and save face.
We tested several different types of databases since they also had a ridiculous security requirement of entire database encrypted at rest. All of this was possible because of the Repository pattern, and the switch was actually pretty lightweight in the end. So don’t tell me no-one ever change their database, it was the bane of my existence for a month. This entire episode happen in 2017, 56k modems and P3 1Ghz minimum spec.
What I know is, this pattern has been blacklisted by most, but I believe that is because of their past implementations. Most will skim this, discount it prematurely with bias, and not understand the underlining purpose.
The Repository Pattern is on the edge of death. Not because it couldn’t work, because so many people have added their own constraints to the pattern and failed to step back and solve the problems. The problems really are not hard to solve.
Are the tech “Gurus” we are listening to creating the best content for us? Most say something is bad because of abc, my implementation was junk, etc. They recommend another approach, but never evaluate solving their problems. Let’s just always move to the next shinny thing. That logic to me is toxic, cause who is to say the next shinny thing won’t have it’s problems that won’t be addressed.
If you are doing the Repository Pattern and like that style, don’t adapt everything here. I wrote this as an example. Their maybe concepts here that can help you. If you want to know more about how I solved these problems in the past, I can create some more code for you.
In Part 3 I address Retrospective and Clarification.