In unserem Blogartikel GitHub Reusable Workflows haben wir bereits geschildert, wie wir als Cloud-/Plattform-Team CI/CD-Pipelines in der Cloud vereinheitlichen und aus wiederverwendbaren Bausteinen zusammensetzen, um unseren EntwicklerInnen die Nutzung unserer GitHub Services so einfach und effizient wie möglich zu gestalten.
Vor dem Hintergrund weiterer Vereinfachungen für unsere EntwicklerInnen haben wir uns mit GitHub Codespaces beschäftigt. Die Codespaces adressieren hierbei ein Problem, das sicherlich vielen Entwicklerteams bekannt sein wird: Der Aufbau der lokalen Entwicklungsumgebung ist meist kompliziert und zeitaufwändig. Nicht selten vergehen etliche Stunden oder sogar Tage, bis ein neues Teammitglied die richtigen Tools in der passenden Konfiguration auf dem eigenen Rechner installiert hat und mit dem Programmieren beginnen kann. Bei der Einführung neuer Tools, Versionsupgrades oder Konfigurationsänderungen entstehen häufig erneut Probleme, sodass die Arbeitsfähigkeit der EntwicklerInnen vorübergehend eingeschränkt ist.
Dieser Herausforderung wollen wir mit Codespaces begegnen.
Screenshot von github.com/features/codespaces
Was ist ein Codespace?
Ein Codespace ist eine Entwicklungsumgebung in der Cloud, die GitHub für dort verwaltete Repositories anbietet. Statt auf seinen lokalen Rechner checkt man sein Projekt also in einen Codespace in der Cloud aus. Technisch gesehen ist jeder Codespace eine virtuelle Maschine, in der Visual Studio Code (VS Code) als Entwicklungsumgebung (IDE) zusammen mit dem ausgecheckten Sourcecode läuft. Standardmäßig bietet sich hierbei die Nutzung im Browser an. Die Arbeit in einer lokalen VS Code-Installation ist ebenfalls möglich, wobei die Runtime und der Code in der Cloud bleiben und nur das GUI der Desktop App benutzt wird.
Gestartet wird der Codespace direkt aus dem jeweiligen Repository für einen bestimmten Branch.
Neben einer Entwicklungsumgebung mit Visual Studio Code besteht die Möglichkeit, VS Code-Erweiterungen und zusätzliche Tools oder Runtimes wie NodeJS, Typescript oder Python zu installieren.
Die gesamte Konfiguration erfolgt über die Cloud-VM und ist damit unabhängig vom lokalen Setup. Somit kann jede EntwicklerIn ihre IDE an jedem Rechner nutzen, ein lokales Setup entfällt.
Codespaces sind an den jeweiligen Benutzer gebunden, d.h. jeder hat eigene, gegebenenfalls auch mehrere Codespaces (bei Bedarf auch vom gleichen Repository), die jederzeit gestoppt (oder bei Inaktivität automatisiert gestoppt) und wieder mit dem eingefrorenen Zustand gestartet werden können.
Codespace sind anpassbar
Ein Feature von Codespaces, das wir in puncto Effizienz sehr schätzen, ist, dass Erweiterungen und Tools für das eigene Repository im Vorfeld in einem devcontainer
JSON File dokumentiert werden können. Ist ein solches File vorhanden, wird bei jeder Erzeugung eines neuen Codespaces (innerhalb dieses Repos) die vordefinierte Umgebung automatisch bereitgestellt.
Als Teil der Codebasis werden devcontainer
genauso wie GitHub Actions versioniert. Ändern sich für ein neues Applikations-Feature die hierfür in der IDE erforderlichen Tools, ändern sich diese eben nur in dem betroffenen neuen Feature Branch. Die eigenständigen Codespaces vereinfachen auf diese Weise das verteilte Arbeiten im Team, wie z.B. Bugfixing im Release Branch und gleichzeitige Neuentwicklung im neuen Feature Branch. Darüber hinaus ist sichergestellt, dass alle im Team automatisch die gleiche Toolchain und die gleiche Umgebung benutzen, was individuelle Probleme mit Builds ausschließt.
Im Folgenden sehen wir ein Beispiel für ein devcontainer
JSON, das drei standardmäßig im Codespace verfügbare Extensions aktiviert:
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"dbaeumer.vscode-eslint",
"ms-vscode.powershell",
"ms-vscode.azurecli"
]
}
}
Gleichzeitig erlaubt der Codespace, dass man die Tooling-Umgebung über Docker definiert und erlaubt damit schon große Freiheitsgrade.
Während in der Anfangsphase für Codespaces nur ein Standardcontainer existierte und wir uns eigene Container für unterschiedliche Umgebungen wie z.B. Python, NodeJS, Powershell und Go bauen mussten, steht inzwischen eine deutlich verbesserte Toolunterstützung seitens GitHub zur Verfügung. Inzwischen stellt GitHub eine vorgefertigte Liste von Basis-Images bereit, die für die meisten Setups ausreichend sind.
Dies beinhaltet den großen Vorteil, dass man die Basis-Images nicht mehr selbst regelmäßig bauen, patchen, pflegen und speichern muss.
Nach der Wahl des Basis Images kann die Wahl der erforderlichen Tools erfolgen, um die für das Repository passende Entwicklungsumgebung zu finalisieren.
Codespaces sind flexibel
Aufgrund der Cloud-Basis kann ein Codespace nicht nur auf jedem Rechner der Welt geöffnet und auf unterschiedlichen Rechnern benutzt werden (wer wollte nicht schon mal schnell zu Hause noch einen Bug fixen), sondern auch in Bezug auf erforderliche Performance (2 vCores oder mehr) skaliert werden. Daneben können Codespaces nach einer gewissen Inaktivität per unternehmensweiter Policy automatisch gestoppt werden, wodurch effizient Kosten gespart werden können.
Die Nutzung im Browser oder im Desktop-Client ist weiterhin reine Geschmackssache ohne Einschränkungen bei den Features. Aus einem Codespace lassen sich auch Ports auf den lokalen Rechner weiterleiten, um z.B. eigene Webanwendung oder Microservices lokal aufzurufen. Selbst VS Code-Erweiterungen wie Liveshare, bei der mehrere Entwickler auf einem Codespace gemeinsam entwickeln, lassen sich problemlos nutzen.
Codespaces sind immer aktuell und sicher
Für Codespaces wird über Dockerfiles eine Umgebung definiert. Diese lässt sich über eine Prebuild Configuration über verschiedene Trigger regelmäßig vorbauen, so dass der Start der Codespaces sehr schnell geht.
Codespace laufen darüber in einer Sandbox und haben keinen Zugriff auf eigene lokale Dateien. Das macht es nicht nur sicherer, sondern stellt auch sicher, dass im individuellen Code keine Referenzen auf Files vorkommen können, die nur auf dem lokalen Rechner eines einzelnen Entwicklers vorhanden sind, z.b. auf c:\temp
.
Codespace Anwendungsfälle (Usecases)
Wir haben für uns festgestellt, dass die IDE-Platzhirsche für Java- und Kotlin-Entwicklung schon sehr mächtig sind und die darüber abgedeckten Usecases zumindest im Augenblick noch nicht die primären Anwendungsfälle von Codespaces sind. So haben die in diesen Entwicklungsumgebungen ausgefeilten Funktionalitäten zur Analyse und zum Debugging von Java-Programmen in den Codespaces noch kein ebenbürtiges Pendant.
Wir benutzen Codespaces für alles, was Script Code oder Infrastruktur Code betrifft. Darunter fallen Python, Typescript, ARM, Bicep, Terraform, Azure Policies und Go. Wir nutzen Codespaces auch häufig für die Implementierung von Azure Functions wie bspw. für Serverless Services.
Damit deckt es in unserem Cloud-/Plattform-Team den wesentlichen Teil unserer täglichen Anwendungsfällen ab. Gefühlt nutzen wir (fast) nichts anderes mehr.
Es ist bestechend einfach, wenn man für jedes Repo, in dem man eine Änderung vornehmen möchte, in wenigen Sekunden eine vollständige IDE öffnen kann. Nach unseren Erfahrungen wechselten wir aus Gewohnheit anfangs noch oft in die Desktop VS Code App. Nach kurzer Eingewöhnung merkten wir im Laufe der Zeit, dass dies keine Vorteile bringt und editiert in der Folge direkt im Browser-basierten Codespace. Wir haben uns nach ausgiebigen Tests in unserem Team entschieden, Codespaces nun für alle EntwicklerInnen freizugeben.
Dabei ist zu beachten, dass Codespaces ein Produkt ist, das nicht in der normalen GitHub Enterprise Lizenz enthalten ist und minutengenau “Pay-as-you-go” abgerechnet wird. Es fallen jedoch nur für aktive Codespaces Gebühren an. Sobald sie sich im gestoppten Zustand befinden und nur noch Speicher verbrauchen, entstehen keine Kosten mehr. Per Policy stoppen wir Codespaces, die nicht aktiv benutzt werden, nach 2 Stunden. So können wir die Kosten automatisiert auf ein überschaubares Maß begrenzen. Auf Knopfdruck lässt sich der eingefrorene Stand jederzeit wieder aktivieren.
Fazit
Aus unser Sicht stellen Codespaces für viele Anwendungsfälle eine wesentliche Vereinfachung für die Entwicklung dar. Es ist definitiv eine Umgewöhnung von der Entwicklung auf einem lokalen Rechner hin zur Entwicklung in einer Cloud-VM.
Für viele Programmier- und Script-Sprachen haben die Codespaces aus unserer Sicht gegenüber lokalen Entwicklungsumgebungen bereits die Nase vorne, da sie
- einfach einzurichten sind,
- bei allen Entwicklern eine identische Grundkonfiguration aufweisen und
- der häufig umfangreiche Initial-Aufwand zur Einrichtung der lokalen Entwicklungsumgebung entfällt.
Die Codespaces erleichtern auch sehr stark die Übergabe von Implementierungsaufgaben von einem Teammitglied zum nächsten, weil alle die gleiche Umgebung teilen, während jeder in seinem Codespace arbeitet.
Bei umfangreichen Programmiersprachen wie Java, in denen mächtige Tools wie IntelliJ in den vergangenen Jahren allerhand Unterstützung bspw. im Bereich des Debuggings und der Code-Analyse für die EntwicklerInnen implementiert haben, können die Codespaces zum jetzigen Zeitpunkt hingegen noch nicht mithalten. Wir sehen allerdings auch hier bereits deutliche Fortschritte, weshalb es nach unserer Einschätzung nur eine Frage der Zeit sein wird, bis Codespaces auch für Java-Enthusiasten eine valide Option sein werden.
Allerdings sind auch wir erst am Anfang unserer Nutzung von GitHub Codespaces und hoffen, dass in Zukunft noch viel mehr Kollegen Codespaces für sich entdecken, benutzen und ihre Erfahrungen miteinander teilen.
Wir blicken diesbezüglich optimistisch in die Zukunft, da sich die Entwicklung von Cloud-basierten IDEs rasant fortsetzt. Microsoft hat gerade die Dev Box angekündigt und auch beim IntelliJ-Hersteller Jetbrains sind ähnliche Angebote in der Vorbereitung. Wir werden Codespaces weiterhin intensiv evaluieren und freuen uns darauf, uns mit Euch über Eure und unsere Erfahrungen auszutauschen.