Vor einer Woche wurde unser Hacking-Buch ausgeliefert. Heute hat es schließlich den Weg bis nach Graz gefunden. Einzig Amazon glaubt noch immer, dass es das Buch erst in ein bis zwei Monaten liefern kann. (Update: Amazon hat die Bücher gefunden, sie sind nun auch dort sofort lieferbar.) Bestellen Sie das Buch am besten direkt im Rheinwerk Verlag! Das hat den Vorteil, dass Ihnen dort das Kombiangebot Buch/Ebook zur Auswahl steht.
Entstehungsgeschichte
Langwierig ist nicht nur die Auslieferung, lange ist auch die Entstehungsgeschichte des Buchs: Zum ersten Mal hat Sebastian Kestel, damals Lektor beim Rheinwerk-Verlag, 2014 bei mir angefragt, ob ich mir vorstellen könnte, ein Hacking-Buch zu machen. Mein erster Gedanke war zwar kein kategorisches »Nein«; es war mir aber bewusst, dass ich alleine unmöglich in der Lage wäre, ein umfassendes und fundiertes Buch zum Thema »Hacking und Security« zu machen. Denn schon damals war mir klar, dass ein derartiges Buchs mehr sein müsste als eine Vorstellung von Kali Linux und ein paar der dort vorhandenen Tools.
»Hacking« ist sicherlich ein spannendes Thema, aber es kann nur der erste Schritt sein. »Security« ist die logische Konsequenz, die aus allen Hacking-Möglichkeiten zu ziehen ist: Wie können Windows- und Linux-Server, Smartphones und Cloud-Anwendungen allen Hacking-Tools zum Trotz möglichst sicher betrieben werden? Diese Themenfülle ist überwältigend, und so habe ich mich vorerst anderen Dingen zugewandt, unter anderem der App-Programmierung mit Swift.
Sebastian Kestel blieb hartnäckig und meldete sich Mitte 2016 neuerlich, diesmal mit zwei weiteren Autoren in der Hinterhand, die den Großteil der Themen inklusive Windows und Mobile Security abdecken würden. Ich müsste »nur« zu Grundlagenthemen und Linux schreiben — und eventuell noch einen Autor für den Cloud-Aspekt finden. Das klang plausibel, und unter diesen Voraussetzungen gab ich dann, immer noch mit etwas Bauchweh, mein OK. Ich entwarf ein erstes Konzept für das Buch und begann an meinen eigenen, zumeist Linux-nahen Kapiteln zu arbeiten.
Aber es kam natürlich ganz anders: Anfang 2017, als der Vertrag bereits aufgesetzt war, sprang der Hauptautor für das Buch ab. Er hätte Texte zu Penetration Testing, Windows-Hardening, WLAN-Hacking usw. verfassen sollen. Zu diesem Zeitpunkt hatte ich schon eine Menge Zeit investiert, rund 100 Seiten formuliert und mich mit dem Thema »Hacking und Security« ganz generell angefreundet.
Und so fiel Anfang 2017 die Entscheidung, dass ich an dem Buch nicht nur als Autor, sondern auch als Herausgeber arbeiten würde. Hätte ich gewusst, was danach auch mich zukam, hätte ich hier garantiert den Schlussstrich gezogen! Stattdessen machten Sebastian Kestel und ich mich auf die Suche nach neuen Autoren und versuchten, diese von meinem Konzept und meinem Workflow (Markdown statt Word) zu überzeugen. Im Verlauf eines halben Jahres war ich mit vielen Hacking- und Security-Experten im Gespräch. Viele Absagen bekam ich deshalb, weil Leute, die sich in diesem Umfeld auskennen, oft ununterbrochen im »Feuerwehreinsatz« stehen. Gleichzeitig änderte sich das Detailkonzept des Buchs mit dem allmählich neu wachsenden Autoren-Team quasi wöchentlich.
Letztlich haben neun Autoren (inklusive mir) Kapitel für das Buch verfasst. Der Vorteil von derart vielen Autoren ist, dass jeder auf seinem Gebiet unumstritten Experte ist — mit einer großen Fülle an technischen Wissen und Praxiserfahrung. Der offensichtliche Nachteil besteht aber darin, dass die Koordination, die Abstimmung der Inhalte, das Sicherstellen des »Roten Fadens« entsprechend schwieriger werden. Gleichzeitig gab es auch im Rheinwerk Verlag Änderungen: Sebastian Kestel, der ursprüngliche Ideenstifter des Buchs, hat den Verlag verlassen. Zum Glück hatte ich mit dem neuen Lektor Christoph Meister zuvor schon einige andere Bücher gemacht, so dass es zumindest auf dieser Ebene keine Probleme gab.
Langer Rede kurzer Sinn: Anfang April ist das Buch in Druck gegangen. Aus den ursprünglich geplanten 700 bis 800 Seiten sind fast 1100 geworden. Ein großes Dankeschön geht dafür an meine Co-Autoren und an das Team vom Verlag, das sich um Korrekturen, Abbildungen, Marketing, das Titelbild (dazu sage ich nur so viel: es gab mehrere Entwürfe …) etc. gekümmert hat!
Und auch wenn mir selbst inzwischen der Abstand fehlt, um das objektiv zu beurteilen: im Großen und Ganzen ist das Ergebnis wohl ganz respektabel ausgefallen. Ich denke, es gelingt unserem Buch, einen soliden und thematisch breiten Einstieg in das Thema Hacking und Security zu geben.
Der aus meiner Sicht größte Vorteil des Umstiegs von Unity auf Gnome besteht darin, dass sich Ubuntu nun wesentlich freier konfigurieren lässt. In den folgenden Schritten stelle ich Ihnen meine persönliche Konfiguration vor. Vermutlich haben Sie ganz andere Vorlieben — aber vielleicht ist ja der eine oder andere Baustein dabei, nach dem Sie auch schon gesucht haben. (Wenn Sie eigene Tipps, haben, dürfen Sie gerne einen kurzen Kommentar verfassen …)
Ubuntu-Desktop nach der Art des Hauses …
Gnome Tweaks
Die Gnome-Philosophie ist es, seine Anwender nicht durch unnötige Optionen zu verwirren. Erfreulicherweise können viele nützliche Einstellungen aber ganz unkompliziert in den Gnome Tweaks (deutscher Programmname Optimierungen) vorgenommen werden. Die Installation erfolgt mit apt install gnome-tweaks. Dort können Sie unter anderem einen freien Skalierungsfaktor für alle Schriften einstellen, Modale Dialoge vom Hauptfenster lösen, Fensterbuttons links oder rechts anzeigen etc.
Gnome Shell Extensions
Damit Gnome-Erweiterungen im Webbrowser konfiguriert werden können, müssen Sie ein zusätzliches Paket installieren: apt install chrome-gnome-shell. Danach besuchen Sie die Seite https://extensions.gnome.org. Dort klicken Sie auf den Link Click here to install browser extension und erlauben Sie die Aktivierung dieser Browser-Erweiterung. Anschließend laden Sie die Seite neu.
Die Liste der aktiven Shell-Erweiterungen
Dock
Ubuntus Dock ist eine reduzierte Variante der beliebten Gnome-Erweiterung Dash to Dock. Das Original bietet mehr Konfigurationsmöglichkeiten, weswegen ich die Erweiterung zuerst im Webbrowser installiert und das entsprechende Ubuntu-Paket dann entfernt habe: apt remove gnome-shell-extensions-ubuntu-dock. (Ohne die De-Installation kämpfen zwei Dock-Erweiterungen gegeneinander. Das eigentlich deaktivierte Dock von Ubuntu taucht nach Updates sonst immer wieder auf.)
Neben diversen Optionen, die die optische Gestaltung des Docks betreffen (z.B. dass das Dock nicht größer als 90% der Bildschirmhöhe werden soll), finden sich in den Konfigurationdialogen auch ausgesprochen nützliche Funktionen: Beispielsweise bewirkt die Einstellung Wirkung bei Mausklick = Minimieren, dass die betroffenen Fenster ein- und wieder ausgeblendet werden.
Die originale »Dash to Dock«-Erweiterung bietet mehr Konfigurationsmöglichkeiten als die Ubuntu-Variante.
Ubuntu-Icon anstelle von »Aktivitäten«
Der Button Aktivitäten ist optisch ein Fremdkörper im Gnome-Panel. Ein dezentes Icon reicht vollkommen aus. Die Erweiterung Activities Configurator bietet neben unzähligen anderen Optionen die Möglichkeit, hierfür eine Bitmap-Datei auszuwählen. Ich habe das Ubuntu-Logo verwendet (/usr/share/icons/Humanity/places/64).
Der »Activities Configurator« steuert das Aussehen und Verhalten der Panel-Zeile.
Systemmonitor
Techniker der ich nun mal bin will ich wissen, was auf meinem Rechner vor sich geht. Meine diesbezüglichen Wünsche erfüllt die Erweiterung system-monitor. Bevor die Erweiterung im Webbrowser aktiviert werden kann, müssen allerdings diverse Pakete installiert werden:
Im Konfigurationsdialog von »system-monitor« kann genau eingestellt werden, welche Statusinformationen wie im Panel bzw. im Menü präsentiert werden sollen.
Touchpad deaktiveren, sobald eine Maus angeschlossen ist
Das Touchpad meines Notebooks in Ehren, aber sobald ich eine Maus angeschlossen habe, ist mir die lieber. Und dann soll das Touchpad automatisch deaktiviert werden, um unbeabsichtigte Mausbewegungen und -klicks zu verhindern. Genau das kann die Erweiterung Touchpad Indicator. Damit die Erweiterung wunschgemäß funktioniert, müssen Sie im Konfigurationsdialog der Erweiterung im erste Dialogblatt die Umschaltmethode Xinput auswählen und im zweiten Dialogblatt die Option Touchpad automatisch ein- bzw. ausschalten aktivieren.
Konfiguration des Touchpad-Indikators
Alt+Tab wiederherstellen
Gnome kennt viel zu viele Tastenkürzel, um zwischen Fenstern und Programmen zu wechseln. Mir reicht eine, und die soll funktionieren, wie es einst unter Windows der Fall war. Diesen Wunsch erfüllt die simple Erweiterung Alternate Tab.
CapsLock deaktivieren
Die überflüssigste Taste jeder Tastatur ist CapsLock. Immer wieder führt ein unbeabsichtigtes Drücken zur eINGABE FEHLERHAFTEN tEXTS. Abhilfe: Im Programm Optimierungen (also Gnome Tweaks) gibt es im Dialogblatt Tastatur und Maus den merkwürdig beschrifteten Button Zusätzliche Belegungsoptionen. Er führt in einen Dialog, in dem Sie die Funktionen diverse Spezialtasten (Strg, Alt, Windows, CapsLock) verändern können. Dort gibt es auch die Möglichkeit, CapsLock ganz zu deaktivieren.
CapsLock ade
Nachtmodus
Gnome kann die Monitorfarben in der Nacht mit weniger Blau- und mehr Gelb- und Orange-Tönen darstellen. Das schont die Augen, ist aber natürlich zur farbechten Bearbeitung von Fotos ungeeignet. Die Option findet sich unter den gewöhnlichen Einstellungen (Dialogblatt Geräte / Anezigegeräte).
Wie die meisten gewerblich tätigen Menschen ganz Europas habe ich in den letzten Tagen jede sinnvolle Arbeit liegen und stehen gelassen und stattdessen eine Datenschutzerlärung verfasst. Ich weiß, keiner wird sie lesen, so wie keiner die durch und durch sinnlosen Cookie-Warnungen wahrnimmt und blind auf ‚Ich bin einverstanden‘ klickt.
Die Intention des DSVGO ist ohne Zweifel gut. Jeder hat ein Recht auf seine Privatsphäre — selbst im Internet. Die DSVGO soll helfen, dass wir diese Privatsphäre ein ganz klein wenig zurückbekommen. Vielleicht …
Leider leben die Leute, die dieses Gesetz formuliert haben, auf einem anderen Stern. Zwei Dinge stören mich:
Alle sind gleich. Aber die Großen sind im Vorteil.
Für Facebook und Amazon gelten (nahezu) die gleichen Regeln wie für den Betreiber einer winzigen Website. Aber während Facebook oder Google genug juristisches Personal haben, um die DSVGO tatsächlich zu lesen, zu verstehen und vielleicht sogar zu befolgen (Google spricht von einem Aufwand von 500 Mannjahren/Fraujahren), folgen Klein- und Kleinstunternehmer den Ratschlägen irgendwelcher Computer-Zeitschriften, Websites etc. WordPress bietet in der neuesten Version fertige Textbausteine an, um die Datenschutzerklärung zusammenzuschustern. (Mit der Datenschutzerklärung ist es nicht getan, ich weiß; aber aktuell geht es einmal darum, dass bis zum 25.5. die nach außen sichtbare Fassade hübsch aussieht.)
Die DSVGO ignoriert, dass die unternehmerischen Voraussetzungen bei Kleinbetrieben anders aussehen als bei großen Konzernen. Statt gewisse Forderungen von Umsatzgrößen, Datenmengen oder anderen Parameter abhängig zu machen, werden alle über einen Kamm geschert.
Wer profitiert davon?
Die Großen. (Ähnliche Gedanken habe ich vor ein paar Jahren in einem ganz anderen Zusammenhang schon einmal formuliert, siehe Alle Macht den Großen.)
Juristen, Rechtsanwälte etc.
Viele Regeln sind praxisfern
Allein die Länge des DSVGO (hier nachzulesen) macht klar, dass es sich um ein Werk von Juristen für Juristen handelt. (OK, das haben Gesetzestexte so an sich …)
Mit der IT-Praxis ist dieser Text oft schwer vereinbar. Um ein Beispiel zu nennen: Gemäß $17 DSVGO gibt es das Recht auf Löschung personenbezogener Daten. Das ist je nach Kontext nachvollziehbar und auch durchführbar.
Aber anscheinend umfasst dieses Recht auch Backups (Quelle). Und hier endet die Durchführbarkeit. Es ist sicher möglich, aus einem Aktivsystem gewisse Datensätze zu löschen. Aber angenommen, es gibt tägliche Datenbank-Backups, wöchentliche Snapshots der virtuellen Maschine, auf dem der Datenbank-Server läuft etc. (Die DSVGO verlangt ja auch, dass alles technisch und menschlich Mögliche getan wird, um die Daten zu schützen …) Wie sollen personenbezogene Daten aus Backups entfernt werden? Das ist in der Praxis ganz einfach undenkbar.
Oder, um ein zweites Beispiel zu nennen: Newsletter und Werbe-Mails dürfen nur mit ausdrücklicher Einwilligung des Empfängers versendet werden (§6 DSVGO). An sich auch vernünftig, auch wenn der Einwilligungsformalismus und die Nachweispflichten viel zu weit gehen. Sicher nicht an diese Regeln halten werden sich die, die das E-Mail-System schon jetzt missbrauchen und unsere Postfächer mit Spam für Viagra, kostenlosen Bitcoins und anderem Unfug zumüllen. Die Angst vor Spam wird dazu führen, dass die meisten Anwender die freundliche Anfrage, ob weiterhin ein wöchentlicher Newsletter versendet werden darf, ganz einfach ignorieren (wenn die Mail nicht sowieso im Junk-Ordner landet). Oder, hart formuliert: Wer sich an die Regeln hält, hat beim E-Mail-Marketing von vorne herein verloren.
Regulierungswut
Ich bin von den Ideen der EU, von den Grundwerten Europas zutiefst überzeugt. Aber ist es wirklich unmöglich, an sich sinnvolle Ziele (den Datenschutz) in praxisnahen, kompakten, verständlichen Gesetzen zu formulieren?
Der unmittelbare »Nutzen«, den die DSVGO aktuell bringt, besteht darin, dass Millionen von Websites durch eine Datenschutzerklärung ergänzt werden. Keiner wird sich dafür interessieren, keiner wird sie lesen, und es ist befürchten, dass selbst die meisten Betreiber von Websites nicht verstehen, was nun eigentlich in ihrer Datenschutzerklärung steht. Wird das Internet dadurch sicherer?
openSUSE hat mit seinem jüngsten Release einen Versionsnummernsprung zurück gemacht. Die Versionsnummer 15 (zuletzt 42.3) soll die Synchronizität mit SUSE Linux Enterprise (SLE) zum Ausdruck bringen — wobei SLE 15 aber noch gar nicht fertig ist.
KDE ist weiterhin das Default-Desktopsystem von openSUSE
Installation
openSUSE steht nur noch als 64-Bit-Version zur Verfügung. Das Installationsprogramm wurde in einigen Details vereinfacht. Standardmäßig schlägt openSUSE weiterhin ein btrfs-Dateisystem für die Systempartition und ein xfs-Dateisystem für /home vor. Im Root-Dateisystem gibt es nun aber weniger btrfs-Subvolumes. Insbesondere wurden alle /var-Subvolumes zu einem Volume zusammengefasst, für das die Option nocow gilt. Das ist mit Geschwindigkeitsvorteilen beim Logging sowie beim Ändern von Datenbank- und Image-Dateien (Virtualisierung) verbunden.
Partitionierungsvorschlag im openSUSE-Installationsprogramm
Versionsnummern
Die Versionsnummern sind openSUSE-typisch ein Mix zwischen der stabilen Basis von SLE und neueren Desktop-Paketen:
KDE setzt sich aus Plasma 5.12, dem KDE Framework 5.45 und den KDE Applications in der Version 17.12 zusammen. Alternativ kann Gnome in Version 3.26 als Desktop-System installiert werden. Java liegt in der aktuellen Version 10 vor. Wie openSUSE mit den halbjährlichen Java-Updates umgehen will, ist mir nicht bekannt. Auch die Release Notes zur noch im Beta-Test befindlichen SLE-15-Version schweigen sich dazu aus.
Das Paket zypper lifecycle verrät, wie lange die Distribution gewartet werden soll:
zypper lifecycle
Product end of support
Codestream: openSUSE Leap 15 2021-11-30
openSUSE Leap 15.0 2019-11-30
No packages with end of support different from product.
Wenn zypper lifecycle Pakete entdeckt, für die Updates zur Verfügung stehen bzw. für die andere Wartungszeiträume gelten, werden diese explizit aufgezählt.
Neuerungen
Außer den Versionsnummern gab es auch auf technischer Ebene einige Neuerungen:
Firewall: openSUSE hat das Firewall-System firewalld von RHEL/Fedora übernommen. Auf eine Integration in YaST hat man verzichtet. Das entsprechende YaST-Modul startet einfach das aus Red-Hat-Systemen bekannte Programm firewall-config.
DKMS: Zur Verwaltung von zusätzlichen Kernelmodulen, die im Quellcode zur Verfügung stehen, verwendet openSUSE nun wie die meisten anderen Distributionen DKMS.
Chrony: Um die Synchronisierung der Uhrzeit kümmert sich nun Chrony, nicht mehr ntpd.
Transaktionaler Server: Während der Installation können Sie im Desktop-Auswahldialog nicht nur zwischen KDE und Gnome wählen, sondern openSUSE auch als Server bzw. als Transaktionalen Server einrichten. Dabei führt openSUSE Updates in Form von Transaktionen durch; sollte ein Update fehlschlagen, wird der gesamte Update-Prozess widerrufen. Details zu diesem Verfahren, das btrfs als Dateisystem voraussetzt, können Sie in den Release-Notes und im openSUSE-Blog nachlesen.
update-alternatives: Einige Einstellungen, die bisher in /etc/sysconfig gespeichert wurden, werden jetzt durch update-alternatives verwaltet. Dazu zählen der Display-Manager und das Default-Desktop-System (siehe die Release Notes). Wem das Kommando update-alternatives nicht zusagt, kann stattdessen das neue YaST-Modul yast2-alternatives installieren.
Ein komplettes Update der aktuellen Version durchführen
Nicht offizielle Paketquellen deaktivieren
Optional: alle /var/xxx-Subvolumes auf /var zusammenfassen (siehe Punkt 3 in der Update-Anleitung)
In der Beschreibung der Paketquellen: 42.3 durch 15.0 ersetzen (sed)
Das eigentliche Distributionsupdate mit zypper dup starten
zypper update
sed -i 's/42.3/15.0/g' /etc/zypp/repos.d/*
zypper ref
zypper dup
...
1467 packages to upgrade, 531 to downgrade, 657 new, 232 to remove, 7 to change arch.
Overall download size: 1.78 GiB. Already cached: 0 B.
After the operation, additional 1.1 GiB will be used.
...
Ein Update-Test in einer VirtualBox-Maschine ist problemlos verlaufen. (Auf ‚echten‘ Installationen ziehe ich generell — unabhängig von der Distribution — eine Neuinstallation vor.)
Vapor ist ein Swift-Framework zur Programmierung von Server-Anwendungen. Zwar ist es möglich, damit z.B. auch einen eigenen Webserver zu gestalten, in der Praxis werden mit Vapor aber überwiegend REST-APIs implementiert.
Derartige APIs können testweise unter macOS laufen; für den Praxisbetrieb kommt dann zumeist ein eigener Ubuntu-Server oder eine entsprechende Cloud-Instanz zum Einsatz.
Als ich im August 2017 für meinem Buch Swift 4 ein Kapitel über Vapor verfasste, dachte ich, in ein paar Wochen würde die aktualisierte Version Vapor 3 fertig werden, die dann (vollständig) Swift-4-kompatibel wäre. Da habe ich mich gleich in zweierlei Hinsicht getäuscht: Zum einen dauerte die Fertigstellung von Vapor 3 bis Mai 2018. Zum anderen war es kein kleines Update, sondern weitestgehend eine Neuimplementierung dieses Frameworks.
Neu in Vapor 3
Bis auf ein paar Grundkonzepte ist in Vapor 3 kein Stein auf dem anderen geblieben; auch nahezu alle Bibliotheken wurden erneuert oder umfassend verändert:
Asynchron: Vapor 3 arbeitet nun vollständig asynchron und greift dabei auf Futures zurück (Doku: Async, Async Overview).
Codable: Anstelle der Vapor-2-eigenen JSON-Klasse greift Vapor 3 umfassend auf das in Swift 4 eingeführte Codable-Protokoll zurück. Das gibt mehr Typsicherheit in eigenen Datenmodellen. (Doku: Content)
Projektkonfiguration: In Vapor 2 wurden einige Aspekte der Konfiguration in JSON-Dateien ausgedrückt (z.B. Config/server.json). Diese Dateien werden in Vapor 3 nicht mehr unterstützt. Stattdessen erfolgt die Konfiguration durch Swift-Code, der Service-Strukturen verändert (Doku: Services-Struktur, Using Services).
Bibliotheken: Vapor 3 verwendet überwiegend dieselben Bibliotheken wie Vapor 2, also z.B. Crypto, Fluent, HTTP, MySQL, PostgreSQL, SQLite und natürlich Vapor. Allerdings wurden alle Bibliotheken grundlegend modernisiert und z.T. umfassend verändert. Die HTTP-Bibliothek greift jetzt auf das von Apple entwickelte NIO-Framework zurück (Doku: Vapor Docs, Swift NIO Intro, Swift NIO auf GitHub). Einige Bibliotheken wurden ganz entfernt, weil sie aufgrund von neuen Konzepten nicht mehr benötigt werden. Das betrifft unter anderem Droplet (-> NIO), Config (-> Service) und JSON (-> Codable).
Die Portierung vorhandener Vapor-Projekte auf Version 3 ist deswegen weitgehend unmöglich. Die Vapor-Dokumentation empfiehlt, ein neues Projekt in Vapor 3 zu starten und vorhandenen Code schrittweise und manuell zu migrieren und an die neuen Vapor-Konzepte anzupassen.
In seiner Anwendung weitgehend unverändert geblieben ist immerhin das Kommando vapor (die »Toolbox«, Doku), mit dem Vapor-Projekte eingerichtet und verwaltet werden. Intern greift das vapor-Kommando stark auf den Swift Package Manager zurück.
Installation unter macOS
Voraussetzung für die Verwendung von Vapor unter macOS ist einerseits natürlich Xcode (ich habe für diesen Test mit Xcode 9.3 / Swift 4.1 gearbeitet), andererseits der Paketmanager Homebrew. Sie installieren Vapor wie folgt im Terminal:
brew install vapor
Mit vapor version (wieder im Terminal) können Sie überprüfen, ob alles geklappt hat:
vapor version
Vapor Toolbox: 3.1.7
Hello World!
Um Vapor kennenzulernen, richten Sie ein Hello-World-Projekt ein. Das Kommando vapor new unterstützt Sie dabei, greift aber auf git zurück. Wenn Sie git bisher nicht bzw. nur aus Xcode heraus verwendet haben, müssen Sie deswegen zuerst eine minimale git-Konfiguration durchführen und Ihren Namen und Ihre E-Mail-Adresse speichern:
cd <in ein Verzeichnis Ihrer Wahl>
vapor new Hello --verbose
Der so initialisierte Muster-Code besteht aus etlichen Dateien. Um das Projekt zu kompilieren und auszuführen, wechseln Sie in das Projektverzeichnis und rufen das Kommando vapor build auf. Das dauert beim ersten Mal circa eine Minute, weil erst jetzt die für das Projekt erforderlichen externen Bibliotheken heruntergeladen und kompiliert werden. Weitere Build-Vorgänge verlaufen dann wesentlich schneller. Bei meinen Tests scheiterte der erste Durchlauf von vapor build manchmal mit einem Fehler. Beim zweiten Versuch klappte es dann.
cd Hello
vapor build --verbose
...
Building Project [Done]
Sie starten das Programm mit vapor run. Die Server-App läuft nun, bis Sie diese mit Strg+C beenden. Während sie läuft, können Sie mit ihr in einem Webbrowser über den Port 8080 kommunizieren. Die Adresse http://localhost:8080/hello führt in die Hello-World-Zeile.
»Hello World«-Seite eines Vapor-Projekts im Webbrowser
Projekt in Xcode bearbeiten
Grundsätzlich können Sie die Dateien eines Vapor-Projekts natürlich mit jedem beliebigen Editor bearbeiten. Mehr Komfort bietet aber Xcode. Erzeugen Sie also mit vapor xcode die erforderlichen Projektdateien und öffnen Sie dann das neue Projekt:
vapor xcode
Generating Xcode Project [Done]
Select the `Run` scheme to run.
Open Xcode project?
y/n> y
In Xcode müssen Sie nun das Schema Run/My Mac auswählen und können das Projekt dann direkt in Xcode kompilieren und ausführen.
Vapor-Projekt in Xcode bearbeiten
Damit das Projekt den Aufruf von http://localhost:8080/hello mit ‚Hello, world!‘ beantwortet, ist der folgende, standardmäßig im Projekt enthaltene Code verantwortlich:
// Datei Sources/App/routes.swift
import Vapor
public func routes(_ router: Router) throws {
// Basic "Hello, world!" example
router.get("hello") { req in
return "Hello, world!"
}
// weiterer Code für Todo-Controller ...
}
Todo-API
Der Hello-World-App enthält mehr Funktionen, als auf den ersten Blick erkenntlich sind: Ein extrem simpler Todo-Controller ist in der Lage, über eine REST-API Todo-Einträge zu speichern und wieder abzurufen.
POST http://localhost:8080/todos: JSON-Daten zur Speicherung eines Todo-Eintrags übergeben (siehe die folgende Abbildung)
Um diese Funktionen auszuprobieren, verwenden Sie am besten ein REST-Tool wie Postman oder RESTed.
Test der REST-API mit »Postman«
Der dafür erforderliche Code umfasst gerade einmal 40 Zeilen und verteilt sich auf die folgenden Dateien:
Sources/App/routes.swift
Sources/App/Controllers/TodoController.swift
Sources/App/Models/Todo.swift
Der Code kann der Ausgangspunkt für eigene Experimente mit Vapor sein. Beachten Sie, dass die Todo-Einträge nur im Arbeitsspeicher. Sobald die Ausführung der Server-App endet, gehen alle Einträge wieder verloren. Natürlich können Sie die Daten auch dauerhaft in einer Datenbank speichern — aber dann steigt die Komplexität des Codes gleich erheblich an.
Eigener Code
Zum Kennenlernen von Vapor bietet es sich an, das vorgegebene Hello-World-Projekt ein wenig zu erweitern. Wenn Sie beispielsweise möchten, dass die Server-App auf den GET-Request http://localhost:8080/now mit der aktuellen Uhrzeit antwortet, ergänzen Sie die Datei routes.swift wie folgt:
// Datei Sources/App/routes.swift
public func routes(_ router: Router) throws {
router.get("now") { req -> String in
let now = Date()
let formatter = DateFormatter()
formatter.dateFormat = "d.M.yyyy H:mm"
let nowfmt = formatter.string(from: now)
return nowfmt
}
...
}
Wenn Vapor auf einen Request mit einer JSON-Struktur antworten soll, richten Sie eine Struktur ein, die von Content abgeleitet ist. (Content ist ein in der Vapor-Bibliothek definiertes Protokoll, welches wiederum vom in Swift 4 eingeführte Codable-Protokoll abgeleitet ist und daher JSON unterstützt.)
// Datei Sources/App/routes.swift
public func routes(_ router: Router) throws {
router.get("jsondata") { req -> MyData in
return MyData(id: 42, txt: "bla")
}
...
}
struct MyData: Content {
var id: Int
var txt: String
}
Binding/Port ändern
Die Vapor-App verwendet standardmäßig den Port 8080 und die IP-Adresse 127.0.0.1 (localhost). Ein davon abweichendes Binding können Sie in configure.swift einstellen:
// in der Datei HelloVapor/Sources/App/configure.swift
public func configure(_ config: inout Config,
_ env: inout Environment,
_ services: inout Services) throws
{
// vorhandenen Code belassen
...
// Bind-Adresse und Port einstellen
let serverConfigure =
NIOServerConfig.default(hostname: "0.0.0.0", port: 8081)
services.register(serverConfigure)
}
Die IP-Adresse 0.0.0.0 ist erforderlich, wenn Sie Vapor in einem Docker-Container ausführen und den Port an den Docker-Host weiterleiten möchten.
Deployment
Zu Vapor gibt es eine eigene Cloud-Infrastruktur, die wohl auch zum Geschäftsmodell für das Projekt werden soll. Mit vapor cloud deploy kann ein Projekt unkompliziert in die Vapor-Cloud übertragen werden. In einer Minimalkonfiguration samt Datenbank kostet das aktuell 13 Dollar im Monat (siehe die Preisliste).
Wer über etwas Linux-Knowhow verfügt, kann Vapor und Swift aber auch recht unkompliziert unter Ubuntu (oder in einem auf Ubuntu basierenden Docker-Container) installieren, den Quellcode des eigenen Projekts dort neu kompilieren und schließlich ausführen. Eine kurze Anleitung zur Ubuntu-Installation von Vapor 3 finden Sie hier.
Vapor verwendet standardmäßig HTTP. Die Brücke zum sicheren HTTPS errichten Sie auf einem eigenen Server am besten mit Apache oder Nginx: Eine Proxy-Konfiguration verbindet dann den Port 8080 von Vapor mit Port 443 des Webservers. Gegenwärtig gibt es dazu noch keine auf Vapor 3 aktualisierte Dokumentation. Grundsätzlich hat sich die Vorgehensweise im Vergleich zu Vapor 2 aber kaum geändert, weswegen Vapor 2 Nginx Deployment und Vapor 2 Apache Deployment weiterhin gültig bleiben.
Praxiserfahrungen
Vapor ist auch in Version 3 ein faszinierendes Projekt. Es gibt aber Verbesserungspotential:
In vielen Situationen steht in Xcode keine kontextabhängige Hilfe für Vapor-Klassen, -Protokolle etc. zur Verfügung. Auch die automatische Vervollständigung funktioniert häufig nicht. Das macht das Arbeiten unnötig mühsam, wobei schwer zu sagen ist, ob die Schuld bei Apple/Xcode liegt oder bei Vapor.
Die Vapor-Dokumentation macht nur auf den ersten Blick einen guten Eindruck. Viele Fragen bleiben offen, praxisnahe Code-Beispiele fehlen. Selbst simple Aufgaben lassen sich nur durch langwieriges Suchen und Probieren lösen.
Die Verwendung von Discord als zentrale Diskussionsplattform für das Vapor-Projekt macht das dort gesammelte Wissen von außen schwer zugänglich (z.B. für Google-Suchen). Die unübersichtliche Gestaltung der Discord-Website verschlimmert die Situation weiter.
Die radikale Neugestaltung des Frameworks ohne Rücksicht auf Kompatibilität ist zwar im Sinne eines sauberen Neustarts verständlich, wurde aber viel zu spät kommuniziert. Wer auf Vapor 2 gesetzt hat, steht jetzt dumm da (so wie ich …). Das schafft keine Vertrauensbasis für die Zukunft.
Das Ebook von Paul Hudson ist aus meiner Sicht enttäuschend: 1/4 des Texts gibt eine Einführung in Swift, die für die Zielgruppe des Buchs irrelevant ist. Danach kreisen viele Beispiele um traditionelle Webserver-Anwendungen. Das Schlagwort ‚REST API‘ kommt im gesamten Buch nicht vor. Paul Hudson erklärt zweifellos viele Vapor-Grundlagen, aber die Beispiele wirken komplett praxisfern.
Ein endgültiges Urteil über das Ebook von Ray Wenderlich fällt schwer, weil das Buch noch nicht fertig ist. (Einige Kapitel fehlen noch. Wenn Sie das Buch jetzt kaufen, bekommen Sie regelmäßig Updates.) Inhaltlich bietet die schon fertigen Teile des Buchs aber ungleich mehr Tiefgang. Allein schon die Kapitelüberschriften zeigen, dass dieses Buch in die richtige Richtung geht:
Das Vapor-Buch von Wenderlich et al in iBooks
Dafür sind formale Aspekte ärgerlich: Die PDF-Version hat weder ein ‚richtiges‘ Inhaltsverzeichnis (das typischerweise in der Seitenleiste des PDF-Viewers angezeigt wird) noch anklickbare Links in der Textform des Inhaltsverzeichnisses. Steinzeitlich! Die EPUB-Version funktioniert in dieser Hinsicht besser, irritiert aber mit halb-leeren Seiten (wegen ungünstigen Seitenumbrüchen) und anderen Layout-Defiziten.
Letztlich zählt der Inhalt, und diesbezüglich bietet das Wenderlich-Buch definitiv mehr.
Seit zwei Tagen ist das erste Service-Update von Ubuntu 18.04 verfügbar. Geändert hat sich (außer den üblichen Updates) nichts. Wenn Sie Ubuntu 18.04 installiert haben und alle Updates durchgeführt haben, dann zeigt /etc/os-release jetzt Version 18.04.1.
Der springende Punkt dieses Minor-Updates besteht darin, dass bei dieser Gelegenheit auch neue Installations-Images erstellt wurden. Das erspart einerseits riesige Updates unmittelbar nach der Installation und gibt Canonical andererseits die Möglichkeit, Probleme im Installer zu beheben. Bei den gewöhnlichen Desktop-Images (Installationsprogramm »Ubiquity«) gibt es hier keine sichtbaren Änderungen, ebensowenig im von Debian übernommenen traditionellen Server-Installationsprogramm (Download-Seite).
Große Änderungen hat es dagegen beim relativ neuen Server-Installationsprogrammm (»Subiquity«) gegeben (Download-Seite) — und davon handelt dieser Beitrag.
Subiquity 18.04: Elegante Server-Installation ohne LVM und RAID
In Version 18.04 wurde Subiquity vielfach gelobt, weil das text-basierte Installationsprogramm wesentlich komfortabler zu bedienen ist ist der bisherige ‚Alternate-Installer‘. Server-Administratoren wurden mit Subiquity aber trotzdem nicht glücklich: LVM und RAID wurden nicht unterstützt, vorhandene Dateisysteme auf der Festplatte konnten nicht weitergenutzt werden etc. Subiquity war einer LTS-Version wahrlich unwürdig.
Subiquity 18.04.1: Neuer Versuch, immer noch nicht viel besser
Mit dem Release 18.04.1 wollte Canonical es besser machen. LVM und RAID (Level 0, 1, 5, 6, 10) werden nun offiziell unterstützt. Die Navigation durch die Partitionierungsmenüs ist einfacher als beim Alternate-Installer, aber zufriedenstellend funktioniert der Installer leider weiterhin nicht.
Für meine Tests habe ich eine virtuelle Maschine mit zwei Festplatten eingerichtet. Mein Ziel war eine RAID-1-Konfiguration mit LVM, also das, was ich auf meinen realen Servern üblicherweise verwende: Die beiden Festplatten werden zu einem RAID-1-Verbund kombiniert (Mirroring), darin wird ein LVM-System eingerichtet, und in diesem die Logical Volumes für Swap, / (Root) und /boot.
Im ersten Versuch habe ich das Setup so gewählt:
in beiden Festplatten eine möglichst große Partition einrichten
diese Partitionen zu RAID-1 verbinden
darin LVM aufsetzen
darin Logical Volumes für /boot, Swap und / einrichten
Obwohl die Menüführung unkompliziert ist, dauert es ein paar Minuten, um alle Einstellungen durchzuführen. Zum Schluss meckert Subiquity aber, dass die /boot-Partition direkt auf einer Festplatte sein müsse.
Gut, es ist üblich, dass /boot außerhalb von LVM ist, auch wenn GRUB durchaus damit zurecht kommen würde. Also zweiter Versuch:
in den beiden Festplatten je zwei Partitionen einrichten, eine kleine und eine große
die beiden kleinen Partitionen zum RAID-Verbund 1 verbinden
RAID-Verbund 1 direkt für /boot nutzen
die beiden großen Partitionen zum RAID-Verbund 2 verbinden
im RAID-Verbund 2 LVM einrichten
dort Logical Volumes für Swap und / einrichten
Subiquity ist immer noch nicht zu frieden. /boot muss direkt auf einer Festplatte liegen, auch RAID ist verboten. Das ist eine absurde Anforderung. Wenn die falsche der beiden Festplatten kaputt geht (also die ohne /boot-Partition), dann verliere ich zwar dank RAID für das restliche System keine Daten, booten kann ich aber auch nicht mehr.
Mangels besserer Alternativen dritter Anlauf:
auf der ersten Festplatte zwei Partitionen einrichten:
1 GByte mit ext4 für /boot
der Rest für RAID
auf der zweiten Festplatte eine Partition für RAID
/boot-Dateisystem direkt auf der ersten Festplatte einrichten
die großen Partitionen beider Festplatten mit RAID-1 verbinden
den RAID-Verbund für LVM nutzen
im LVM Logical Volumes für Swap und /
Diese Konfiguration akzeptiert Subiquity. Während ich dem Rechner einen Hostnamen geben und meinen Account einrichten darf, beginnt Subiquity mit den Installationsarbeiten — nur um diese wenig später mit einer sehr unspezifischen Fehlermeldung an error has occurred zu beenden (siehe die Screenshots unten).
An dieser Stelle habe ich aufgegeben. (Genau genommen habe ich die dritte Konfiguration noch einmal exakt gleich durchgeführt, um eventuelle Fehler meinerseits auszuschließen — gleiches Resultat.)
Screenshots
Manuelle PartitionierungPartition einrichtenRAID-1 einrichtenLVM einrichtenLogical Volume einrichtenZusammenfassung der KonfigurationFehler kurz nach Beginn der InstallationProtokoll zum Fehler
Fazit
Wenn Sie Ubuntu in eine neue virtuelle Maschine (eine Disk, weder LVM noch RAID) installieren möchten, ist Subiquity OK. Für alle anderen Fälle — »echte« Server-Installationen also — müssen Sie den Alternate Installer verwenden. Achten Sie schon beim Download darauf! Den Alternate-Installer finden Sie hier.
Vergangene Woche sind gleich zwei neue Bücher erschienen. Ein vollkommen neuer Titel ist Docker: Bernd Öggl (der bei diesem Buch der Hauptautor ist) und ich stellen in diesem Buch die Container-Software Docker vor und zeigen anhand diverser Beispiele viele Einsatzmöglichkeiten. Zielgruppe des Buchs sind Software-Entwickler und Administratoren.
Das Buch Raspberry Pi hat bereits die fünfte Auflage erreicht. Das Konzept des Buchs ist unverändert geblieben. Die Inhalte sind aber im Hinblick auf die neuen Raspberry-Pi-Modelle 3B+ und Zero WH aktualisiert, außerdem berücksichtigt das Werk nun durchgängig die aktuelle Raspbian-Version »Stretch«. Neue Abschnitte/Kapitel gehen auf das Erweiterungs-Board Sense HAT und auf den Werbeblocker Pi-Hole ein.
Zusammen mit Xcode 10 wird in den nächsten Tagen Swift 4.2 freigegeben. Entwickler mit einem Apple-Developer-Zugang können den Goldmaster von Xcode 10 bereits jetzt herunterladen, alle anderen werden das Update in ein paar Tagen über den App Store automatisch erhalten.
Apple weicht mit dem Release vom bisher jährlichen Major-Release-Zyklus ab. Swift 5 soll es erst im Frühjahr 2019 geben. (Voraussichtlich ein bis zwei Monate später wird es dann vorauss. auch die Neuauflage meines Swift-Buchs geben.)
Swift 4.2 ist ein inkrementelles Update zu Swift 4.1. Es gibt also keine inkompatiblen Änderungen, aber diverse Erweiterung der Sprache oder der Standardbibliothek. Eine Referenz aller Neuerungen finden Sie auf der swift-evolution-Seite. Ich greife hier nur die wichtigsten Punkte heraus.
Zufallszahlen
Die für viele Programmierer(innen) sichtbarste Verbesserung in Swift 4.2 besteht darin, dass es endlich einen einfachen und konsistenten Weg gibt, um Zufallszahlen zu generieren:
let n = Int.random(in: 0..<10) // zwischen 0 (inkl.) und 9 (inkl.)
let f = Float.random(in: 0..<1) // zwischen 0.0 (inkl.) und 1.0 (exkl.)
let d = Double.random(in: -1..<1) // zwischen -1.0 (inkl.) und 1.0 (exkl.)
let b = Bool.random() // true/false
var lst = [17, 33, 51, 67]
lst.shuffle() // verändert lst
let lst2 = lst.shuffled() // erzeugt neue Liste, lst bleibt unverändert
let itm = lst.randomElement() // wählt ein zufälliges Element aus
let s = "Hello, World!"
let ar3 = s.shuffled() // z.B. ["l", "o", "l", ...]
let c = s.randomElement() // z.B. "o"
let char = "abcde".randomElement()
toggle() für Bool
Der Datentyp Bool kennt nun die Methode toggle. Sie macht aus true -> false bzw. als false -> true:
var b = true
b.toggle()
b // false
Bearbeitung von Collections (allSatisfy und removeAll)
Swift kennt neue Methoden zur Bearbeitung von Collections. Mit allSatisfy können Sie überprüfen, ob alle Elemente der Collection eine Bedingung erfüllen:
let lst = [2, 44, 120]
if(lst.allSatisfy {$0 % 2 == 0}) {
print("Alle Zahlen sind gerade.")
}
removeAll entfernt alle Elemente, die eine Bedingung erfüllen. Die Methode verändert die Aufzählung in-place und ist besonders effizient implementiert (siehe SE-0197):
var data = [1, 2, 3, 4, 7, 12, 25, 30]
data.removeAll() {$0 % 2 == 0} // alle geraden Zahlen entfernen
data // [1, 3, 7, 25]
Enumerationen mit CaseIterable
Wenn Sie Enumerationen mit dem Protokoll CaseIterable ausstatten, steht die Eigenschaft allCases zur Verfügung. Sie enthält ei
enum Colors: CaseIterable {
case red, blue, green, black, white
}
for c in Colors.allCases {
print(c)
}
Dynamische Eigenschaften (@dynamicMemberLookup)
Das neue Attribut @dynamicMemberLookup gibt Ihnen die Möglichkeit, Typen zu definieren, auf deren Daten Sie in der Form obj.name [= ...] zugreifen können, obwohl die Eigenschaft name gar nicht statisch definiert ist. Stattdessen wird bei unbekannten Eigenschaftsnamen eine subscript-Methode aufgerufen. Um deren Implementierung müssen Sie sich selbst kümmern. Die folgenden Zeilen geben ein einfaches Beispiel:
@dynamicMemberLookup
struct Person {
private var dynamicdata = [String: String]()
subscript(dynamicMember member: String) -> String {
get {
return dynamicdata[member] ?? ""
}
set {
dynamicdata[member] = newValue
}
}
}
var p = Person()
p.name = "Michael Kofler"
p.city = "Graz"
p.tel = "+43 123 4567 8901"
p.city // "Graz"
p.mail // ""
Die Struktur Person hat also gar keine Eigenschaften. Sie können aber beliebige Daten in der Form obj.name = "xxx" speichern und später in der Form obj.name wieder auslesen. Wenn name unbekannt ist, liefert die subscript-Methode in der obigen Implementierung einfach eine leere Zeichenkette. (Sie könnten hier auch einen Fehler auslösen oder auf eine andere Art und Weise reagieren.)
Die hier präsentierte Implementierung hat den Nachteil, dass ausschließlich Zeichenketten gespeichert und wieder ausgelesen werden können. Diese Einschränkung lässt sich umgehen, indem Sie subscript-Methoden für mehrere Datentypen implementieren. Das macht allerdings später den Zugriff umständlicher, weil der Datentyp für den Compiler immer eindeutig erkennbar sein muss:
struct Person {
private var dynamicStringData = [String: String]()
private var dynamicIntData = [String: Int]()
// dynamische Zeichenketten-Eigenschaften
subscript(dynamicMember member: String) -> String {
get {
return dynamicStringData[member] ?? ""
}
set {
dynamicStringData[member] = newValue
}
}
// dynamische Int-Eigenschaften
subscript(dynamicMember member: String) -> Int {
get {
return dynamicIntData[member] ?? 0
}
set {
dynamicIntData[member] = newValue
}
}
}
// Anwendung
var p = Person()
p.name = "Michael Kofler"
p.id = 123
// OK, weil n explizit als Int deklariert wurde
let n: Int = p.id
print(n)
// Fehler, Ambiguous use of 'subscript(dynamicMember:)',
// weil der Datentyp unklar (String oder Int?)
print(p.id)
Weitere Hintergrundinformationen und Anwendungsbeispiele finden Sie in der Dokumentation zu SE-0195. Weitere Beispiele gibt Hacking with Swift und Ray Wenderlich.
Eigene Hash-Funktion einfacher gemacht
Seit Swift 4.1 reicht es oft aus, eigene Strukturen oder Enumerationen mit dem Protokoll Hashable auszustatten (siehe auch Swift 4.1). Swift kümmert sich dann selbst um die Implementierung der Hash-Funktion, sofern der Typ selbst aus lauter Elementen zusammengesetzt ist, die selbst Hashable sind. Das trifft u.a. für alle Standarddatentypen zu (Int, String etc.). Allerdings ist dieser Automatismus mit einigen Einschränkungen verbunden und funktioniert insbesondere für Klassen nicht.
Für den Fall, dass Sie die Hash-Funktion selbst programmieren müssen (class) oder wollen, unterstützt Sie Swift 4.2 dabei nun besser als zuvor (siehe auch SE-0206): Zur Erfüllung des Protokolls Hashable müssen Sie nunmehr die Methode hash implementieren (nicht mehr var hashvalue). An dieses Methode wird eine Instanz einer Hasher-Struktur übergeben. Eigene Daten, die in die Hash-Funktion einfließen sollen, übergeben Sie einfach mit hasher.combine(daten).
class Person : Hashable, Equatable {
var name: String
var tel: String
var mail: String
init(name: String, tel: String, mail: String) {
self.name = name
self.tel = tel
self.mail = mail
}
// für Equatable
static func == (lhs: Person, rhs: Person) -> Bool {
return lhs.name == rhs.name &&
lhs.mail == rhs.mail &&
lhs.tel == rhs.tel
}
// für Hashable
func hash(into hasher: inout Hasher) {
hasher.combine(name)
hasher.combine(tel)
hasher.combine(mail)
}
}
Aus Kompatibilitätsgründen reicht es für das Hashable-Protokoll aktuell aus, entweder wie bisher var hashvalue oder (neu in Swift 4.2) func hash zu implementieren. Allerdings gilt hashvalue ab Swift 4.2 als deprecated und wird längerfristig eliminiert werden (siehe auch den Abschnitt Source compatibility in SE-0206).
Kompatibilität, Xcode
Bei schnellen Tests mit den mehr als 100 Beispielprogramme aus dem Swift-Buch bin ich beim Update von 4.1 auf 4.2 auf keine nennenswerten Probleme gestoßen.
Xcode meckert jetzt auch bei Steuerelementen ohne Layout-Constraint: Auto Layout Localization: Views without any layout constraints may clip their content or overlap other views. Bisher wurden Steuerelemente ganz ohne Constraints still akzeptiert, was gerade in Testprogrammen praktisch war. Dass Xcode hier nun noch pingeliger ist, führt zu einer Menge zusätzlicher Warnungen, die aber natürlich nichts mit Swift zu tun haben.
Playgrounds sind leider instabil und zickig wie eh und je. Bei meinen Tests habe ich deswegen etliche Komplettabstürze von Xcode erlebt. Neuerdings wirft Xcode im Playground ständig mit unknow context-Warnungen um sich. Mitunter behauptet Xcode, dass Code im Playground syntaktisch falsch sei, obwohl derselbe Code in einem ‚richtigen‘ Xcode-Projekt wunderbar funktioniert. Schade, dass Apple die Playgrounds nicht so hinbekommt, dass man gerne damit arbeitet!
Endlich für Ubuntu 18.04, in Zukunft wohl auch »offizielles« Docker-Image
(Update 20.9.2018) Eine nicht unwesentliche Kleinigkeit habe ich übersehen: Swift 4.2 steht nun (endlich) auch für das aktuelle Ubuntu 18.04 zum Download zur Verfügung. Längerfristig soll Swift aber auch »offiziell« für Docker angeboten werden (siehe den entsprechenden Forum-Thread). Das ist schon länger mein bevorzugter Weg, wenn ich Swift außerhalb der macOS-Welt brauche.
Mit Java 11 liefert Oracle endlich, was sich viele Entwickler vor einem Jahr erwartet hatten: eine stabile Java-Version mit Langzeitwartung (LTS = Long Time Support). Unter diesem Gesichtspunkt kann man Java 9 und Java 10 eigentlich nur als öffentliche Betas betrachten, bereits nicht mehr gewartet und aus heutiger Sicht obsolet.
An sich wäre das alles in Ordnung, wenn Oracle diesen Release-Prozess ehrlich und früh genug kommuniziert hätte …
Aktuelle IntelliJ-Versionen sind bereits kompatibel zu Java 11
Long Term Support
In der Support Roadmap verspricht Oracle, Java 11 regulär bis September 2023 mit Updates zu versorgen. Der »Extended Support« reicht sogar noch drei Jahre länger. Was den Support betrifft, ist Java 11 somit der logische Nachfolger von Java 8.
Die kommenden fünf Java-Versionen 12 bis 16, die im Halbjahresrhythmus erscheinen werden, genießen wie Java 9 und 10 keinen Long Term Support. Sie sind also nur für Entwickler gedacht, die gerne die neuesten Features ausprobieren. Die nächste LTS-Version wird voraussichtlich erst wieder Java 17 sein (geplant für Herbst 2021, siehe auch dieses Diagramm eines Ubuntu-Entwicklers).
Neue Funktionen
Java 11 bietet eine Menge neuer Funktionen, die sich primär an fortgeschrittene Entwickler bzw. an das Enterprise-Lager richten. Zu den wichtigsten Neuerungen zählen:
Zusätzliche kryptografische Funktionen (ChaCha20 and Poly1305, JEP 329)
Einfachere Java-Ausführung für Einsteiger
Die interessanteste Neuerung für Java-Einsteiger ist ein neues Konzept zur Ausführung von Java-Programmen, die aus nur einer einzigen Datei bestehen (* Launch Single-File Source-Code Programs*, JEP 330). Derartige Programme können nun einfach mit java Quellcode.java gestartet werden. (Bisher musste der Code bekanntlich zuerst mit javac kompiliert werden. Im zweiten Schritt musste an java der Klassenname ohne die Endung .java oder .class übergeben werden — ein Punkt, der bei Einsteigern oft für Verwirrung sorgt.)
Wenn Sie also die folgende Datei in einem Verzeichnis gespeichert haben …
// Datei HelloWorld.java
public class HelloWorld11 {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
… dann können Sie den Code nun wie folgt ausführen:
java HelloWorld.java
Das ist eigentlich eine feine Sache! Das Kompilat wird dabei nicht dauerhaft gespeichert (es entsteht also keine neue Datei HelloWorld.class), sondern nur im RAM zwischengespeichert.
ACHTUNG Die Code-Ausführung funktioniert nur, wenn Sie das Programm nicht vorher schon kompiliert haben! Wenn es im aktuellen Verzeichnis bereits die Datei HelloWorld.class gibt, dann kommt es zur verwirrenden Fehlermeldung class found on application class path: HelloWorld. Mit anderen Worten: java weiß nicht, ob es nun HelloWorld.java kompilieren und ausführen soll, oder ob Sie eigentlich die bereits kompilierte Klasse HelloWorld.class ausführen möchten.
Zu diesem Konzept gibt es einige Varianten. Die Ausführung gelingt auch, eenn die Code-Datei nicht die Endung .java hat. In diesem Fall erfolgt der Aufruf mit der Option java --source n, wobei n die Java-Versionsnummer ist:
java --source 11 HelloWorld.txt
Linux- und macOS-Fans können den Java-Code sogar als Script verpacken. Die erste Zeile des Scripts muss in diesem Fall mit #!/pfad/zu/java --source 11 beginnen, also z.B.:
#!/usr/bin/java --source 11
// Datei HelloWorld.script
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
Nach chmod +x HelloWorld.script können Sie die Datei nun mit ./HelloWorld.script ausführen. Abermals scheitert die Ausführung, wenn es im gleichen Verzeichnis bereits die Datei HelloWorld.class gibt. Anstelle von #!/usr/bin/java ist auch die portablere Varianten #!/usr/bin/env java erlaubt.
Einige weitere Varianten mit mehreren Klassen in einer Datei sowie mit der Verwendung von import sind in diesem Blog-Beitrag dokumentiert.
Neue Zeichenkettenfunktionen
In Java 11 stehen auch sechs neue Methoden zur Bearbeitung von Zeichenketten zur Verfügung:
s.repeat(n) dupliziert s n-mal
s.lines() liefert einen Stream mit den Zeilen der Zeichenkette
s.isBlank() liefert true, wenn die Zeichenkette leer ist oder nur aus Whitespace besteht
s.stripLeading(), s.stripTrailing() und s.strip() liefert eine neue Zeichenkette, in der der Whitespace am Beginn und/oder Ende eliminiert ist
Der Unterschied zwischen trim und strip besteht darin, dass strip komplett Unicode-kompatibel ist. Die folgenden Zeilen zeigen die Anwendung der neuen Funktionen in der jshell.
jshell> var s=" abc "
s ==> " abc "
jshell> s.strip()
$2 ==> "abc"
jshell> "abc".repeat(3)
$8 ==> "abcabcabc"
jshell> s="Hello\nWorld!"
s ==> "Hello\nWorld!"
jshell> var lines = s.lines()
lines ==> java.util.stream.ReferencePipeline$Head@5f2108b5
jshell> lines.forEach(System.out::println)
Hello
World!
JavaFX
Mit Java 11 wurde JavaFX ausgegliedert. Das führt zur absurden Situation, dass die technologisch komplett veraltete Swing-Technologie weiter offiziell unterstützt wird, JavaFX aber nicht. Vielleicht sollte man es so formulieren: Nicht einmal Oracle glaubt daran, dass Java die richtige Sprache zur GUI-Entwicklung ist.
Persönlich finde ich das schade, weniger weil ich riesige JavaFX-Projekte entwickle, sondern mehr, weil JavaFX einen einfachen und eleganten Weg zur Realisierung einfacher Grafikprogramme bot.
JavaFX ist aber (noch) nicht (vollständig) tot. Vielmehr kümmert sich die Community nun um JavaFX, wobei die Firma Gluon dieKoordination übernommen hat. Zumindest für Version 11 hat das wunderbar funktioniert. JavaFX 11 wurde sogar eine Woche vor Java 11 freigegeben.
JavaFX steht auf der neuen Community-Website https://openjfx.io zum Download zur Verfügung. Für kommerzielle Kunden bietet Gluon Support-Verträge an.
Um also weiterhin JavaFX-Programme entwickeln zu können, müssen Sie das JavaFX SDK von hier herunterladen. Nach dem Auspacken der ZIP-Datei müssen Sie den Verzeichnisbaum an einen Ort verschieben, wo er für alle JavaFX-Benutzer zugänglich ist. Wenn JavaFX nur von einem einzelnen Benutzer verwendet wird, können Sie es auch im Home- oder Download-Verzeichnis belassen.
Um ein simples Hello-World-Programm zu kompilieren und auszuführen, sind die folgenden Anweisungen erforderlich (hier für macOS):
Um JavaFX in einem IntelliJ-Projekt ohne Maven, Gradle oder andere externe Tools zu verwenden, müssen Sie zwei Dinge tun:
Im Dialog File/Project Structure, Dialogblatt Modules wählen Sie mit dem Plus-Button JARs or directories aus und geben dann den Pfad zu Ihren lokalen JavaFX-Dateien an, also z.B. /Users/kofler/Downloads/javafx-sdk-11/lib/. Damit sollte IntelliJ im Quellcode alle javafx-Importe verstehen und in der Lage sein, das Programm zu kompilieren.
Im Dialog Run/Edit Configuration fügen Sie bei den VM options die folgenden zwei Optionen hinzu. (Dabei müssen Sie natürlich den Pfad durch den Ort auf Ihrem Rechner ersetzen.)
JavaFX-Bibliothek in IntelliJ hinzufügenErforderliche Optionen, damit IntelliJ ein JavaFX-Programm ausführen kann
Java 11 unter Linux
Ubuntu hat versprochen, die Java-Pakete in Ubuntu 18.04 automatisch auf Version 11 zu aktualisieren. Bisher ist das noch nicht der Fall. Ähnlich sieht es in der Beta für Ubuntu 18.10 aus. Die Paketnamen lauten zwar bereits openjdk-11-xxx, aber javac -version liefert 10.0.2.
Die Beta von Fedora 29 enthält immerhin schon eine Early-Access-Version von Java 11.
Wie gut JavaFX im Zusammenspiel mit Java 11 unter Linux funktioniert, werde ich mir ansehen, wenn es finale Versionen von Ubuntu 18.10 und Fedora 29 gibt.
Ubuntu 18.10 ist das erste von drei Zwischen-Releases auf dem Weg hin zur nächsten LTS-Version, also zu Ubuntu 20.04. Insofern spricht Ubuntu 18.10 nur Benutzer an, die bereit sind, in einem halben Jahr das nächste Update bzw. die nächste Neuinstallation durchzuführen — sprich Linux-Fans/Freaks.
Der Lohn für die ständigen Updates: Man ist ganz vorne dabei, wenn es darum geht, neue Features auszuprobieren. Der Benchmark-Experte Michael Larabel (phoronix.com) erwartet von Ubuntu 18.10 zudem deutlich mehr Performance, besonders im 3D-Grafik/Gaming-Bereich. Auch ein neues Notebook zwingt mitunter zum Einsatz einer Nicht-LTS-Version: Aktuelle Treiber versprechen eine höhere Kompatibilität zu modernen Hardware-Komponenten.
Der aufgefrischte Ubuntu-Desktop geizt nicht mit Farben
Neue Farben, ein neues Desktop-Theme und frischere Icons prägen den Desktop. Der Ubuntu-Desktop bleibt wiedererkennbar und wirkt dennoch wesentlich frischer. Ob aber Grün die ideale Kontrastfarbe zu Violett/Aubergine ist, darüber kann man geteilter Meinung sein … Insgesamt ist Canonical mit Ubuntu 18.10 auf jeden Fall ein Release gelungen, das auch ohne Langzeit-Support überraschend attraktiv ist.
Nautilus bleibt allerdings bei Version 3.26, Ubuntu will auf Desktop-Icons nicht verzichten. Konservativ bleibt Canonical auch beim Grafiksystem, Xorg gilt weiter als Default. (Wayland ist aber nur einen Mausklick beim Login entfernt.)
Wenig geändert hat sich an der Liste der vorinstallierten Snap-Pakete. Es ist wohl eher eine politische Entscheidung, dass Canonical die Snap-Pakete den deutlich kleineren ’normalen‘ Paketen vorzieht.
Zu meinen ersten »eigenen« E-Book-Veröffentlichungen zählte das Buch Markdown und Pandoc. 2017 habe ich den Verkauf eingestellt, weil mehrere Kapitel des E-Books total veraltet waren. Jetzt habe ich endlich Zeit gefunden, das E-Book gründlich zu aktualisieren.
Die 200-seitige Neuauflage ist vollständig aktualisiert und nun aktuell zu Pandoc 2.3. Neu hinzugekommen ist das Kapitel »Arbeitstechniken«. Es verrät, wie das E-Book selbst erzeugt wurde und gibt Tipps zum Einsatz des Editors Atom im Zusammenspiel mit Markdown und Pandoc. Ein weiterer Abschnitt beschreibt, wie Sie Docker dazu verwenden können, eine komplette Pandoc- und LaTeX-Umgebung reproduzierbar aufzusetzen.
Neu ist auch der Abschnitt »Kollaboratives Arbeiten mit GitLab«, in dem Axel Dürkop und Tina Ladwig von der TU Hamburg zeigen, wie Pandoc zum gemeinschaftlichen Verfassen von (wissenschaftlichen) Texten verwendet werden kann.
Selten ist mir ein Buch derart gut von der Hand gegangen wie der soeben erschienene Python Grundkurs:
Die Idee für das Buch hatte ich eigentlich schon vor drei Jahren. Dass das Buch gerade jetzt zustande kam, haben Sie — zugegebenermaßen etwas überraschend — Apple zu verdanken: Eigentlich wollte ich über den Sommer an der Neuauflage meines Swift-Buchs arbeiten. Aber dann hat Apple verkündet, dass Swift 5 erst 2019 fertig würde. Die so entstandene Lücke in meinem Kalender habe ich mit vielen Radtouren gefüllt. Außerdem habe ich auf 460 kompakten Seiten die Grundelemente der Programmiersprache Python zusammengefasst.
Ein Loblied auf Python
Python ist eine ungemein elegante Programmiersprache. Mit Python verfasster Code ist in der Regel kompakter und leichter zu lesen als bei vielen anderen Sprachen. Weil zudem der Overhead einer kompilierten Sprache entfällt, kommt Python Einsteigern besonders entgegen. (Persönlich bin ich der Meinung, das Python als First Programming Language viel besser geeignet wäre als Java oder C#. Diese beide Sprachen dominieren zumindest im deutschen Sprachraum den Unterricht in den ersten Semestern.)
Die Einfachheit von Python schränkt aber keinesfalls seine Anwendung ein:
Dass Python universell für alle erdenklichen Aufgaben geeignet ist, liegt an seinem Modulkonzept: Im Internet finden Sie Tausende kostenlose Erweiterungen. Die Installation solcher Module und ihre Integration in eigenen Code sind ausgesprochen einfach.
Python ist auch im (natur)wissenschaftlichen Sektor sehr beliebt — aktuell ganz besonders im Bereich der künstlichen Intelligenz. Mit keiner anderen Sprache kommen Sie mit derart wenig Code ans Ziel. Python ist ideal zum Experimentieren geeignet, wenn konkrete Ergebnisse und nicht der perfekte Code im Vordergrund stehen.
Zur Popularität von Python hat natürlich auch der Raspberry Pi beigetragen. Trotz vieler Alternativen ist Python die bevorzugte Programmiersprache der Maker-Gemeinde.
Lassen Sie sich von meiner Begeisterung für Python anstecken! Wenn Sie Python kennenlernen möchten, bietet mein Grundkurs mit vielen Übungsaufgaben (natürlich samt Lösungen) einen idealen Startpunkt.
Fedora 29 bietet im Vergleich zur Vorgängerversion die üblichen Software-Updates, aber nur wenige tiefgreifende Neuerungen:
Der Bootprozess sollte nun auf manchen Rechnern vollkommen ohne Bildschirmflackern verlaufen. Das setzt aktuell allerdings voraus, dass UEFI sowie ein Intel-Grafiksystem genutzt wird, siehe auch Announcing flickerfree boot for Fedora 29.
Das in Version 28 für Fedora Server eingeführte Modularity-Prinzip steht nun standardmäßig auch in der Desktop-Variante zur Verfügung. (Wie ich in meinem Blog-Beitrag zu Fedora 28 berichtet habe, konnten modularisierte Pakete mit dnf install fedora-repos-modular auch schon in der Desktop-Version 28 genutzt werden. Dass dieses Paket nun standardmäßig installiert ist, ändert nichts daran, dass das Angebot an modularisierten Paketen weiterhin sehr klein ist. Der praktische Nutzen dieses Konzepts ist für Fedora ohnedies gering, weil die Distribution eine kurze Lebensdauer hat. Wirklich spannend werden modularisierte Pakete wohl erst in RHEL 8 bzw. CentOS 8.)
Die Überschrift sagt schon alles: In diesem Beitrag geht es darum, Programme mit Java 11 und JavaFX in der IntelliJ IDEA unter Linux zu entwickeln. Als Testumgebung dienten Ubuntu 18.10 und Fedora 29. (Unter Ubuntu 18.04 stehen noch immer keine offiziellen Java-11-Pakete zur Verfügung.)
Die IntelliJ IDEA mit einem Java-11-Projekt samt JavaFX unter Ubuntu 18.10
Wie ich in meinem Blog-Beitrag zu Java 11 schon erläutert habe, ist JavaFX nicht mehr in Java 11 enthalten. Das erforderliche JavaFX-SDK steht zwar weiterhin kostenlos zur Verfügung, die Entwicklung und Weitergabe von JavaFX-Programmen ist aber nun viel umständlicher als bisher.
Java 11 installieren
Fedora 29 und Ubuntu 18.10 enthalten bereits Java-11-Pakete. Die Installation ist daher ein Kinderspiel:
JavaFX kann hier kostenlos heruntergeladen werden. (JavaFX wird nun von der Community gepflegt. Die Downloads stellt die Firma Gluon zur Verfügung.) Sie können die Dateien nun in ein beliebiges Verzeichnis installieren. Ich habe die Installation auf meinen Testgeräten direkt
im Heimatverzeichnis durchgeführt, also:
Die JavaFX-Dateien landen dann im Unterverzeichnis javafx-sdk-11.0.1.
IntelliJ IDEA installieren
Die Java-Entwicklungsumgebung IntelliJ IDEA kann hier heruntergeladen werden. Zur Installation packen Sie das TAR-Archiv aus:
cd
tar xzf Downloads/idea-nnn.tar.gz
Der erste Start erfolgt manuell im Terminal:
./idea-nnn/bin/idea.sh
Wenn Sie im Setup-Assistenten die Default-Optionen belassen, wird für die Entwicklungsumgebung ein Starter eingerichtet, so dass das Programm in Zukunft in den Gnome-Aktivitäten auftaucht. Erfreulicherweise findet die IntelliJ IDEA das Java-11-SDK selbstständig.
JavaFX-Projekte einrichten
Damit IntelliJ die JavaFX-Bibliotheken findet und richtig nutzt, müssen zwei Projekteinstellungen verändert werden:
Im Dialog File/Project Structure, Dialogblatt Modules/Dependencies wählen Sie mit dem Plus-Button JARs or directories aus und geben dann den Pfad zu Ihren lokalen JavaFX-Dateien an, also z.B. /Users/kofler/javafx-sdk-11.0.1/lib/. Damit sollte IntelliJ im Quellcode alle javafx-Importe verstehen und in der Lage sein, das Programm zu kompilieren.
Im Dialog Run/Edit Configuration fügen Sie bei den VM options die folgenden zwei Optionen hinzu. (Dabei müssen Sie natürlich den Pfad durch den Ort auf Ihrem Rechner ersetzen.)
528 Seiten, Hard-Cover (4. Auflage)
Preis: Euro 19,90 (in D inkl. MWSt.)
Dieses Buch enthält den Linux-Grundwortschatz für das Arbeiten im Terminal – über 500 Kommandos samt Optionen, Erläuterungen und Beispielen. Außerdem umfasst das Buch eine Referenz der wichtigsten Konfigurationsdateien sowie eine Zusammenstellung wichtiger Tastenkürzel.
Für die Neuauflage wurde das Buch vollständig aktualisiert. Außerdem wurden einige weitere Kommandos und Konfigurationsdateien hinzugefügt, unter anderem:
Nach einem SSH-Login auf einem Ubuntu-Server werden Sie aktuell mit ca. 40 Zeilen Text beglückt, die eine Mischung aus sinnvollen Informationen sowie Werbung für Zusatzdienste von Canonical sind. Das Ganze sieht so ähnlich aus wie das folgende Muster:
ssh ein-u1804-server
Welcome to Ubuntu 18.04.1 LTS (GNU/Linux 4.15.0-15-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Thu Dec 13 16:46:12 CET 2018
System load: 0.0 Processes: 135
Usage of /: 33.0% of 18.61GB Users logged in: 1
Memory usage: 37% IP address for ens3: 1.2.3.4
Swap usage: 6%
=> There is 1 zombie process.
* MicroK8s is Kubernetes in a snap. Made by devs for devs.
One quick install on a workstation, VM, or appliance.
- https://bit.ly/microk8s
* Full K8s GPU support is now available! Get it in MicroK8s, CDK,
and on GKE with Ubuntu workers.
- https://blog.ubuntu.com/2018/12/10/using-gpgpus-with-kubernetes
* Canonical Livepatch is available for installation.
- Reduce system reboots and improve kernel security. Activate at:
https://ubuntu.com/livepatch
149 packages can be updated.
0 updates are security updates.
*** System restart required ***
You have mail.
Last login: Nov 19 15:50:28 2018 from 5.6.7.8
Weniger ist mehr
Der beim Login angezeigte Text wird unter Ubuntu durch mehrere Scripts generiert, die sich im Verzeichnis /etc/update-motd.d befinden. Für die eigentliche Anzeige ist das PAM-Modul pam_motd zuständig. (Details und Hintergrundinformationen gibt man update-motd. Die Abkürzung motd steht für Message of the Day.)
Die radikalste Lösung zur Minimierung der Login-Nachrichtenflut besteht darin, einfach bei allen Scripts in /etc/update-motd.d das Execute-Bit zu entfernen:
sudo chmod -x /etc/update-motd.d/*
Statt mit dem Holzhammer können Sie aber auch differenzierter vorgehen und nur die Scripts deaktivieren, die am lästigsten sind:
cd /etc/update-motd.d
sudo chmod -x 10-help-text 50-landscape-sysinfo 50-motd-news
Ein neuerlicher Login zeigt eine stark reduzierte Willkommensbotschaft:
ssh ein-u1804-server
Welcome to Ubuntu 18.04.1 LTS (GNU/Linux 4.15.0-15-generic x86_64)
* Canonical Livepatch is available for installation.
- Reduce system reboots and improve kernel security. Activate at:
https://ubuntu.com/livepatch
149 packages can be updated.
0 updates are security updates.
*** System restart required ***
You have mail.
Last login: Thu Dec 13 16:46:13 2018 from 5.6.7.8
Die SQL-Syntax unterscheidet syntaktisch bei Vergleichen mit realen Werten und NULL:
SELECT * FROM tabelle WHERE spalte=0
SELECT * FROM tabelle WHERE spalte IS NULL
Wenn Sie in einem Python-Script mit PyMySQL auf eine MySQL- oder MariaDB-Datenbank zugreifen und dabei Datensätzen selektieren möchten, deren Inhalt je nach Parameter auch NULL sein darf, führt das zu Problemen:
import pymysql.cursors
conn = pymysql.connect(...)
with conn.cursor() as cur:
sql = 'SELECT * FROM tabelle WHERE spalte = %s'
cur.execute(sql, (0)) # OK
cur.execute(sql, (None)) # liefert einen SQL-Syntaxfehler
...
Lösung
Die naheliegende Lösung besteht darin, das SQL-Statement eben in Abhängigkeit vom betreffenden Parameter zu variieren, also:
if value == None:
sql = 'SELECT * FROM tabelle WHERE spalte IS %s'
else:
sql = 'SELECT * FROM tabelle WHERE spalte = %s'
In einem Projekt musste ich zuletzt aber eine Menge derartiger SELECT-Abfragen zusammenstellen, bei denen es jeweils viele Parameter gab, die alle NULL sein konnten. Der obige Ansatz wird dann unübersichtlich. Ich habe mir deswegen eine kleine Funktion programmiert, an die ich ein Dictionary mit Spaltennamen und Werten übergeben kann. Die Funktion erzeugt daraus eine Zeichenkette mit dem WHERE-Teil des SQL-Statements.
dict = { 'spalte1': 123, 'spalte2': 'abc', 'spalte3': None }
sql = 'SELECT FROM tabelle ' + buildWhere(conn, dict)
# erzeugt eine Zeichenkette der Form
# WHERE col1 = 'val1' AND col2 = 'val2' etc.
# mit col1 IS NULL für Werte, die None sind
def buildWhere(conn, dict):
result = "WHERE "
for colname, value in dict.items():
if value == None:
result += colname + ' IS NULL AND '
else:
result += colname + ' = ' + conn.escape(value) + ' AND '
return result[:-4] # letztes 'AND ' eliminieren
Die Methode escape stellt sicher, dass das auch dann funktioniert, wenn die Werte im Dictionary Anführungszeichen oder andere problematische Zeichen enthalten.
Über den exorbitaten Speicherbedarf von Ubuntus Paketverwaltungsprogramm Snap habe ich ja schon öfters gelästert. Aber erst jetzt ist mir eine weitere unangenehme Eigenheit aufgefallen: Snap speichert standardmäßig von jedem installierten Paket zwei Backups älterer Versionen. Nach Updates bleiben also ältere Versionen erhalten. Das verdreifacht den von Snap beanspruchten Speicherplatz!
Um nicht mehr benötigte Pakete zu löschen, führen Sie im Terminal als Administrator (vorher sudo -s) die folgende Schleife aus:
snap list --all | awk '/disabled/{print $1, $3}' |
while read snapname revision; do
snap remove "$snapname" --revision="$revision"
done
Versionsanzahl einstellen
Beginnend mit Snap 2.34 kann die Anzahl der sinnlosen Snap-Backups eingestellt werden. Allerdings lautet der kleinste zulässige Wert 2, was offensichtlich bereits die Defaulteinstellung ist.
sudo snap set system refresh.retain=2
Bleibt auf Systemen mit wenig Speicherplatz also nur ein cron-Script, das einmal wöchentlich wie oben beschrieben alle ‚disabled‘-Pakete rauswirft. Schöne neue Welt …
In den nächsten Wochen/Monaten wird Swift 5 fertig werden. Dieser Beitrag fasst die wichtigsten Neuerungen zusammen. Swift 5 gilt insofern als »Meilenstein«, als Apple erstmalig die binäre Kompatibilität der Schnittstellen garantiert. Die größte Auswirkung in der Praxis besteht darin, dass Standardbibliotheken nun auf Apple-Geräten installiert werden und nicht mehr mit jeder App mitgeliefert werden müssen. Xcode erzeugt daher kleinere Binärdateien.
Dieser Artikel wird bis zur Freigabe von Swift 5 bei Bedarf aktualisiert.
ABI-Stabilität
Das Application Binary Interface (ABI) beschreibt die Schnittstelle zwischen Programmen bzw. Bibliotheken auf binärer Ebene, also zur Laufzeit. Im Unterschied dazu betrifft das Application Programming Interface (API) »nur« den Quellcode.
Das vermutlich wichtigste Ziel bei der Entwicklung von Swift 5 war die Erreichung der ABI-Stabilität. Ein mit Swift 5 kompiliertes Programm kann sich also darauf verlassen, dass die Zusammenarbeit mit einer für Swift 5 kompilierten Bibliothek funktioniert — auch dann, wenn die App mit Swift 5.0 kompiliert ist, die (z.B. unter iOS installierte) Bibliothek aber bereits mit Swift 5.1.
Das Erreichen der ABI-Stabilität hat insofern große praktische Auswirkungen, als Swift-Bibliotheken nun direkt als Teil von iOS, macOS usw. ausgeliefert werden. In Swift entwickelte Apps können sich darauf verlassen, dass die Bibliotheken zur Verfügung stehen. Es ist nicht mehr möglich, mit jeder App diverse Bibliotheken mitzuliefern, so dass die Apps selbst kleiner werden. Besonders stark bemerkbar macht sich das bei kleinen Apps. Einige Beispiele dafür, wie groß die Platzersparnis voraussichtlich sein wird, hat 9to5mac gesammelt.
Mitunter soll eine Zeichenkette as is angegeben werden. Ein Backslash soll ein Backslash bleiben und keine Zusatzfunktionen entfalten. Auch Anführungszeichen sollen erhalten bleiben. Diese Möglichkeit bietet Swift nun mit Raw-Strings. Die Syntax ist häßlich, aber sie funktioniert:
let sql = #"SELECT * FROM table WHERE column="ab""#
let winfn = #"C:\verzeichnis\name.txt"#
Zeichenketten werden also zusätzlich von einem #-Zeichen umschlossen. Das hat folgende Auswirkung:
Innerhalb der Zeichenkette sind Anführungszeichen erlaubt. (Erst "# beendet die Zeichenkette.)
Sequenzen wie \n oder \u{1234} haben nicht die übliche Wirkung, sondern werden as is übernommen.
String-Interpolation wie \(ausdruck) funktioniert nicht mehr.
Die neue Syntax ist auch für mehrzeilige Zeichenketten erlaubt:
let sql = #"""
SELECT *
FROM table
WHERE column="abc"
"""#
So weit, so gut. Es gibt nun aber noch diverse Sonderfälle. Wenn in einem Raw-String doch String-Interpolation verwendet werden soll, lautet die Syntax hierfür \#(ausdruck), also:
let id = 17
let sql = #"SELECT * FROM t WHERE col="abc" AND id=\#(id)"#
print(sql)
// Ausgabe: SELECT * FROM t WHERE col="abc" AND id=17
Für den Fall, dass in der Zeichenkette "# vorkommt, kann die Anzahl der #-Zeichen vor und nach der Zeichenkette vergrößert werden.
let special = ##"abc"#efg"##
print(special) // Ausgabe: abc"#efg
Auch dieser Fall kann mit String-Interpolation verbunden werden, dann eben mit \##(ausdruck). Noch mehr Spitzfindigkeiten und Sonderfälle sind hier dokumentiert:
Die Swift-Standardbibliothek definiert den neuen Datentyp Result:
public enum Result<Success, Failure: Error> {
case success(Success), failure(Failure)
}
Result ist vor allem für asynchrone Algorithmen gedacht, die wahlweise ein Ergebnis liefern oder einen Fehler auslösen. Der Einführung von Result sind schier endlose Diskussionen im Swift-Forum vorangegangen (siehe initial review, second review und acceptance). Erst der zweite Entwurf wurde nach weiteren Modifikationen akzeptiert. In der Diskussion wurde u.a. der Einwand eingebracht, dass Result eine halbherzige Lösung im Hinblick auf die für Swift 6 geplanten asynchronen Spracherweiterungen sind. Man hat sich aber darauf geeinigt, dass Result bis dahin auf jeden Fall besser als gar keine Lösung ist.
Details zur Implementierung sowie Anwendungsbeispiele finden Sie hier:
Wenn Sie in Swift 4 mit try? einen Ausdruck verarbeiten, der selbst ein Optional zurückgibt, erhalten Sie als Ergebnis ein doppeltes (verschachteltes) Optional. Das macht die weitere Verarbeitung recht mühsam.
In Swift 5 werden hingegen alle Optional-Ebenen verflacht. Das Resultat ist ein einfaches Optional. Es hat entweder einen sinnvollen Wert oder nil.
enum MyErrors : Error {
case tooBig
}
func f(_ n: Int) throws -> Int? {
if n < 0 { return nil}
if n > 100 { throw MyErrors.tooBig }
return n + 1
}
let result = try? f(1000)
// Swift 4: result hat den Typ Int??
// Swift 5: result hat den Typ Int?
Exclusivity Enforcement: Schon seit Swift 4 versucht der Compiler, fehlerhafte Parallelzugriffe auf Variablen zu entdecken. Diese Tests, die vor allem Fehler in multiläufigen Algorithmen vermeiden sollen, sind in Swift 5 noch strenger geworden. Details können Sie hier nachlesen: https://swift.org/blog/swift-5-exclusivity
SIMD-Unterstützung (Single Instruction, Multiple Data): SIMD ist eine Low-Level-Bibliothek um mit Vektoren fixer Größe zu arbeiten (simd/simd.h). Diese Bibliothek kann nun auch von Swift genutzt werden. Der resultierende Code ist nicht sonderlich elegant; Entwickler, die mathematische Algorithmen in Swift effizient implementieren wollen, werden sich über das Feature trotzdem freuen. Details siehe: https://github.com/apple/swift-evolution/blob/master/proposals/0229-simd.md
Dynamically callable types: Swift bietet einen neuen Weg zur Definition von Typen, die wie Funktionen aufgerufen werden können. Für »gewöhnliche« Swift-Programmierer ist das Feature von geringer Relevanz. Es verbessert aber das Zusammenspiel mit anderen Programmiersprachen, z.B. wenn ein Swift-Programm auf Python-Bibliotheken zurückgreifen will. Details: https://github.com/apple/swift-evolution/blob/master/proposals/0216-dynamic-callable.md
@unkown-Attribut zur Auswertung von Enumerationen: Die Auswertung von Enumerationswerten in switch mit einem default-Zweig kann problematisch sein, wenn die Enumeration später erweitert wird: Dann gilt der default-Zweig für mehr Fälle als ursprünglich gedacht. Abhilfe schafft das Attribut @unknown für den Default-Zweig, das eine Warnung auslöst, wenn die externe Enumeration erweitert wurde. Bitte beachten Sie, dass dieses Feature nicht für selbst definierte Enumerationen gedacht ist und daher mit solchen Enumerationen auch nicht sinnvoll getestet werden kann! Es ist nur für Enumerationen gedacht, die sich außerhalb der Kontrolle des Entwicklers z.B. in irgendwelchen Bibliotheken befinden. Details: https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md
count(where:) zählt alle Elemente, die eine Bedingung erfüllen (Details).
compactMapValues verändert die Values eines Dictionaries und eliminiert alle Key/Value-Paare, deren Werte nil sind. compactMapValues ist eine Kombination aus mapValues und filter (Details).
Die Methode index(of:) wurde umbenannt in firstIndex(of:).
Die Methode isMultiple(of:) testet, ob eine Zahl ein Vielfaches einer anderen Zahl ist. n.isMultiple(of: 4) entspricht n % 4 == 0.
Beachten Sie, dass bereits in Swift 4.1 und 4.2 diverse Änderungen/Erweiterungen der Standardbibliothek durchgeführt sowie einige Swift-Neuerungen eingeführt wurden (automatische Implementierung von Equatable und Hashable, Zufallszahlen, compactMap, toggle, allSatisfy, removeAll etc.). Die wichtigsten Neuerungen habe ich in diesem Blog in den Artikeln Swift 4.1 und Swift 4.2 zusammengefasst.
Swift mit Linux/Docker
Apple stellt wie bisher Swift-Binärpakete für Ubuntu 14.04, 16.04 und 18.04 zur Verfügung. Neu ist, dass es für die Swift-Version 4.2 ab sofort geregelte monatliche Updates gibt (siehe diese Ankündigung im Swift-Forum). Es ist zu erwarten, dass es derartige Releases auch für Swift 5 geben wird, sobald diese Version fertig gestellt ist.
Leider kann sich Apple weiterhin nicht aufraffen, Swift als APT- oder YUM-Paketquelle anzubieten. Das würde die Installation und Wartung natürlich stark vereinfachen.
Etwas verbessert hat sich die Docker-Unterstützung: Aus meiner Sicht war Docker schon seit jeher der beste Weg, um Swift unter verschiedenen Linux-Distributionen sowie unter Windows zum Laufen zu bringen. Mittlerweile gibt es im Dockerhub offizielle Swift-Images — aktuell aber leider erst für Version 4.n.
Wer Swift 5 als Docker-Image benötigt, muss momentan auf ein inoffizielles Image des Vapor-Entwicklers Tanner zurückgreifen (siehe diese Ankündigung).
Praxis
Der Umbau der Beispielprogramme meines Buchs von Swift 4 auf Swift 5 hat sich bisher als erstaunlich unkompliziert erwiesen: Viele Änderungen in Swift 5 sind Zusatz-Features und bedürfen gar keiner Anpassung am Code. Die wenigen doch erforderlichen Modifikationen erkannte der in Xcode integrierte Code-Konverter sehr zuverlässig.
Ganz generell richten sich sehr viele Neuerungen, die in Swift seit Version 3 eingeflossen sind, an die Entwickler von (Standard-)Bibliotheken. Für den »normalen« App-Entwickler bzw. die Entwicklerin sind viele Features nur von geringer Relevanz.
Vorschau auf die Neuauflage meines Buchs
Die Neuauflage meines Swift-Buchs wird voraussichtlich im Mai erscheinen. In dem Buch berücksichtige ich natürlich alle wichtigen Neuerungen von Swift 5. Ein neues Kapitel behandelt auf vielfachen Leserwunsch Core Data und SQLite. Stark überarbeitet habe ich den Abschnitt zur Lokalisierung von Apps. (Xcode zickt dabei wie eh und je …) Außerdem gibt es da und dort ein paar neue Beispiele (Slider-Puzzle-App, macOS Dark Mode etc.)
Das Buch kann bereits beim Rheinwerk Verlag oder bei Amazon vorbestellt werden. Die E-Book-Ausgabe bzw. das Bundle aus Buch und E+Book gibt es allerdings nur beim Rheinwerk Verlag!
Mein aktuelles Notebook ist ein Lenovo E320 (2012, i3-CPU, notebookcheck). Erstaunlicherweise funktioniert das Gerät noch immer passabel, aber naturgemäß geht es dem Ende seiner Tage entgegen. In den letzten Tagen habe ich mich näher dem Notebook-Markt auseinandergesetzt. Das Ziel ist ein leistungsstarkes Notebook, das nicht nur unterwegs eingesetzt werden soll, sondern täglich als Desktop-Ersatz. Bei meiner Suche bin direkt in die NVIDIA-Falle gestolpert …
PS: Dieser Blog-Beitrag hat zugegebenermaßen den Charakter eines persönlichen Notizzettels. Klar ist auch, dass die folgende Übersicht nur eine Momentaufnahme (Februar 2019) sein kann; ich habe nicht vor, den Text in Zukunft zu aktualisieren. Aber vielleicht helfen die gesammelten Informationen und die vielen Links anderen Leuten, die gerade auf der Suche nach einem Traum-Linux-Notebook sind :-)
Kommentare sind willkommen!
Wunschliste
Das sind meine Präferenzen, die sich zugegebenermaßen ein wenig widersprechen … (15-Zoll / leicht, starke CPU / leise)
Linux-kompatibel
15-Zoll-Bildschirm in einem möglichst kompakten/leichten Gehäuse (max. 2kg)
leistungsstarke CPU (viele virtuelle Maschinen gleichzeitig), idealerweise Intel i7 H-Serie
wartungsfreundlich, RAM- und SSD-Slots leicht zugänglich (kostengünstige Aufrüstung auf 32 GB/2 TByte)
bei moderater Nutzung möglichst lautlos
ordentliche Tastatur ohne Ziffernblock mittig vor dem Bildschirm
möglichst großes Touchpad, idealerweise wie bei einem MacBook
Weniger wichtig
Akkulaufzeit
hohe Displayauflösung (FHD, also 1920×1080, reicht)
Dell XPS 15
Die naheliegendste Entsprechung meiner Wünsche bietet das Dell XPS 15 (Test bei notebookcheck, noch ein Test bei notebookcheck). Optisch sehr ansprechend, Gewicht gerade noch OK, je nach Modell tolle CPU (i7 8750H, 6 Cores/12 Threads). Für das XPS 15 spricht, dass es weit verbreitet ist und dass es im Internet unzählige Installationsanleitungen für Linux gibt, z.B. auf GitHub, im archlinux-Wiki, bei askubuntu, auf reddit sowie Blog1, Blog2, Blog3.
Allerdings gibt es das Gerät ebenso wie das verwandte Dell Precision 5530 (notebookcheck) nur mit einer NVIDIA-GPU. Und die macht unter Linux oft Probleme: Dell-Forum, askubuntu, Blog. Ein paar allgemeine Anmerkungen zu NVIDIA folgen gleich …
Unzählige Rezensionen und Blogs berichten zudem von Qualitätsproblemen bzw. Qualitätsstreuungen bei Dell. Anscheinend ist es trotz des hohen Preises ein Glücksspiel, ob man ein ordentliches Gerät erhält oder nicht — siehe z.B. amazon.de, nochmals amazon.de, amazon.com, notebooksbilliger.de, ycombinator. Ein Thema für sich ist das offenbar gelegentlich auftretende Spulenfiepen: Google-Suche xps coil whine.
Lenovo X1 Extreme oder Lenovo P1
Letztlich bin ich zur Einsicht gekommen, dass Dell für mich leider nicht in Frage kommt und dass ich wohl Lenovo treu bleiben werde. (Alle meine bisherigen Notebooks waren von IBM bzw. Lenovo.)
Das Gegenstück zum XPS 15 bei Lenovo heisst X1 Extreme (die »Consumer«-Variante, Test bei notebookcheck, Preise bei geizhals) bzw. P1 (die »Workstation«-Variante, notebookcheck, geizhals). Beide Geräte sind äußerlich baugleich, es gibt aber unterschiedliche Ausstattungsoptionen (z.B. Xeon-CPU für den P1). Überraschenderweise gibt es für den P1 fallweise günstigere Angebote (bei vergleichbarer Ausstattung) als für den X1E.
Im Vergleich zum XPS 15 sind die Geräte minimal größer, aber gleichzeitig ein wenig leichter, primär wegen des kleineren Akkus. Der größte Vorteil zum XPS 15 sind aus meiner Sicht zwei PCIe-SSD-Slots. Der größte Nachteil ist die geringere Display-Helligkeit beim FHD-Display (max. 300 Nits vs 400 Nits bei Dell). Wie beim XPS 15 gibt es leider kein Modell ohne NVDIA-GPU.
Auch bei diesen Notebooks sind im Internet diverse Probleme dokumentiert, z.T. mit Lösungsideen: Lenovo-Forum, reddit, nochmals reddit (veraltet), Blog.
Es ist unbedingt erforderlich, vor irgendwelchen Linux-Installationen ein BIOS-Update durchzuführen (siehe z.B. reddit)! Ohne dieses Update besteht die Gefahr, dass das Notebook funktionsunfähig wird (»bricking«, wie es im Englischen so schön heißt).
In den Diskussionen taucht immer wieder die Empfehlung auf, Pop!_OS zu verwenden. Diese von Ubuntu abgeleitete Distribution installiert die NVIDIA-Treiber sofort und hilft mit Zusatzprogrammen beim Umschalten zwischen der Intel- und der NVIDIA-GPU. Pop!_OS wird von der Firma System 76 entwickelt, die im englischen Sprachraum ähnliche/gleiche Notebooks wie Tuxedo verkauft. Links: Forbes, reddit
Notebooks mit Intel-H-CPU, aber ohne NVIDIA: Fehlanzeige
Kurz zusammengefasst: der einzige gravierende Nachteil meiner Wunschkandidaten besteht in der elenden NVIDIA-GPU. Es muss doch auch Notebooks mit Intel-H-CPU ohne dezidierte GPU geben, oder? Eine entsprechende Suche auf geizhals führt allerdings zu einer mageren Liste — ganze 7 Geräte sind tatsächlich lagernd/lieferbar, wirklich interessant ist keines.
Wenn schon eine GPU, dann wenigstens eine von AMD! Eine weitere geizhals-Suche zeigt: Solche Notebooks gibt es. Sie sind schön, teuer und von Apple. Als Linux-Notebook sind sie ungeeignet und auch preislich liegen sie außerhalb meiner Vorstellungen.
Nicht auf geizhals zu finden ist schließlich ein eher hässliches und 2,3 kg schweres Workstation-Notebook von Tuxedo. Die technischen Daten sind OK (i7-8750H, bis zu 64 GB RAM), der Preis auch (ca. EUR 1520 mit 32 GB RAM + 2 TB SSD), aber sonst vermag das Gerät nicht zu begeistern.
Warum nicht NVIDIA?
Vielleicht fragen Sie sich, woher mein Widerwille gegen NVIDIA stammt. Die Firma baut ja zweifelsfrei grandiose Grafikkarten, die unter Windows gut funktionieren …
NVIDIA weigert sich nun schon seit Jahrzehnten, mit den Linux-Kernelentwicklern vernünftig zu kooperieren. Ich mag die Firma also nicht mit dem Kauf eines Notebooks fördern.
Es ist natürlich möglich, Notebooks und PCs mit NVIDIA-GPUs unter Linux zu nutzen, aber die Installation der Treiber ist genau das, was Linux-Kritiker oft bemängeln: ein zeitaufwändiges, mühsames Gefrickel. (Und in meiner speziellen Situation werde ich auf dem Notebook sicher nicht nur eine Linux-Distribution installieren.) Niemand kann heute sagen, für welche NVIDIA-GPUs es in zwei oder drei Jahren noch Treiber gibt und welche Distributionen bzw. Kernel-Versionen dazu kompatibel sind.
Eine dezidierte GPU (egal welchen Herstellers) bringt für mich keinen Zusatznutzen. Ich brauche die Grafikleistung ganz einfach nicht. ABER: Weil die GPU nun einmal eingebaut ist, frisst sie Strom, macht das Gerät laut und verkürzt die Akkulaufzeit.
Sie können die GPU nicht einfach ‚ausschalten‘: Bei vielen aktuellen Notebooks (definitiv beim Dell XPS 15 9570 sowie bei den Lenovos X1 Extreme bzw. P1) sind alle externen Grafikausgänge mit der NVIDIA-Grafikkarte verbunden. Solange Sie nur das Notebook-Display verwenden, können Sie das Gerät also mit der integrierten Intel-GPU betreiben. Externe Monitore, Beamer etc. funktionieren aber nur, wenn die NVIDIA-GPU aktiv ist. (Siehe z.B. Bumblebee-Wikie sowie archlinux-Wiki.) Je nachdem, für welche Treiber bzw. für welche Distribution Sie sich entscheiden, erfordert der Wechsel zwischen interner Grafik und NVIDIA-GPU einen Neustart. Mühsam hoch drei!
Dann eben eine langsamere CPU
Damit platzt der Traum von einem Notebook mit Intel-H-CPU. Die nächst langsamere und energiesparendere Variante sind Intel-U-CPUs, z.B. i7 8550U oder i7 8565U. Kurzzeitig liefern diese CPU nahezu dieselbe Single-Core-Leistung wie die 8750H, aber die Multi-Core-Leistung (4 Cores/8 Threads) ist deutlich geringer als beim 8750H.
Auf dieser Basis gibt es Hunderte von Notebooks. Viele davon sind im Low-End-Bereich angesiedelt (z.B. mit max. 16 GB RAM) und kommen von vorne herein nicht in Frage. Bei einigen Kandidaten habe ich mir die Spezifikationen näher angesehen. Alle hier aufgezählten Modelle sind ohne dezidierte GPU erhältlich und können auf 32 GB RAM oder mehr aufgerüstet werden. Ich habe auch einige 14-Zoll-Geräte aufgenommen, obwohl meine Präferenz klar bei 15 Zoll ist. (Der Unterschied klingt geringfügig. Aber genau genommen sind es 14 Zoll vs 15,6 Zoll Bildschirmdiagonale. Daraus ergibt sich eine zusätzliche Fläche von 25%!)
14-Zoll-Geräte
Lenovo E490 (noch kein Test verfügbar, Datenblatt auf lapstars): i7 8565U, 14-Zoll-Display mit nur 250 Nits, quasi ein direkter Nachfolger meines E320. Relativ preisgünstig, aber für ein 14-Zoll-Gerät auch relativ schwer (1,75 kg).
Lenovo T480 (lapstars, Test eines ähnlichen Geräts bei notebookcheck): ein solides Gerät mit 3 Jahren Garantie, aber nur um 0,1 kg leichter als das E490, gleich schlechtes Display, Vorjahres-CPU i7 8550U und viel teurer.
Lenovo T480s (lapstars, Test eines ähnlichen Geräts bei notebookcheck): Mit 1,32 kg ein ungemein leichtes Gerät, quasi ein MacBook Air von Lenovo. Gleichzeitig etwas größerer Akku als die beiden vorigen Modelle. Wiederum i7 8550U, gleiches Display wie oben. Teuer, mit vertretbaren Kosten nur auf 24 GB RAM aufrüstbar (8 GB verlötet, zweiter Slot frei). Aber definitiv ein ideales Reise-Notebook mit langer Laufzeit.
Lenovo T490, T490S: Die Nachfolger der obigen zwei Geräte sind schon angekündigt, aber noch nicht lieferbar. Die Geräte sind etwas leichter und stellen mehrere Displays (auch hellere) zur Wahl. Konkrete Konfigurationen und Preise sind noch nicht bekannt.
Tuxedo Infinity Book Pro 14 v4 (Herstellerseite, Test bei notebookcheck): eine spannende Alternative zum T480s! Helleres Display (370 Nit lt. Hersteller), aktuelle CPU (i7 8565U), aber kleinerer Akku, kleines Touchpad, 1 Jahr weniger Garantie. In meiner Wunschkonfiguration (32 GB/2TB) deutlich günstiger als das T480s.
15-Zoll-Geräte
HP 850G (z.B. geizhals, Test ähnlicher Modelle bei notebookcheck und bei laptopmedia): i7-8550U, 1,8 kg, breite Tastatur mit eigenwilligem Layout (Seite auf/ab sind komplett abseits), dafür helles Display mit 400 Nits. Vergleichsweise breites Gehäuse (2,5 cm breiter als Dell XPS 15, 1,8 cm breiter als Lenovo T580).
Lenovo E590 (z.B. lapstars oder ein anderes Modell bei lapstars, Test bei notebooks-und-mobiles): Der große Bruder zum E490 hat wiederum nur ein Display mit 250 Nits (die düsteren Displays sind ein generelles Lenovo-Problem) und leider eine breite Tastatur mit Ziffernblock. Das Gewicht beträgt laut Hersteller 2,1 kg, laut Test aber nur 1,9 kg? Das i7-Modell ist ärgerlicherweise nur in Kombination mit einer dezidierten Grafikkarte zu erhalten — immerhin von AMD (Radeon RX 550X GDDR5). Einziger Pluspunkt: relativ preisgünstig.
Lenovo T580 (lapstars, Test eines ähnlichen Geräts bei notebookcheck): Vorjahres-CPU i7 8550U , ebenfalls nur 250 Nits, ebenfalls breite Tastatur mit Ziffernblock. Mit 1,95 kg immerhin gerade unter dem magischen 2kg-Limit. Für die gebotene Leistung sehr teuer.
Lenovo T590: Auch hier ist das Nachfolgemodell schon angekündigt, aber noch nicht lieferbar. Vorauss. etwas leichter, ca. 1,75 kg. Bei den Displays gibt es anscheinend die Wahl zwischen dem alten FHD-Display mit 250 Nits und einem neuen UHD-Display mit 500 Nits.
Tuxedo Infinity Book Pro 15 v4 (Herstellerseite, noch kein Test verfügbar): weitgehend dieselben technischen Daten wie wie beim Inifinity Pro 14, aber eben mit größerem Gehäuse (mit 1,7 kg immer noch erfreulich leicht). Display mit 300 Nits. Leider wie bei den obigen Lenovos eine Tastatur mit Ziffernblock und ein Touchpad, das gegenüber der Leertaste viel zu weit rechts platziert ist (Bild).
Fazit
Die Dominanz von NVIDIA in High-End-Notebooks ist im höchsten Ausmaß frustrierend. Es scheint unmöglich zu sein, auch nur einigermaßen attraktive 15-Zoll-Alternativen zum Dell XPS 15 oder zum Lenovo X1 Extreme bzw. Lenovo P1 ohne NVIDIA-GPU zu finden.
Bei den 14-Zöllern bieten das Tuxedo Infinity 14 und das E490 ein gutes Preis/Leistungs-Verhältnis. Die bereits angekündigten Modelle T490 und T490S könnten interessante Alternativen werden.
Auf der Basis 32 GB RAM / 2 TB SSD ist der Preisunterschied zwischen dem Lenovo P1 (aktuell ist das Basismodell auf lapstars relativ günstig zu haben) und den in Frage kommenden NVIDIA-freien 15-Zöllern gering (ca. 300 EUR). Die Versuchung ist groß, in den sauren NVIDIA-Apfel zu beißen, d.h. die oben aufgezählten Nachteile eben in Kauf zu nehmen und dafür ein ansonsten äußerst attraktives Notebook zu bekommen.
Mit heutiger Hardware wäre mein Traumnotebook wohl am ehesten ein Dell XPS 15 (Gehäuse/Display) mit Dell-XPS-13-Innenleben (Mainboard, CPU) oder ein Lenovo P1/X1E (Gehäuse/Display/Tastatur!) mit i7-8565 CPU ohne dezidierte GPU. In Kombination mit den großen Akkus von XPS 15 oder P1/X1E wären damit leise Entwickler-Notebooks mit sehr langer Akku-Laufzeit möglich. Den Performance-Nachteil im Vergleich i7-8750H würde ich hinnehmen. (Notebook-Hersteller, hört ihr mich? Vermutlich nicht …)
PS: Wenn Sie ein interessantes Modell kennen, das ich übersehen habe, wenn Sie Erfahrungen mit einem der hier diskutierten Modelle haben, oder wenn Sie Korrekturen einbringen möchten, freue ich mich über Ihre Kommentare bzw. Mails!