Last Updated: May 27, 2020
·
4.732K
· sohape

File nesting with interfaces

Mads Kristensen created yet another extension to Visual Studio. This one is called File Nesting, and can be found here.

Essentially it allows you to nest files under each other in the Visual Studio solution explorer. This modifies the csproj file, specifying that the nested file depends on the other file. This is useful for nesting related files, to keep the solution explorer free from clutter (or at least cut down on the clutter). The examples he use is to nest minified JavaScript files under their non-minified source. This makes perfect sense, as you normally do not need to poke around in the minified files.

The first thing I thought about when seeing this new extension was if I could use it to nest implementations under their interface. This might sound like a bad idea to you, and I can not make up my mind if I want to do it or not.

Because I use a lot of dependency injection in my code I end up with a lot of loosely coupled "service" classes. Each of these classes implement an interface, and so I have two files pr "service". I usually like to group those two files in a folder, to keep them together in the solution explorer, like this:

list of my services folder structure

However this poses a few minor problems:

  • I get a lot of folder clutter
  • I get more complicated namespaces

Both of these issues are of course just small annoyances - but the File Nesting extension has been created exactly for avoiding these small annoyances.

So using File Nesting I can avoid the extra folders, and instead my solution explorer looks like this:

list of nested services collapsed

The actual implementation is now nested under each of the interfaces, so if you want to navigate to it in solution explorer, then you have to expand on the interface:

one service interface expanded

Navigating to the implementation using Visual Studio or ReSharper shortcuts still work in the same way (Ctrl+T (Visual Studio shortcut scheme), or Ctrl+N (IntelliJ IDEA shurtcut scheme)).

What do you think of this approach? - Is it a bad practice, or do you like the idea of getting a smaller solution explorer?

10 Responses
Add your response

I never understand tightly coupling interfaces with concrete implementations in the same project, so I'd say bad practice, but that's just me. :)

over 1 year ago ·

@stevenbey, I completely understand your viewpoint, and that is also why I am hesitant to use it everywhere. However there is nothing in the code that makes them tightly coupled, it is only the appearance in the solution explorer. In that respect, my previous way of structuring, using folders, looks just as bad I guess?

What structuring do you use? - I think it is often overkill to put interfaces in their own assembly, especially when you, like me, use interfaces everywhere. But, I am very interested to hear about other approaches :)

over 1 year ago ·

If you only have one implementation of an interface, why would you ever induce the complexity of debugging and following code logic? DI and IOC are useful tools in some scenarios, however using them for the sake of using them like this is just a waste of time and effort.

over 1 year ago ·

@jameshancock10 I respectfully disagree. It is true that most of the interfaces I make only ever get one implementation for production code, however they get mocked or stubbed for unit testing. Splitting up the code into small reusable parts makes it much easier to write unit tests, and I would argue that it also makes the code much easier to maintain. This adheres to the SOLID principles: http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)

over 1 year ago ·

I've worked on these projects where this is done. What you get is code that you can't ever discover what's going on because when you right click and go to definition you get an interface and can't find the implementation that is going to actually execute. If there is one, all you've accomplished is to make debugging and finding code MUCH harder.

This makes new team members and people that have to maintain your code have A HUGE LEARNING CURVE and basically makes your code impenetrable.

Worse, doing Unit Tests based on mocked/stubbed functions defeats the concept of "unit tests"

So again, you're looking for a solution caused by a problem that should never exist.

DI and IOC work well for plugins. I.e. functionality where you need to blind call on an interface and have it point to something that was dynamically loaded.

If that's not the problem you're solving, then you're missing the point and causing yourself a ton of extra work and making your project incredibly hard to maintain for absolutely 0 benefit (And if your reason for doing something that makes all of your coding and maintenance vastly harder is to make testing easier, then you've just shot yourself in the foot.)

over 1 year ago ·

@jameshancock10 I respect your opinion, but I do not agree with you. I think code that adheres to the SOLID principles is MUCH easier to maintain than code that doesn't. I have worked with both as well. If you do not split up your classes and functions, then you end up with very large functions and very large classes. This makes it difficult to keep your code DRY, and it makes it difficult to see what is going on.

You argue that it is difficult to find the classes that implement an interface - I do not agree, Visual Studio or ReSharper can do that for you. With the approach I have described in this blog post it should be very simple to find the implementation for an interface since it is nested under the interface in the solution explorer.

You argue that mocks and stubs are not for unit tests - again I do not agree. Mocks and stubs are made exactly for unit tests. In a unit test you are only interested to test a very small part of your code - one function, or possibly only part of a function. You do not want to test your dependencies in a unit test, so you mock them.

So, using dependency injection is a no brainer for me, but that was actually not the topic of this blog post :)

over 1 year ago ·

@vincpa I understand the reason but thanks.

over 1 year ago ·

@sohape my use of the phrase 'tightly coupled' may have been slightly erroneous but what I meant was that, even if you don't use the concrete class (e.g. when mocking/stubbing the interface for your tests), it's always 'there' (in the library). I know this is a little OCD but, like I said, that's just me.

I completely agree with you concerning interfaces in their own project. I've seen so many examples of it and it drives me crazy (to the point of frothing at the mouth ;).

I structure solutions with a 'base' project and then implementation projects. The 'base' project contains all of the entities that are used in the application and has a folder structure that reflects the application's architecture. It also contains the interfaces for the application. For example:

Data/
IRepository
IUserRepository
Commands/
ICommand
IUserCommand
Services/
IService
IUserService
IFileBundleService
IFileReaderService

Then, I name the implementation projects to follow the folder structure (e.g *.Services or *.Commands) or, where appropriate, with the technology that they're using (e.g. *.Data.SqlClient).

Of course, YMMV =)

over 1 year ago ·

@stevenbey Thanks for getting back to me :)

That sounds like an interesting approach. I don't suffer from the same OCD as you though, so I don't have a problem with the classes being there. However, I am open for trying other approaches, so I might give your approach a try in my next project - thanks!

over 1 year ago ·

@vincpa Nice to know - thanks!

I agree - this is a team decision, but it is also nice to get input from outside the team :)

over 1 year ago ·