10

I've run into some code (C# if it matters) that has classes which have the same name, but differ in their namespaces. They all tend to represent the same logical thing, but often are different "views" of the same object. The different namespaces are at times part of the same solution, and even the same dll.

I have my thoughts, but couldn't find anything definitive about this practice to be considered a clever use of the tools available or a pattern to avoid.

This question on smurf naming touches on this, but from the other direction. Disambiguating the names would likely require an arbitrary and pervasive prefix, which that question wanted to eliminate.

What are the guidelines around this practice?

  • 1
    In OOP there are many exceptions, but at first I consider this bad design, especially if all of the classes share the same level of accessibility. When I read a class name, in any file, then I want to know in what namespace the class is located immediately without having to refer the namespace directives. – Leopold Asperger Jul 30 '14 at 21:41
  • There is a valid case for having multiple related objects that deal with the same state, but typically they are separated by function. Maybe you have one object that adapts a model for a view. Another one might perform a calculation on the object. Another might be an adapter or facade. So you might have FooAdapter, FooViewer, FooCalculator, etc. but certainly not named the same thing. Without more information about the specific classes about which you are talking it is difficult to provide an answer, however. – user22815 Jul 30 '14 at 21:44
  • @JohnGaughan - consider Employee as the example. There is an employee that is for other employees, one for HR, one for outside exposure. They're all named "employee" and they all have varieties of helpers (EmployeeRepository, EmployeeView, etc.). They all are in the same dll, and while they share some common properties (name, title), they all differ (phone number, salary). – Telastyn Jul 30 '14 at 22:00
  • Having worked with systems that model Employees several times, sounds like you need a model with the union of all the attributes and include a type or department attribute. Otherwise, there is needless duplication of code. – user22815 Jul 30 '14 at 22:03
  • 5
    Wasn't this one of the reasons for namespaces to begin with? To allow name collisions? – Dan Pichelman Jul 31 '14 at 0:09
5

I'll try to give an answer against such usage, after having seen and worked on this in one of my projects as well.

Code readability

First of all, consider that code readability is important and this practice is counter to that. Someone reads a piece of code and let's just say it has a function doSomething(Employee e). This is no longer readable, because due to 10 different Employee classes existing in different packages you will have to first resort to the import declaration to find out what your input really is.

This, however, is a high-level view and we often have seemingly random name clashes, which no one cares about or even finds, because the meaning can be derived from the remaining code and which package you are in. So one could even argue that, locally, there is no problem, because of course if you see Employee within an hr package you have to know that we're talking about an HR view of the employee.

Things break apart as soon as you leave these packages though. Once you are working in a different module/package/etc and need to work with an employee, you're already sacrificing readability if you do not fully qualify its type. Additionally, having 10 different Employee classes means that your IDE's auto-completion will no longer work and you have to manually choose from the type of employee.

Code duplication

Due to the very nature of each of these classes being related to each other your code is bound to deteriorate due to lots of duplication. In most cases, you will have something like an employee's name or some identification number, which each of the classes has to implement. Even though each class adds its own sort of view, if they do not share the underlying employee data, then you will end up with huge masses of useless, but costly, code.

Code complexity

What can be so complex you may ask? After all, each of the classes can keep it as simple as it wants to. What truly becomes a problem is how you propagate changes. In a reasonably feature-rich software you may be able to change employee data - and you want to reflect that everywhere. Say that one lady just married and you have to rename her from X to Y due to that. Hard enough to do this right all over the place, but even harder when you have all of these distinct classes. Depending on your other design choices, this may easily mean that each of the classes has to implement its own sort of listener or such to be notified of changes - which basically translates to a factor being applied to the number of classes you have to deal with. And more code duplication of course, and less code readability, .. Factors like this may be ignorable in complexity analysis, but they sure are annoying when applied to the size of your code base.

Code communication

Apart from the above problems with code complexity, which are also related to design choices, you are also reducing your higher-level design clarity and lose the ability to properly communicate with domain experts. When you discuss architecture, designs, or requirements you are no longer free to make simple statements like given an employee, you can do .... A developer will no longer know what employee really means at that point. Although a domain expert will know it of course. We all do. sort of. But in terms of the software it's not so easy to communicate anymore.

How to get rid of the problem

After becoming aware of this and if your team agrees that it is a problem big enough to tackle, then you will have to work out a way to deal with it. Typically, you cannot ask your manager to give the whole team a week off so they can take out the trash. So in essence,you will have to find a way to partially eliminate these classes, one at a time. The most important part about this is to decide - with the whole team - what an Employee really is. Do not integrate all of the individual attributes into one god-employee. Think more of a core-employee and most importantly, decide where that Employee class will reside.

If you do code reviews, then it is particularly easy to ensure that the problem does at least not grow any further, i.e. stop everyone right in their track when they want to add another Employee again. Also take care that new subsystems adhere to the agreed Employee and are not allowed to access the old versions.

Depending on your programming language, you may also want to mark the classes that will eventually be eliminated with something like @Deprecated to aid your team in immediately realizing that they're working with something that will have to be changed.

As for getting rid of the outdated employee classes, you can decide for each individual case how it's best eliminated, or just agree on a common pattern. You can affix the class name and wrap it around the real employee, you can use patterns (decorator or adapter come to mind), or, or or.

To make a long story short: This "practice" is technically sound, but is choked full of hidden costs that will only occur further down the road. While you may not be able to immediately get rid of the problem, you can start immediately with containing its harmful effects.

  • Having a Core class seems like a good solution. Other classes can extend from it. About the IDE, auto completion is smart enough to know which class to suggest to you to best match the context. Overall, I don't see why this is such a big problem especially if the codebase is used internally. – InformedA Jul 31 '14 at 6:10
  • 1
    It's not smart enough once you are outside of one context. Consider a class, which actually needs both of the problematic classes - auto-complete will not help at all. And it won't even differentiate these from the other ten classes. But the real problem is that new team member, who doesn't even know what all of those package domains actually are and which one he should choose. – Frank Jul 31 '14 at 7:34
  • If multiple classes with same name are being used in the same context, then it's hard. I haven't seen that case. I have seen multiple classes with same name, but they are not often used in the same context as you mentioned. – InformedA Jul 31 '14 at 7:44
  • @randomA - sadly, that case is fairly common in this codebase. – Telastyn Jul 31 '14 at 11:30
8

The Scala Collection Framework is a good example of this. There are mutable and immutable collections as well as serial and parallel (and in the future maybe distributed as well) collections. So, there are, for example, four Map traits:

scala.collection.Map
scala.collection.immutable.Map
scala.collection.mutable.Map
scala.collection.concurrent.Map

plus three ParMaps:

scala.collecion.parallel.ParMap
scala.collecion.parallel.immutable.ParMap
scala.collecion.parallel.mutable.ParMap

Even more interesting:

scala.collection.immutable.Map            extends scala.collection.Map
scala.collection.mutable.Map              extends scala.collection.Map
scala.collection.concurrent.Map           extends scala.collection.mutable.Map

scala.collecion.parallel.ParMap           extends scala.collection.Map
scala.collecion.parallel.immutable.ParMap extends scala.collecion.parallel.ParMap
scala.collecion.parallel.mutable.ParMap   extends scala.collecion.parallel.ParMap

So, ParMap extends ParMap extends Map and Map extends Map extends Map.

But, let's face it: what else would you call them? This makes perfect sense. That's what namespaces are for!

  • 3
    "That's what namespaces are for!" => +1 – svidgen Aug 5 '14 at 14:13
  • I like this, but in C#/.NET world when I moved parallel classes into a Parallel sub-namespace this then clashes with the helper class System.Threading.Parallel, which I happen to be using heavily to obtain parallelism. I didn't want to use the namespace 'Concurrent' instead as that is already being used to mean 'concurrent access' on collection classes. As a compromise I've opted for the sub-namespace 'Parallelized'. – redcalx Dec 30 '17 at 18:27
2

This is a real interesting question where the two essentially opposing answers are both correct. Here's a real-world example of this discussion we're having on a project of mine.

I think there are two very salient considerations so far that would make you want to go in one direction or the other, drawing from the two answers from @Jorg and @Frank:

  1. If you anticipate a situation where more than one of the same-named classes might need to be used within the same code context, this is a reason not to use the same name. That is, if you need to work with hr.Employee but at the same time need to look at permissions via security.Employee, it's going to get annoying real fast.
  2. Conversely, if your classes with the same name all have the same or very similar APIs, then that's a good example of when you should use the same name with different namespaces. The Scala example is precisely this, where all the Map classes implement the same interface or are subclasses of each other. In this case the ambiguity or "confusion" can arguably be called a good thing, because the user rightly can treat all the implementations of the class or interface the same...which is the point of interfaces and subclasses.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.