Die Probleme beim Vermeiden von Smurf-Benennungsklassen mit Namespaces

39

Ich habe den Begriff Schlumpfnamen von hier gezogen (Nummer 21). Um jedem zu ersparen, der nicht mit den Problemen vertraut ist, wird beim Benennen von Schlümpfen eine Reihe verwandter Klassen, Variablen usw. mit einem gemeinsamen Präfix vorangestellt, sodass am Ende "a SmurfAccountViewgeht a SmurfAccountDTOan die SmurfAccountController" usw. angezeigt werden.

Die Lösung, die ich bisher gehört habe, besteht darin, einen Schlumpf-Namespace zu erstellen und die Schlumpf-Präfixe zu löschen. Das hat mir im Allgemeinen gute Dienste geleistet, aber ich habe zwei Probleme.

  1. Ich arbeite mit einer Bibliothek mit einer ConfigurationKlasse. Es hätte aufgerufen werden können, WartmongerConfigurationaber es befindet sich im Wartmonger-Namespace. Es wird also nur aufgerufen Configuration. Ich habe ebenfalls eine ConfigurationKlasse, die aufgerufen werden könnte SmurfConfiguration, aber sie befindet sich im Schlumpf-Namespace, sodass sie überflüssig wäre. Es gibt Stellen in meinem Code, an denen Smurf.Configurationnebeneinander angezeigt wird Wartmonger.Configurationund die Eingabe von vollständig qualifizierten Namen klobig ist und den Code weniger lesbar macht. Es wäre schöner, mit einem SmurfConfigurationund umzugehen (wenn es mein Code und keine Bibliothek wäre) WartmongerConfiguration.

  2. ServiceIn meinem Smurf-Namespace befindet sich eine Klasse, die aufgerufen werden könnte SmurfService. Serviceist eine Fassade auf einer komplexen Schlumpfbibliothek, in der Schlumpfjobs ausgeführt werden. SmurfServicescheint ein besserer Name zu sein, denn Serviceohne das Smurf-Präfix ist das so unglaublich generisch. Ich kann akzeptieren, dass dies SmurfServicebereits ein generischer, unbrauchbarer Name war, und das Entfernen von Schlumpf machte dies nur deutlicher. Aber es hätte benannt werden Runnerkönnen Launcher, usw. und es würde sich für mich immer noch "besser anfühlen", SmurfLauncherweil ich nicht weiß, was ein Launchertut, aber ich weiß, was ein SmurfLaunchertut. Man könnte argumentieren, dass das, was ein Smurf.Launchertut, genauso offensichtlich sein sollte wie einSmurf.SmurfLauncher, aber ich konnte sehen, dass `Smurf.Launcher eine Art Klasse ist, die sich eher auf Setup bezieht als auf eine Klasse, die Schlümpfe startet.

Wenn es einen offenen und geschlossenen Weg gibt, mit beiden umzugehen, wäre das großartig. Wenn nicht, was sind einige gängige Praktiken, um ihre Belästigung zu lindern?

Daniel Koverman
quelle
3
Startet Smurf.LauncherSchlümpfe oder startet es SmurfJobs? Vielleicht könnte es aufgerufen werden Smurf.JobLauncher?
Blorgbeard
2
Es ist ein Code-Geruch, um eine Klasse XService, XManager usw. zu nennen. Diese haben keine Bedeutung. Es ist wie ein Util. Wenn Sie die Dateinamen überfliegen, ist möglicherweise etwas vorhanden oder fehlt. Es gibt keine Möglichkeit zu wissen, es sei denn, Sie schauen hinein. Ich würde es komplett von SmurfService in etwas anderes umbenennen.
Daniel Kaplan
1
Es startet tatsächlich SmurfJobs oder führt sie technisch aus, um mit der Sprache der Schlumpfdokumentation übereinzustimmen. In Anbetracht dessen, und die anderen Antworten, ich werde umbenennen SmurfServicezu SmurfJobRunner. Es scheint, dass Nummer 1 keine sprachenunabhängige beste Auflösung hat, wie ich erwartet hatte. Ich kann Fälle sehen, in denen das Mitgehen SmurfConfigurationder richtige Anruf wäre, aber in meinem Fall denke ich, Configurationist es das Beste, selbst mit dem Ärger von Wartmonger.Configuration.
Daniel Koverman
6
Ich versuche zu verstehen, warum Sie eine einzige Klasse haben, die sich überhaupt um die Konfiguration von Wartmongern und Schlümpfen kümmert.
Donal Fellows
Warum tun Smurf.Configurationund SmurfConfigurationfühlen sich anders an ? Sicherlich ist es nicht der Sonderpreis, oder? (Kürzen auf, Configwenn die Länge das Problem ist.) Gibt Smurf.Configurationes Probleme, bei denen SmurfConfigurationdies nicht der Fall ist?
Pablo H

Antworten:

16

Sie sprechen einige gute Punkte an.

  1. Im Hinblick auf doppelte Klassen können Sie Klassen in C # aliasen. Verwenden Sie zum Beispiel using ColorScheme = The.Fully.Qualified.Namespace.Outlook2007ColorScheme;Siehe diesen Beitrag auf StackOverflow . Sie haben Ihre Programmiersprache nicht angegeben, aber ich habe sie dem entnommen, was Sie geschrieben haben. Also , wo man mit zwei verschiedenen Projekten zu tun haben, können Sie alias sie als SmurfConfigurationund WartmongerConfigurationdie würde Zweideutigkeit freizugeben, wenn beide Klassen raubend.

  2. Da ein Dienst externen Anwendungen ausgesetzt ist, sehe ich kein Problem darin, den Dienst mit Ihrem Anwendungsnamen zu kennzeichnen. In diesem Fall SmurfServicewäre dies gültig, da dadurch tatsächlich Gruppen von Diensten in der konsumierenden Anwendung unterschieden werden.

Ich bin der Meinung, dass Namespaces verwendet werden sollten, um diese Art der Benennung zu vermeiden. Dadurch wird es schwieriger, den Code zu durchsuchen und zu erkennen, was eine Klasse ist, ohne MyCompanyMyProductMyAreaClassName zu lesen. Mit der Aliasing-Technik können Sie Mehrdeutigkeiten bei Bedarf reduzieren. Das einzige Mal, wenn Sie Ihrer Namensgebung Komplexität verleihen sollten, ist, wie ich bereits in Nr. 2 dargelegt habe, wann die Leute einen Dienst in Anspruch nehmen werden. Hier ist es sinnvoll, diese Art der Benennung zu verwenden, da die Mehrdeutigkeit verwirrend sein kann, wenn der Verbraucher über eine Vielzahl von Diensten verfügt, die er verbraucht.

Sam
quelle
5
Aliase verwirren nur die Dinge. Statt Smurf.Service haben Sie jetzt SmurfService = Smurf.Service. Genauso gut hätten Sie SmurfService als Namen der Sache haben können. Sie haben einen Platz, aber nicht für dieses spezielle Thema. Allerdings ist es wahrscheinlich die beste Antwort auf ein Problem, das keine Antwort hat :)
gbjbaanb
Das C # in mir kam in meiner Frage heraus, aber ich beschäftige mich aktuell mit Java und org.apache.smurfville.wartmonger.configuration. Dies schließt leider Aliase aus. 2 ist ein solider Punkt, deshalb werde ich das Schlumpf-Branding für den Service beibehalten.
Daniel Koverman
25

Der Sinn von Namespaces ist, dass Sie Klassen mit demselben Namen aus verschiedenen Bibliotheken haben können, ohne dass sie kollidieren. Wenn Sie dieselbe benannte Klasse von beiden verwenden müssen, müssen Sie die Mehrdeutigkeit beseitigen, indem Sie einer oder beiden den Namespace-Bereich voranstellen.

Das heißt, es ist nicht wirklich schlimm, eine Reihe von Schlumpfklassen zu haben, wenn Schlumpf Ihnen etwas Bestimmtes über die Klasse sagt. Die Klassennamen sollten so aussagekräftig sein, dass Sie einige Informationen über die Funktionsweise der Klasse erhalten.

      Session
       ^   ^
      /     \
DBSession   HttpSession

Ebenso DBSessionkönnte ein DBRequestObjekt nehmen, das ein Objekt zurückgibt DBResponse. Das HttpSessionkönnte auch auf HttpRequestund HttpResponseObjekte wirken.

Dies sind Schlumpfklassen mit einem Zweck.

Sie könnten in dem Live - MyCompanyNamespace aber MyCompanyHttpSessionund MyCompanyDBSessionnicht geben Ihnen mehr Informationen , als Sie zuvor. In diesem Fall löschen Sie den Schlumpf und machen ihn zu einem Namespace.

MyCompany.HttpSession
Dave Rager
quelle
3

Ich bin schon einmal auf diesen Punkt der Verwirrung gestoßen und es ist normalerweise eine Frage, ob wir die Art von Dingen, die es ist, als Teil seines Namens einbeziehen.

Sie erwähnen SmurfConfigurationund WartmongerConfigurationals mögliche Arten von Konfigurationen. Sie geben an, dass Sie das Adjektiv (seine Art) in seinem Namespace entfernt haben, sodass nur noch die Vanille übrig bleibt Configuration. Das würde ich vermeiden.

Es ist, als würde man entscheiden, dass Erdbeereis nur Eis im Erdbeer-Namensraum und ebenfalls mit Schokolade ist, aber was passiert ist, ist, dass Sie das Adjektiv, das ihm seine Identität verleiht, von der Sache selbst getrennt haben. Es ist kein Eis in der Kategorie Erdbeeren. Es ist Erdbeereis - eine Art Eis.

Stellen wir uns vor, Sie importieren die Strawberry.IceCreamKlasse in Ihre App und beginnen direkt mit der Instanziierung IceCream.

var ic = new IceCream(); //actually I'm strawberry ice cream

Dies mag gut und schön erscheinen, bis Sie am Ende eine andere IceCreamKlasse importieren . Jetzt kehren Sie zu dem ursprünglichen Problem zurück, sie irgendwie unterscheiden zu müssen, was problematisch ist. Was Sie die ganze Zeit wollten, war:

var sic = new StrawberryIceCream();
var cic = new ChocolateIceCream();

Namespaces sollten besser belassen werden, um potenzielle Konflikte zwischen Drittanbietern zu vermeiden, die möglicherweise in ihren Bibliotheken die gleichen Konzepte verwenden. Wenn ein Entwickler jedoch eine Bibliothek oder ein Projekt erstellt, sollte er jedes Konzept eindeutig benennen und Namespaces nur als Ordner für die Organisation verwenden. Oft wird der Name des Ordners im Namen der von ihm organisierten Konzepte gefunden, und das ist in Ordnung.

Mario T. Lanza
quelle
2

Es ist auf jeden Fall eine gute Faustregel, dass Klassen, die ein gemeinsames Präfix für eine Reihe von Klassen haben, es wahrscheinlich verdienen, in ihrem eigenen Namespace zu arbeiten. Um das Problem zu lösen, wenn Sie Klassen mit ähnlichen Namen aus zwei Namespaces verwenden müssen:

1) Alias ​​die Namespaces, obwohl ich es kurz und bündig machen würde, jede natürliche Abkürzung, vielleicht sogar nur 1 Buchstabe:

using Sm = Smurf;
using W = Wartmonger;

Dann immer Präfix verwenden und Instanzen entsprechend benennen:

Sm::Configuration smConf; 
W::Configuration wConf;

2) Alias ​​der Klasse, wie in einer anderen Antwort vorgeschlagen.

using SmConf = Smurf.Configuration;

3) Jede Bibliothek, über die Sie die Kontrolle haben, sollte den Begriff "Konfiguration" nicht verwenden. Verwenden Sie den Thesaurus: zB 'Einstellungen', 'Modell', 'Parameter'. Könnte für den Kontext sowieso aussagekräftiger sein: Wenn Smurf beispielsweise eine Art numerisches Analysemodul wäre, das Sie geschrieben haben, wäre 'Parameters' möglicherweise besser für die Konfiguration. Verwenden Sie das spezielle Vokabular, das mit dem Kontext eines Moduls verknüpft ist, zu Ihrem Vorteil, um eindeutige Namen zu erhalten, die auch dann eindeutig sind, wenn sie in andere Namespaces gemischt werden. Ich denke, dies könnte eine Art Antwort auf die OP-Frage 2 sein.

4) Refactor-Code, damit Sie die Verwendung der Konfiguration nicht an zwei verschiedenen Stellen mischen müssen. Details dazu liegen bei Ihnen.

5) Kombinieren Sie die beiden Konfigurationen zu einer, bevor Sie sie an Ihre Klasse übergeben. Verwenden Sie eine kombinierte conf-Klasse, um Folgendes darzustellen:

struct Conf {
    SmurfConfiguration smurf;
    WartmongerConfiguation wart;
}

Die kurzen Mitgliedsvariablennamen erreichen jetzt das Gleiche wie das Aliasing der Klasse / des Namespaces.

Benedikt
quelle
0

Scheint seltsam, dass das Hinzufügen eines Punktes zum Namen Sie stört.

Wartmonger.Configuration configuration = Wartmonger.Configuration .new();

// vs

WartmongerConfiguration configuration = WartmongerConfiguration.new();

Wenn beide Smurfund WartmongerKonfigurationen an einem Ort zusammen verwendet werden, sie jedoch getrennt an mehreren Orten verwendet werden, ist der Namespace auf jeden Fall ein guter Ansatz.

Wenn Sie über einen Namespace verfügen, können Sie im internen Code "saubere" Namen verwenden. Bei Präfixen wird der interne Code von SmurfConfigurationinside SmurfServiceverwendet, was jedes Mal ärgerlich sein kann, wenn Sie diesen Code öffnen.

Fabio
quelle