DEV Community

Kelly Brown
Kelly Brown

Posted on

C# Namespace Fever

Alright... I'm done chopping my code into microscopic namespaces. There's just no point. All it does is force a bunch of using statements all over the code (both in the project itself and in any project consuming it as a library).

The most common place I see this unhealthy obsession is in your typical ASP.NET app. Devs feel this compulsion to make a namespace for every kind of component.

namespace MyApp.Web.Controllers;
namespace MyApp.Web.Models;
namespace MyApp.Web.Services;
namespace MyApp.Web.Utils;
Enter fullscreen mode Exit fullscreen mode

And this is a kind representation. I've even seen projects isolate Models.Request from Models.Response. Personally, I do not think this is necessary or helpful. In my more recent endeavors, I've settled on just using MyApp.Web and stopping there. It gets rid of a ton of useless using statements, and all the identifiers I need are now properly visible. I still find it acceptable to put the other whole layers into separate namespaces (MyApp.Domain, MyApp.Repository, etc.).

I fell prey to this in Jawbone. I think there is just something alluring about "being as cool as the .NET base classes". Hey, .NET has a namespace for its collections, so I should have a namespace for my collections! There's just one problem, though: .NET is huge, and my library is not. When you reach a certain size, it makes sense to gently categorize various components. Also, if code exists in distinct projects, having a different namespace makes sense.

So, I've taken the first steps to wrangling this mess. I am eliminating the Piranha.Jawbone.Tools and Piranha.Jawbone.Collections namespaces. In my mind, there are only two scenarios that justify a new namespace:

  1. Strongly distinct domains: I am keeping namespaces such as Piranha.Jawbone.Sqlite and Piranha.Jawbone.Sdl. Those are highly cohesive domains that could arguably even be spun off into their own libraries if the need arose. They revolve around major native components and have clear delineation.
  2. Isolation of extensions on common datatypes: if I want to introduce extensions for common types like string or DateTime or whatever, I don't want those extensions flooding devs' autocomplete. It's polite to let them opt in by using Piranha.Jawbone.Extensions. They should not pay that price just for using Piranah.Jawbone. Meanwhile, for new datatypes introduced by Jawbone itself, the extensions just sit in the Piranha.Jawbone namespace.

Already, I am enjoying the drastic reduction in using statements.

Top comments (5)

Collapse
 
nixon profile image
Jerry Nixon

Agree to disagree. Strongly.

Collapse
 
thebuzzsaw profile image
Kelly Brown

Well don't leave me hanging. Go ahead. Let it out.

Collapse
 
nixon profile image
Jerry Nixon

I don't disagree with everything you say, of course. There is no question that namespaces, like anything, can be overused and burden a codebase more than benefiting it. I like that you frame the potential for disconnected libraries as a good justification for grouping types together in a namespace. I feel the same. I appreciate that your article focuses on code hygiene for the sake of the next developer. I think many architectural decisions overlook this important perspective, and it's a great point to make.

However, there's no denying that your overall motivation, which bookends your article in the first and last paragraphs, is to avoid the nuisance, clutter, and noise of using directives. (It's worth noting that in C#, formally, these are using directives _ and not using _statements. Though I think we've all said it both ways at times.) I mean, Kelly, you double down to the point where you even diagnose the abundance of namespaces and the collection of using directives as an unhealthy obsession. Unhealthy? How many is healthy? Who arbitrates?

Look, I acknowledge your point that breaking every type into a namespace would be ridiculous. This is especially true, as you noted, in a smaller codebase. That said, consider these three notes:

  • Unused using directives can be automatically removed through code cleanup, which is natively integrated into the IDE.
  • Your using directives can be collapsed into a single line, taking up just one line in the editor regardless of how many there are.
  • With C#'s new global using directives, you can automatically include all the directives you need in every file in a single place, hidden from view.

The main reason I prefer to err on the side of too many namespaces over too few is because I recognize their benefit in terms of discovery. You gave the example of Models.Response and Models.Request, and I would argue that this is very reasonable. Very. When you are responding, Intellisense will present to you a discrete list of models that are appropriate for the operation. Without this, you are just fooling yourself because ResponseModel or RequestModel, or something like that, would end up being part of the name in some other way - otherwise, how would you ever know which is appropriate? More importantly and to your other point, how will other developers know?

  • I strongly disagree that usings are a problem.
  • I strongly agree that namespaces can be misused.
  • I strongly disagree that lots of namespaces are unhealthy.
  • I am grateful your article got me thinking about this again.

It's okay we don't agree on this. We probably agree on a lot of other things. Your article was thoughtful, articulate, and worth my time. Don't be discouraged by this comment from me. I mean, seriously, who am I? Every developer doesn't need to be the same. Every dev team does not need to be the same. I will consider the points you made more. This would not be the first time my opinion on something is wrong. Maybe I am. Thanks.

Best of luck,
Jerry Nixon

Thread Thread
 
thebuzzsaw profile image
Kelly Brown

Hey, I appreciate the thoughtful response. I'm not the authority over all C# written everywhere! I'm just sharing my feelings. :)

However, there's no denying that your overall motivation, which bookends your article in the first and last paragraphs, is to avoid the nuisance, clutter, and noise of using directives.

Perhaps I overstated my case, but just to add some perspective here: I have worked in code bases where, upon opening a source file, you are greeted by multiple pages of using directives. (Directives! Not statements! Thanks for the correction!) Perhaps that is indicative of other problems, but I do think that a big part of the problem is the fact that the classes are sitting in way too many namespaces in a given library.

I mean, Kelly, you double down to the point where you even diagnose the abundance of namespaces and the collection of using directives as an unhealthy obsession. Unhealthy? How many is healthy? Who arbitrates?

Who arbitrates? Me! It's my blog! My opinion is king here! But in all seriousness, I call it unhealthy because it's a simple case where I feel the actions cannot be reasonably justified. I feel like people do it only because they have seen other people do it.

With C#'s new global using directives, you can automatically include all the directives you need in every file in a single place, hidden from view.

This is a separate discussion. Despite what I've written here, I don't like global using directives and feel that it largely defeats both our points. I actually like seeing what other namespaces a given source file explicitly accesses; I just think that one namespace (give or take) per library is enough.

The main reason I prefer to err on the side of too many namespaces over too few is because I recognize their benefit in terms of discovery.

This is a strong argument. I do think there is validity to this aspect. This isn't really how I personally navigate a new library. (I just have the docs open.) But it is something I'll have to keep in mind.

You gave the example of Models.Response and Models.Request, and I would argue that this is very reasonable. Very. When you are responding, Intellisense will present to you a discrete list of models that are appropriate for the operation. Without this, you are just fooling yourself because ResponseModel or RequestModel, or something like that, would end up being part of the name in some other way - otherwise, how would you ever know which is appropriate? More importantly and to your other point, how will other developers know?

So, a few thoughts here. First off, are you reusing models? How extensively? A lot of APIs I've worked in tend to have one specific request model and one specific response model for one particular action/endpoint. Occasionally, the response model is reused across a couple HTTP verbs, but even in such a case, the actions are typically developed together. So, I'm rarely (never?) in a situation where I would want to discover the right models using Intellisense.

From there, are you making models with identical names? Request.GetResource and Response.GetResource? This leads to ambiguity and basically prevents you from using the namespaces here. So, yes, I would actually rather just have a GetResourceRequest and a GetResourceResponse.

It's okay we don't agree on this. We probably agree on a lot of other things.

I was going to say something similar. I suspect we're more alike than different. I've simply had experiences that led to me producing today's rant. I'm grateful you're not the average Twitter user here to insist that I'm a bumbling buffoon who will never amount to anything in the world of .NET.

I wish you luck in your endeavors. Thanks for taking the time to read my words.

Thread Thread
 
nixon profile image
Jerry Nixon

All great points.

And as far as one coding file with multiple pages of using directives? Shameful. I would love to have an engineer try to defend that with a straight face. Maybe "unhealthy" is exactly the right word choice - in this case - and, besides, it is your blog - not mine.

Thanks again for the exchange of ideas. 2 peas in a pod, I'm sure.

Image description