Dieser Artikel soll Ihnen helfen, mit Ihrem neuen Projekt in Go einen guten Start hinzulegen.
A QUICK SUMMARY – FOR THE BUSY ONES
TABLE OF CONTENTS
Sobald Sie mit der Arbeit an Ihrer Go-Web-App begonnen haben, gibt es viele unbeantwortete Fragen. Einige von ihnen tauchen auf, noch bevor die erste Zeile des Quellcodes geschrieben ist.
Lass uns Machen Sie den Beginn Ihrer Reise mit Go ein bisschen einfacher. Im Folgenden finden Sie Antworten auf die wichtigsten Fragen zu Frameworks, DI-Containern und der Auswahl der Verzeichnisstruktur.
Bei der Auswahl eines Tools, mit dem wir arbeiten möchten, müssen wir uns oft zwischen Geschwindigkeit und dem Funktionsumfang entscheiden.
Bei der Auswahl eines Frameworks in einer neuen Programmiersprache ist es nicht anders. Es gibt zu viele Lösungen und es ist nicht möglich, alle auszuprobieren.
In der Go-Sprache finden Sie über 40 Frameworks für die Erstellung von Go-Webanwendungen. Wie wählen Sie die richtige für Ihre Go-Anwendung aus?
Lassen Sie uns zunächst überprüfen, welche davon aktiv entwickelt. Dies verkürzt die Liste erheblich, reicht jedoch nicht aus, um nur eine auszuwählen. In solchen Fällen hilft es, die Beliebtheit eines Tools in Github zu überprüfen.
Das beliebteste Golang-Framework hat 32.000 Sterne. Man könnte also sagen, dass diejenigen ohne mindestens 6.000 (20% der maximalen Punktzahl) nicht sehr beliebt sind, was später zu Problemen bei der Suche nach einem Team von Programmierern, Community-Support usw. führen kann.
Es gibt 4 Tools mit mehr als 6.000 Sternen:
Mit einer so kurzen Liste können Sie etwas Zeit verbringen jedes einzelne gründlich überprüfen. Prüfen Sie, ob das Framework die Tools bietet, die Sie benötigen:
<span class="colorbox1" fs-test-element="box1"><p>Tipp: Im Allgemeinen ist es wichtig, die Stärken und Schwächen der Lösung herauszufinden.</p></span>
Wenn jedes der Tools unseren Erwartungen entspricht, steht dem Start mit dem beliebtesten nichts mehr im Weg: Gin!
Beim Schreiben von Code ist es ein Standard, der sicherstellt, dass seine Strukturen und Funktionen nicht mit anderen Teilen des Systems zusammenhängen, um ihnen Flexibilität zu geben und sie testen, entwickeln und modifizieren zu können.
Zweifellos tragen die Dependency Injection-Container dazu bei, dieses Ziel zu erreichen. Sie ermöglichen es Ihnen orchestrieren Sie das Ganze, um die notwendigen Abhängigkeiten aufzubauen.
Wire und Dig sind gängige Tools in der Go-Umgebung. Das erste wird verwendet, um Abhängigkeiten bei der Kompilierung zu verwalten, und letzteres ist ein Beispiel für einen Container in Runtime. Der Nachteil ist, dass große Unternehmen sie zwar unterstützen, aber nicht besonders beliebt sind.
Unabhängig davon, ob Sie die Version „mit“ oder „ohne“ den Container wählen, ist es wichtig, die Anwendung so zu erstellen, dass diese Abhängigkeiten injiziert werden. Auch ohne Container ist es möglich, dieses Ziel zu erreichen.
Hier ist ein Beispielfragment einer Anwendung:
Repository: = repositories.newInMemoryParcelRepository ()
parcelService: = services.NewParcelService (Repositorium)
ParcelController: = Controllers.NewParcelController (ParcelService)
server.post („/schedule“, parcelController.scheduleParcelPickup) vom Typ ParcelController struct {
Servicedienstleistungen.Paketservice
}
func newParcelController (Dienst Services.ParcelService) ParcelController {
gib ParcelController {service: service} zurück
}
func (Steuerung ParcelController) scheduleParcelPickup (c *gin.Context) {
..
}
ParcelController benötigt ParcelService, um ordnungsgemäß zu funktionieren, aber anstatt eine Instanz von ParcelService innerhalb des Controllers zu erstellen, Injizieren Sie die Instanz vom bereits gebauten ParcelService zu NewParcelController. Auf diese Weise können Sie ParcelService unabhängig von ParcelController ändern.
Schließlich verbinden wir die Methode scheduleParcelPickPickup mit dem Router (POST, „/schedule“) mit den Abhängigkeiten, die wir bereits injiziert haben.
Solange das Projekt nicht zu groß ist, ist die Verwaltung von Abhängigkeiten auf diese Weise relativ einfach.
Bevor Sie sich entscheiden, einen DI-Container in Ihr Abhängigkeitsmanagement einzubeziehen, können Sie versuchen, Abhängigkeiten in Builders oder Factories zu erstellen. Eine ziemlich große Go-Anwendung kann ohne zusätzliche Tools verwaltet werden.
Das ist ein sehr kompliziertes Thema. Es hängt von der allgemeinen Architektur ab (Monolith im Vergleich zu Microservices), der Anzahl der Funktionen, die Ihre Go-Anwendung enthalten wird, Komplexität der Domain, sowohl in Bezug auf die Anzahl der Modelle als auch auf die Anzahl der durchgeführten Domänenaktionen und viele andere Faktoren, die berücksichtigt werden müssen.
Aber was ist, wenn Sie nur eine Go-Anwendung erstellen möchten und noch keine detaillierten Kenntnisse über die Domain haben, aber trotzdem mit etwas beginnen müssen?
Eine der Optionen besteht darin, der Onion Architecture zu folgen, die im Folgenden vorgestellt wird:
√── README.md
√── go.mod
√── go.sum
─ ─ src
√── Steuerungen
│ │ ── parcel.go
√── Domäne
│ √── Befehle
│ │ │ ── Paketabholung.go vereinbaren
│ √── Modelle
│ │ ── parcel.go
│ √── Repositorien
│ │ ── parcel.go
│ ── Dienstleistungen
│ │ ── parcel.go
√── Funktionen
│ √── Kontext
│ │ ── Hauptfunktion
│ │ ── parcel.feature
√── go_test.go
√── Infrastruktur
│ •── Repositorien
│ │ ── parcel.go
─ ─ main.go
Lies mich — Hier findest du neben grundlegenden Dingen wie Logo, Projektname, Überschrift, Badges und Beschreibung weitere Informationen wie: Installation, Nutzung, Konfiguration und nicht zuletzt die Lizenz, wenn du planst, sie als Open Source zu veröffentlichen (sonst kann niemand die Software benutzen!)
go.mod, go.sum — die Dateien, die verwendet werden von Go-Module, die Standardmethode zur Verwaltung von Abhängigkeiten in einer Go-Anwendung.
src/controller — hier kommt die HTTP-Anfrage des Benutzers ins Spiel. Der Controller ist der Eingang zu unserer Go-Anwendung. Der Controller empfängt und überprüft Daten vom Benutzer, fordert die Anwendung auf, eine Aktion auszuführen, und gibt dann die Antwort an den Benutzer zurück.
//ParcelController enthält Routen im Zusammenhang mit dem Paketplan
geben Sie ParcelController struct ein {
Servicedienstleistungen.Paketservice
}
//scheduleParcelPickup erstellt eine neue Paketabholung für den Kurier
func (Steuerung ParcelController) scheduleParcelPickup (c *gin.Context) {
var-Befehl commands.scheduleParcelPickup
wenn err: = c.shouldBindJSON (&command); err! = Null {
c.JSON (http.statusBadRequest, gin.H {"message“: „Ungültiges Formular“, „Formular“: err})
c.Abbrechen ()
Rückkehr
}
Paket: = Controller.service.scheduleParcelPickup (Befehl)
c.JSON (http.statusOK, &parcel)
src/domain/befehle — sind Befehle, die vom Benutzer gegeben werden, um Änderungen in der Domain auszuführen. Controller konvertieren die HTTP-Anforderungsdaten in Objekte, die die Absichten des Benutzers enthalten.
//ScheduleParcelPickup ist ein sehr, sehr einfaches Abholzeitplanobjekt.
//Wir gehen davon aus, dass jeder jeden kennt, daher ist der Vorname die vollständige Information, um das Paket abzuholen.
geben Sie ScheduleParcelPickup struct ein {
FirstName-Zeichenfolge `json: "first_name“ -Bindung: "erforderlich, min=2, max=100"`
}
src/domain/dienste — hier entfaltet sich die Magie der Models. Sie interagieren miteinander und ändern den Status unserer Go-Anwendung. Im Fall von ScheduleParcelPickPickup ist die Aktion sehr einfach. Beachten Sie dies nur, wenn Sie in die Datenbank schreiben. Während der Entwicklung der Geschäftslogik werden hier die nächsten Aktionen, wie z. B. ParcelPickup, ausgeführt.
//ParcelPickup versetzt das Paket in den Status „In Lieferung“
func (Dienst ParcelService) ParcelPickup (data commands.pickupParcel) (*models.Parcel, Fehler) {
Paket, err: = service.repository.Find (Data.ID)
wenn irr! = Null {
return nil, fmt.ERRORF („Ein nicht vorhandenes Paket kann nicht abgeholt werden“)
}
parcel.status = „in_delivery“
service.repository.save (*Paket)
Paket zurücksenden, Null
}
src/domain/models — sind unsere modellierten Objekte. Sie stellen tatsächliche Entitäten im Projekt dar.
src/domain/repositorys — ist die Datenbankzugriffsebene (nur zu aktivierende Schnittstellen) Umkehrung der Kontrolle). Um die grundlegenden Anforderungen für den Versand von Paketen zu erfüllen, wird unser Repository sehr einfach sein.
geben Sie ParcelRepository-Schnittstelle ein {
Speichern (Models.parcel)
Find (Models.ParcelId) (*Models.Parcel, Fehler)
}
Es enthält nur Methoden, mit denen ein Paket gespeichert und gefunden werden kann. In Zukunft könnten Methoden wie findUndeliveredParcels () oder findParcelsDeliveredBy (Models.Courier) hier erscheinen.
src/Infrastruktur/Repositorien — ist eine konkrete Implementierung von Repository-Schnittstellen.
Im Go-Beispielanwendungsprojekt ist uns nicht die Persistenz der Daten wichtig, sondern die Geschwindigkeit der Bedienung und die Vereinfachung des gesamten Beispiels. Daher basiert die Implementierung auf Speicher (InMemoryRepository), aber in Zukunft wird es sicherlich andere Implementierungen geben (z. B. PostgresRepository).
Die Verwendung dieses Ansatzes kann die Entscheidung, wie auf die Datenbank zugegriffen werden soll, verzögern. Je mehr wir wissen, bevor wir eine Entscheidung treffen, desto wahrscheinlicher ist es, dass es die richtige ist (welche ORM- oder Rohabfragen)
src/funktionen — Funktionen im BDD-Stil zu beschreiben ist ein Thema für sich. Es gibt eine Bibliothek namens Godog in Go. Es ermöglicht uns, die Dokumentation zu beschreiben und dann unsere Domain automatisch anhand dieser Dateien zu testen.
src/Features/Kontext — Kontexte sind Dateien, die eine wörtliche Beschreibung in eine bestimmte Aktion im Code übersetzen.
Funktion beschrieben als:
Merkmal: Healthcheck
Um gesunde Dienstleistungen zu haben
Als Container-Orchestrator
Ich muss in der Lage sein, den Dienst anzupingen
Szenario: Gesundheitscheck
Wenn ich pinge
Dann bekomme ich Pong
Dies veranschaulicht perfekt die Anforderung, die ein bestimmter Endpunkt erfüllt, und was die gewünschte Aktion ist, obwohl die Implementierung versteckt ist.
Im Folgenden beschreibt FeatureContext, was diese Schritte bedeuten:
func (context *featureContext) iPing () Fehler {
req, _: = http.NewRequest („GET“, „/ping“, null)
Context.Server.ServeHttp (context.recorder, erforderlich)
Null zurückgeben
}
func (Kontext *FeatureContext) IGetPong () Fehler {
Körper: = Context.Recorder.body.String ()
erwartet: = „{" message“ :"pong "}“
wenn Körper! = erwartet {
return fmt.ERRORF („Erwartet, {" message“ :"pong "} zu erhalten, habe aber %s“ bekommen, erwartet)
}
Null zurückgeben
}
Wenn Sie eine API erstellen, sollten Sie auch erwägen, die technische Dokumentation auf diese Weise zu speichern.
Merkmal: Healthcheck
Um gesunde Dienstleistungen zu haben
Als Container-Orchestrator
Ich muss in der Lage sein, den Ping-Endpunkt zu verwenden
Szenario: Gesundheitscheck
Wenn ich eine GET-Anfrage an „/ping“ sende
Dann sollte die Antwort dem Muster entsprechen:
„“
{"Nachricht“ :"pong "}
„“
src/main.go — die Hauptdatei unserer Go-Anwendung. Sie enthält zwei Funktionen. Der `Bootstrap`, der alle Abhängigkeiten aufbaut und die Controller mit bestimmten Routen verbindet, und der `main`, der den Server startet.
Um eine Bewerbung in einer neuen, unbekannten Sprache zu schreiben, sollten Sie zunächst Antworten auf einige Fragen finden.
In der Go-Sprache, um Ihr Abenteuer mit Webanwendungen zu beginnen, betrachte Gin als HTTP-Framework. Es ist beliebt und enthält die notwendigen Tools für die Bearbeitung von Anfragen, ohne optionale Auswahlmöglichkeiten wie ORM oder Verzeichnisstruktur vorzuschreiben. Wenn Sie nicht wissen, ob Sie einen DI-Container benötigen, müssen Sie ihn nicht vom ersten Tag an verwenden.
Beginnen Sie mit der Regel, dass Sie Abhängigkeiten in die unteren Ebenen der Go-Web-App einfügen. Wenn Sie entscheiden, dass Sie einen DI-Container benötigen, können Sie ihn dem Projekt hinzufügen.
Denken Sie daran, sich um die zu kümmern richtige Verzeichnisstruktur von Anfang an. Vergessen Sie jedoch nicht, von Anfang an auf die richtige Struktur der Anwendung zu achten, da es schwierig und teuer ist, die Struktur eines funktionierenden Projekts zu ändern.
Our promise
Every year, Brainhub helps 750,000+ founders, leaders and software engineers make smart tech decisions. We earn that trust by openly sharing our insights based on practical software engineering experience.
Authors
Read next
Popular this month