|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: Naming Things Is Hard: Namespaces |
| 4 | +excerpt: How should classes be grouped into namespaces, and how should those namespaces be named? Is 'Interfaces' a namespace? |
| 5 | +tags: [Naming Patterns] |
| 6 | +--- |
| 7 | + |
| 8 | +Organising classes into namespaces gives high-level clues to what classes do, what sort of classes |
| 9 | +they are, and makes it easier to navigate to classes of interest. But how should classes be grouped, |
| 10 | +and how should the groups be named? What's a helpful group name, and what isn't? |
| 11 | + |
| 12 | +## How to Group Classes |
| 13 | + |
| 14 | +Let's say you're looking for a set of hand towels in a department store - how would you find them? |
| 15 | +You'd probably go to the homewares department, then to the bathrooms section, and finally to towels - |
| 16 | +and that's how to group classes into namespaces - make categories of successively smaller scope. Is |
| 17 | +'hand towels' a namespace? Probably not - the smallest namespace scope should be wide enough to contain |
| 18 | +several classes with common features, and how many different types of hand towels are there? |
| 19 | + |
| 20 | +Next, let's say the department store sold descriptions of all its product, as well as the products |
| 21 | +themselves. Would it make more sense to have a top-level 'Descriptions' department, or to group the |
| 22 | +descriptions with the products they describe? The latter! Which is to point out: |
| 23 | + |
| 24 | +## 'Interfaces' is not a Namespace |
| 25 | + |
| 26 | +I've seen countless projects with an 'Interfaces' namespace, usually without narrower namespaces within. |
| 27 | +This is like our department store having a single 'Descriptions' department, with no further organisation |
| 28 | +within it - it doesn't help organise your code, and it's not a meaningful grouping. |
| 29 | + |
| 30 | +The 'Interfaces' namespace is usually found in a separate project, and used to implement |
| 31 | +[Inversion of Control](https://en.wikipedia.org/wiki/Inversion_of_control), which is a worthwhile thing |
| 32 | +to do. So how should we organise and name interfaces for IoC, without having an 'Interfaces' namespace? |
| 33 | + |
| 34 | +The appropriate name for a project like this is something like '[Prefixes].Abstractions', _e.g._ |
| 35 | +[Microsoft.Extensions.Logging.Abstractions](https://nuget.org/packages/Microsoft.Extensions.Logging.Abstractions), |
| 36 | +and if you look at the types in that project - _e.g._ |
| 37 | +[`ILogger`](https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/ILogger.cs) - |
| 38 | +you'll note that 'Abstractions' is not part of the namespace. The department store doesn't have a |
| 39 | +'Descriptions' department. |
| 40 | + |
| 41 | +Oh, and by the same reasoning - 'Implementations' isn't a namespace either :) |
| 42 | + |
| 43 | +## Quick Tips |
| 44 | + |
| 45 | +- If a namespace will contain several child items, make it plural, _e.g._ |
| 46 | + [`Microsoft.Extensions.Options.DataAnnotations`](https://nuget.org/packages/Microsoft.Extensions.Options.DataAnnotationsDataAnnotations), |
| 47 | + or [`System.IO.Pipelines`](https://nuget.org/packages/System.IO.Pipelines) |
| 48 | + |
| 49 | +- If a namespace will contain a particular implementation of something, make it singular, _e.g._ |
| 50 | + [`Microsoft.Extensions.FileSystemGlobbing`](https://nuget.org/packages/Microsoft.Extensions.FileSystemGlobbing), |
| 51 | + or [`System.Security.SecureString`](https://nuget.org/packages/System.Security.SecureString) |
| 52 | + |
| 53 | +- Name namespaces after the behaviours or services they provide, _e.g._ 'Security', 'Caching', |
| 54 | + 'Logging', etc |
| 55 | + |
| 56 | +- Put cross-cutting behaviours within your service namespaces into namespaces of their own, _e.g._ |
| 57 | + 'Caching.Configuration' |
| 58 | + |
| 59 | +- Within test projects, reproduce the namespaces of the classes under test, _e.g._ tests for types in an |
| 60 | + 'ExceptionHandling.AspNetCore' namespace should live in 'ExceptionHandling.AspNetCore.Tests' |
| 61 | + |
| 62 | +Happy namespacing! |
0 commit comments