fixed typo
Source Link

Now, let's take a look at each principle with the understanding that while they may sometimes pull in different directions, they are by nowno means inherently in conflict.

YAGNI was conceived to help developers avoid a particular kind of rework: that which comes from building the wrong thing. It does this by guiding us to avoid making errant decisions totoo early based on assumptions or predictions about what we think will change or be needed in the future. Collective experience tells us that when we do this, we are usually wrong. For example, YAGNI would tell you not to create an interface for the purpose of reusability, unless you know right now that you need multiple implementers. Similarly YAGNI would say don't create a "ScreenManager" to manage the single form in an application unless you know right now that you're going to have more than one screen.

Now, let's take a look at each principle with the understanding that while they may sometimes pull in different directions, they are by now means inherently in conflict.

YAGNI was conceived to help developers avoid a particular kind of rework: that which comes from building the wrong thing. It does this by guiding us to avoid making errant decisions to early based on assumptions or predictions about what we think will change or be needed in the future. Collective experience tells us that when we do this, we are usually wrong. For example, YAGNI would tell you not to create an interface for the purpose of reusability, unless you know right now that you need multiple implementers. Similarly YAGNI would say don't create a "ScreenManager" to manage the single form in an application unless you know right now that you're going to have more than one screen.

Now, let's take a look at each principle with the understanding that while they may sometimes pull in different directions, they are by no means inherently in conflict.

YAGNI was conceived to help developers avoid a particular kind of rework: that which comes from building the wrong thing. It does this by guiding us to avoid making errant decisions too early based on assumptions or predictions about what we think will change or be needed in the future. Collective experience tells us that when we do this, we are usually wrong. For example, YAGNI would tell you not to create an interface for the purpose of reusability, unless you know right now that you need multiple implementers. Similarly YAGNI would say don't create a "ScreenManager" to manage the single form in an application unless you know right now that you're going to have more than one screen.

Source Link

The question presents a false dilemma. Proper application of the YAGNI principle isn't some unrelated thing. It's one aspect of good design. Each of the SOLID principles are aspects of good design as well. You can't always fully apply every principle in any discipline. Real-world problems put a lot of forces on your code, and some of those push in opposing directions. Principles of design have to account for all of those, but no handful of principles can fit all situations.

Now, let's take a look at each principle with the understanding that while they may sometimes pull in different directions, they are by now means inherently in conflict.

YAGNI was conceived to help developers avoid a particular kind of rework: that which comes from building the wrong thing. It does this by guiding us to avoid making errant decisions to early based on assumptions or predictions about what we think will change or be needed in the future. Collective experience tells us that when we do this, we are usually wrong. For example, YAGNI would tell you not to create an interface for the purpose of reusability, unless you know right now that you need multiple implementers. Similarly YAGNI would say don't create a "ScreenManager" to manage the single form in an application unless you know right now that you're going to have more than one screen.

Contrary to what many people think, SOLID is not about reusability, genericity, or even abstraction. SOLID is intended to help you write code that is prepared for change, without saying anything about what that specific change might be. The five principles of SOLID create a strategy for building code that is flexible without being overly generic, and simple without being naive. Proper application of SOLID code produces small, focused classes with well-defined roles and boundaries. The practical result is that for any needed requirements change, a minimum number of classes need to be touched. And similarly, for any code change, there is a minimized amount of "ripple" through to other classes.

Looking at the example situation you have, let's see what YAGNI and SOLID might have to say. You are considering a common repository interface due to the fact that all the repositories look the same from the outside. But the value of a common, generic interface is the ability to use any of the implementers without needing to know which one it is in particular. Unless there is somewhere in your app where this would be necessary or useful, YAGNI says don't do it.

There are 5 SOLID principles to look at. S is Single Responsibility. This says nothing about the interface, but it might say something about your concrete classes. It could be argued that handling the data access itself might best be made a responsibility of one or more other classes, while the repositories' responsibility is to translate from an implicit context (CustomerRepository is a repository implicitly for Customer entities) into explicit calls to the generalized data access API specifying the Customer entity type.

O is Open-Closed. This is mostly about inheritance. It would apply if you were trying to derive your repositories from a common base implementing common functionality, or if you expected to derive further from the different repositories. But you're not, so it doesn't.

L is Liskov Substitutability. This applies if you intended to use the repositories through the common repository interface. It places restrictions on the interface and implementations to ensure consistency and avoid special handling for different impelementers. The reason for this is that such special handling undermines the purpose of an interface. It might be useful to consider this principle, because it may warn you away from using the common repository interface. This coincides with YAGNI's guidance.

I is Interface Segregation. This may apply if you start to add different query operations to your repositories. Interface segregation applies where you can divide the members of a class into two subsets where one will be used by certain consumers and the other by others, but no consumer will likely use both subsets. The guidance is to create two separate interfaces, rather than one common one. In your case, it's unlikely that fetching and saving individual instances would be consumed by the same code that would do general querying, so it might be useful to separate those into two interfaces.

D is Dependency Injection. Here we come back to the same point as the S. If you separated your consumption of the data access API into a separate object, this principle says that rather than just newing up an instance of that object, you should pass it in when you create a repository. This makes it easier to control the lifetime of the data access component, opening up the possibility of sharing references to it between your repositories, without having to go the route of making it a singleton.

It's important to note that most of the SOLID principles don't necessarily apply at this particular stage of your app's development. For example, whether you should break out data access depends on how complicated it is, and whether you want to test your repository logic without hitting the database. It sounds like this is unlikely (unfortunately, in my opinion), so it's probably not necessary.

So after all that consideration, we find that YAGNI and SOLID actually do provide one common piece of solid, immediately-relevant advice: It's probably not necessary to create a common generic repository interface.

All this careful thought is extremely useful as a learning exercise. It's time consuming as you learn, but over time you develop intuition and becomes very quick. You'll know the right thing to do, but don't need to think all these words unless someone asks you to explain why.