Click here to Skip to main content
15,887,175 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am trying to overcome some kind of disorder. Let's assume we have the next project structure:
C#
ZooProject
	Animals (folder)
		Ape.cs (class)
		Bear.cs (class)
		Cow.cs (class)
		IApe.cs (interface)
		IBear.cs (interface)
		Ibex.cs (class)
		ICow.cs (interface)
		Iguana.cs (class)
		IIbex.cs (interface)
		IIguana.cs (interface)
		IImpala.cs (interface)
		IInsect.cs (interface)
		Impala.cs (class)
		INarwhal.cs (interface)
		Insect.cs (class)
		IOwl.cs (interface)
		ISnake.cs (interface)
		Narwhal.cs (class)
		Owl.cs (class)
		Snake.cs (class)

//Namespace
namespace ZooProject.Animals
{
}

Instead of Animals we can put Entities for Data Access Layer or Models for Business Logic Layer.

The problem is classes rotate with interfaces so there is a mixed unordered "ugly-something".

What I have tried:

* Moved to separate namespace
C#
namespace AnimalInterfaces
{
	// all interfaces
}
namespace Animals
{
	// all classes
}

Problem #1: I suppose the convention when both interface IX and class X should be in the same namespace is considered among developers the only true. Besides, there are many examples in standard sources where they are in the same namespace (e.g. Dictionary and IDictionary in System.Collections.Generic).


* Moved to separate folder or even project (e.g. ".interfaces", "Interfaces", "AnimalInterfaces")
C#
ZooProject
	Animals
		.interfaces
			IApe.cs
			IBear.cs
			ICow.cs
		Ape.cs
		Bear.cs
		Cow.cs

Problem #2: a common convention in many software development projects is to organize folders and namespaces in a consistent and aligned manner. Here we return to problem #1.

Question #1: Which way/convention do you prefer most and why?

Question #2: Do you even create an interface for each class like these ones?
C#
CowEntity / ICowEntity
CowStorage / ICowStorage
CowModel / ICowModel
CowService / ICowService

And what namespaces/folders contain them?

Question #3: So if you store interfaces separately from classes, how do you do that? Or what can you advice?
Posted
Comments
PIEBALDconsult 5-Mar-24 18:31pm    
I think the plot was back that way.
Graeme_Grant 5-Mar-24 18:40pm    
The answer is it depends. It depends on the type of application, size, etc. For a small application, it does not matter.
[no name] 6-Mar-24 14:12pm    
If you're near the "end of a project", these are good questions and allow for refactoring. If you're still in development, you're feelings will change and doing this type of refactoring may be premature. The longer one works on a project, the deeper the understanding of the "subject matter".

We can't really answer that because it depends on so many details about the project: the size, what the interfaces do, and so forth.
But I suspect that you are overthinking this - the organisation of the project files should reflect the usage of the file content, not the type. So separating all your interfaces off into a folder called "Interfaces" and your structs into another called "Structs" may make it easier to find when you are looking for "what the heck can I use" but doesn't really help with understanding the project. Similarly, adding namespaces just to separate them doesn't really do anything useful.

Since classes and interfaces tend to be very interrelated (understandably, interfaces are useless without classes to implement them!) it's probably better to organise things in groups (by folders, by namespaces, or both) according to what they actually relate to: "Animals", "Vegetables", and "Minerals" for example.

As the projects get bigger, they do need more rigorous organisation, but that's generally achieved by splitting the solution into multiple projects which can act as "black box" references instead of file / namespace level. My general rule is "one project, one namespace" - though I do break that on occasion!
 
Share this answer
 
Comments
RuthWa 6-Mar-24 14:47pm    
I know that files must be structured according to content logic. I'm talking about the case where further grouping is not possible. And even in that case, I still feel bad when I see different or even chaotic order of files.

But anyway, thanks for the answer. I appreciate it.
I'll invert the question and ask, why do you need so many interfaces? Whenever I see people using interfaces, the question I have is, what purpose does this serve you? Normally, people say that they use interfaces to support testing so that they can swap out implementations and mock the interface. The interesting thing about this is, a lot of the time this is theoretical because they don't have any tests. Another reason for using an interface is that it provides an abstraction for something with multiple implementations. Again, this is intereresting because it's rare for people to create code that needs multiple implementations. Now, there are places where interfaces are useful - if you're writing an API for others to use, there may be places for them, but how often is that the case?

The problem seems to arise because Microsoft documentation and guides are littered with interfaces and it has become the norm to accept that this is what people should do. Where this is especially apparent is in documentation around IoC containers. We often see something like services.RegisterSingleton<IDog, Dog>();. The funny thing is, it's just as easy to do services.RegisterSingleton<Dog>();. Then, when you need a dog instance, you are just accept Dog in the constructor.

I mentioned that interfaces were justified by people saying they needed to swap out implementations for testing. If you don't have an interface, how do you do this? The answer is to use (where possible), virtual methods and inheritance where needed. As an example, suppose I want to mock the behaviour of a method that accepts a (for the purposes of this example a completely made up) RulesProviderEngine. What might this look like? Let's look at our method first.
C#
public async Task<ValidationRulesResults> InvokeValidationAsync(RulesProviderEngine engine, string ruleset)
{
  var results = await engine.ExecuteRulesetAsync(ruleset);
  Logger.LogInfo(results.ToJson());
  return results;
}
To mock this, we could simply do this (assuming that ExecuteRulesetAsync is virtual).
C#
public class MockRulesProviderEngine
{
  public List<ValidationRulesResults> ExpectedResults = ValidationRulesResults.Empty;
  public override Task<ValidationRulesResults> ExecuteRulesetAsync(string ruleset) => ExpectedResults;
}
Then, when you're testing, simply substitute the mock instance with the real one like so:
C#
var results = new ValidationRulesResults();
var engine = new MockRulesProviderEngine();
var results = await myImplementation.InvokeValidationAsync(engine, " someruleset");
assert.equals(validationrulesresults.empty, results);
So, going back to my original question. Why do you think you need interfaces? Think about the code you're writing and really think hard about whether you need an interface or not.
 
Share this answer
 
v2
Comments
RuthWa 6-Mar-24 14:37pm    
I thought it is necessary to use interfaces for "Tight Coupling between classes" avoiding. Especially since I encountered many articles which state how decoupling is vital.

At least, I can see now the approach "ICat -> Cat; IDog -> Dog" is disputed. As an inexperienced beginner before, I asked myself, why do I really need the Interfaces here. Now I came to the same point.
RuthWa 7-Mar-24 2:24am    
I understand the "services.RegisterSingleton<IDog, Dog>();" line. But on the other side it is not clear for me what the line "services.RegisterSingleton<Dog>();" is supposed to do. Why can't we just use Dog class without registering it?
Pete O'Hanlon 7-Mar-24 3:11am    
You can use Dog without registering it - I was just demonstrating that you didn't need to create an interface just to register a concrete type in the container.
RuthWa 7-Mar-24 5:35am    
Okay. Thank you for the clarification an for the answer.
Pete O'Hanlon 7-Mar-24 6:37am    
It was my absolute pleasure.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900