Exportieren Sie private Typen in Go besser nicht

In der Go-Entwicklung ist ein bestimmtes Anti-Pattern weit verbreitet: der Export privater Typen. Was auf den ersten Blick harmlos wirkt, untergräbt die Kapselung und erschwert langfristig die Pflege und Erweiterbarkeit des Codes. In diesem Artikel beleuchten wir, wie dieses Muster entstanden ist, welche Risiken es birgt und wie es sich konkret auf Ihre Code-Architektur auswirken kann.
— Geschätzte Lesezeit: 8 Minuten
private Typen in Go

Nicht exportierte Typen in Go: Wo alles begann

Wenn man von klassischen objektorientierten Sprachen wie Java oder PHP in die Welt von Go einsteigt, sind viele Entwickler an die Verwendung von Klassen und die automatische Objektinitialisierung beim Aufruf von Konstruktoren gewöhnt.

Strukturen in Go sind jedoch nicht dasselbe wie Klassen und Objekte in anderen Sprachen. Sie spielen eine ähnliche Rolle, sind aber nicht identisch!
Übrigens, erfahren Sie mehr über unsere Herangehensweise in der Webentwicklung, wir empfehlen auch sich unsere Projekte anzusehen - sie werden Sie sicher überraschen.

Probleme mit dem Export privater Typen

Das Hauptproblem beim Exportieren privater Typen besteht darin, dass dies das Prinzip der Kapselung verletzt.

Allein der Begriff "nicht exportierte Struktur" selbst besagt: Sie ist für die interne Verwendung im Paket bestimmt. Die wird benötigt, damit die Codekonsumenten NUR mit exportierten Typen arbeiten. Das ist die Kapselung, die es Ihnen ermöglicht, Dinge zu verbergen, auf die von außen nicht zugegriffen werden sollte! Es handelt sich um etwas Komplexes, das sich mit neuen Versionen des Pakets ändern kann. Daher ist es dasselbe, als würde man versuchen, etwas, das als "nicht essbar" gekennzeichnet ist - essbar zu machen. Es ist, als würde man Nägel mit einem Presslufthammer einschlagen. Wenn ein Programmierer so etwas tut, versteht er einfach nicht, warum es notwendig ist.

Schreiben von Strukturen, die keine Initialisierung erfordern.

Beispiele: sync.Mutex, time.Time, sync.WaitGroup und andere.

Bei der Standardinitialisierung funktionieren sie korrekt. Benannte Konstruktoren können für die Initialisierung in den gewünschten Zustand verwendet werden: time.Now(), time.Parse(). Dies ist der ideale Ansatz! Allerdings kann dies nicht in allen Fällen erreicht werden.

Ein komplexer Domänendienst erfordert möglicherweise eine tiefere Initialisierung.

Zum Beispiel Dependency Injection (Config, Logger, Repo, NetClient usw.). In diesem Fall werden ein benannter Konstruktor und eine Struktur mit privaten Feldern erstellt, in die bei der Grundinitialisierung nichts geschrieben werden kann. In diesem Fall werden Abhängigkeiten, Konfigurationen und andere Dinge im Konstruktor überprüft, der einen Fehler zurückgeben kann.

NewDomainService(c Config, d Dependencies) (*DomainService, error)

Solche Dienste haben in der Signatur immer Methoden, die eine domänenspezifische Funktion ausführen:

  • Start(ctx context.Context) error
  • Process(ctx context.Context) error
  • Execute(ctx context.Context) error
  • .....

Wenn der Dienst nicht ordnungsgemäß initialisiert wurde, gibt er einen Fehler zurück. In 99% der Fälle können solche Dienste ohnehin verschiedene Fehler aus dutzenden von Gründen zurückgeben. Das Argument „Ich bin zu faul, Fehler zu beheben“ klingt also nicht gut.

Fehler behandeln ist der Go-Ansatz

Das wird mit zwei Zeilen erledigt, die vom IDE automatisch generiert werden. Und genau das ermöglicht es, sofort die Schwachstellen des eigenen Codes zu erkennen, mögliche Fehler zu identifizieren und darüber nachzudenken, was damit zu tun ist. Und dabei wird nichts Schlimmes passieren.

Sie wird vom Verbraucher verarbeitet, und im Falle einer fehlerhaften Initialisierung wird der Programmierer den Fehler auf der Ebene der Tests seines Moduls sehen, sofern er sie natürlich schreibt. Im schlimmsten Fall wird alles beim ersten Testlauf der Anwendung zusammenbrechen.

Wenn jedoch ein solches Problem (mein Dienst wurde nicht initialisiert) zu "irgendwelchen schrecklichen kritischen Dingen" führt, wie zum Beispiel das Löschen der Datenbank, das Formatieren der Festplatte oder das Übertragen von Bitcoins an eine nicht existierende Brieftasche, dann haben Sie Probleme mit der Dienstentwicklung! Das Problem liegt bei Ihnen, nicht bei denen, die Ihren Code verwenden! Denn so etwas sollte niemals passieren!

Schutz vor unerwarteten Problemen mit "naiven Verbrauchern" - erwarte Probleme

Und zwar:

  1. Sie werden nicht in der Lage sein, eine ordentliche Anwendungsarchitektur aufzubauen. Denn Sie können diesen privaten Typ einfach nicht in den oberen Schichten verwenden. Zum Beispiel, wenn es sich um ein Repository handelt oder um einen anderen Domänendienst, muss er im Verbraucher-Interface beschrieben werden. Aber das können Sie nicht tun, weil es ein privater Typ ist! Sie werden einfach nicht in der Lage sein, etwas außerhalb seines Pakets zu typisieren! Daher wird DI nicht funktionieren.
  2. Wenn Sie es in einem Interface-Typ eines Verbrauchers einbauen wollen, benötigen Sie Folgendes:

    - ServiceLocator oder ApplicationRegistry - dies ist ein Top-Level-Architekturobjekt, das Verweise auf die Hauptdienste speichert. Es muss die Initialisierung dieses Objekts kennen und speichern

    - IoC - hier müssen Sie eine Implementierung für das Interface binden, das automatisch beim Erstellen von Objekten injiziert wird. Ob Sie dies manuell tun, Wire oder FX verwenden, Sie müssen trotzdem beispielsweise einen FX-Show-Konstruktor für diesen Typ schreiben und ihn dann an die entsprechenden Interfaces binden. All dies ist mit privaten Typen unmöglich.
  3. Sie können die GoDoc-Dokumentation nicht verwenden, weil private Typen dort nicht für die externe Verwendung beschrieben werden, was absolut logisch ist!
  4. Dies widerspricht der Idiomatik der Sprache und verwirrt andere Entwickler mit einem ungewöhnlichen und falschen Ansatz.

Anstelle einer Schlussfolgerung

Der Export privater Typen in Go wirkt zunächst wie eine pragmatische Lösung, führt aber langfristig zu Problemen bei Wartung, Erweiterbarkeit und Skalierbarkeit. Nutzen Sie private Typen ausschließlich innerhalb des Pakets und orientieren Sie sich an den etablierten Best Practices der Go-Community.

Wenn Sie die Architektur Ihres Projekts optimieren oder sich zur Entwicklung mit Go beraten lassen möchten – sprechen Sie uns an. Wir zeigen Ihnen praxisnahe und zuverlässige Lösungen.

Effizientes Website-Management: Wie Geschäftsautomatisierung Gewinne steigert und Zeit bei Routineaufgaben und Buchhaltungsproblemen spart Effizientes Website-Management: Wie Geschäftsautomatisierung Gewinne steigert und Zeit bei Routineaufgaben und Buchhaltungsproblemen spart

Wie beeinflusst die Automatisierung von Geschäftsprozessen die Website-Verwaltung, Effizienz und Rentabilität eines Unternehmens? Die...

2. Februar 2024
Benötigen Sie nur Links, um in Google zu werben? Benötigen Sie nur Links, um in Google zu werben?

Ein wichtiger Aspekt des Google-Marketings ist das Backlink-Profil 🚀 Die Entwicklung eines Linkprofils allein kann jedoch Ihr Budget erheblich erhöhen und Prob...

18. April 2024
Warum ist es wichtig, ein Website-Audit durchzuführen und welche Schritte sind darin enthalten? Warum ist es wichtig, ein Website-Audit durchzuführen und welche Schritte sind darin enthalten?

Ein SEO-Audit ist eine Überprüfung der Website anhand einer Checkliste. Das Ziel besteht darin festzustellen, ob die Website den grundlegenden Standards für die...

18. April 2024
cookies Wir verwenden Cookies

Wir verwenden Cookies auf unserer Website, um die Nutzung zu analysieren, Inhalte zu personalisieren und die Website zu verbessern. Einige Cookies sind technisch notwendig und können nicht deaktiviert werden. Für alle anderen Cookies benötigen wir Ihre Zustimmung. Sie können Ihre Auswahl jederzeit ändern oder Ihre Einwilligung widerrufen. Weitere Informationen finden Sie in unserer Datenschutzerklärung.

Notwendige Cookies

Manche Cookies sind erforderlich, damit bestimmte Webseiten funktionieren. Aus diesem Grund werden sie ohne Ihre Einwilligung gesetzt.

Analyse-Cookies

Wir nutzen diese Cookies für interne Analysen, um unseren Service für alle Nutzer zu verbessern. Diese Cookies bewerten, wie Sie mit unserer Webseite interagieren. Sie werden nur mit Ihrer Einwilligung gesetzt.

Werbe-Cookies

Diese Cookies können von unseren Werbepartnern über unsere Webseite gesetzt werden. Sie ermöglichen es diesen Unternehmen, ein Profil Ihrer Interessen zu erstellen und Ihnen relevante Anzeigen auf anderen Webseiten anzuzeigen. Sie speichern keine direkt personenbezogenen Daten, basieren jedoch auf der eindeutigen Identifizierung Ihres Browsers und Internetgeräts. Diese Cookies werden nur mit Ihrer Einwilligung gesetzt. Wenn Sie sie nicht zulassen, erhalten Sie weniger zielgerichtete Werbung.