(Bild: Open Elements)
Für Java gibt es eine Fülle an verschiedenen Logging-Bibliotheken und Möglichkeiten, Log-Nachrichten auszugeben. Aber welche davon sind wirklich performant?
In den vorherigen Posts zum Thema Java Logging (Best Practices [1], Logging Facades [2]) habe ich bereits erwähnt, dass es eine Fülle an Java Libraries zum Thema Logging gibt. Nachdem wir im letzten Post geklärt haben, wie man mit einer Facade verschiedene Logger vereinen kann, wollen wir uns nun die Performance von Logging-Bibliotheken anschauen.
Um kleine Teile einer Java-Anwendung oder -Bibliothek mittels eines Benchmarks zu überprüfen, gibt es in Java das Tool Java Microbenchmark Harness (JMH) [3], das vom OpenJDK bereitgestellt wird, um Performance-Benchmarks durchzuführen. Es führt ähnlich wie bei Unit-Tests kleine Teile der Anwendung (Micro-Benchmarks) aus und analysiert sie. Hierbei kann man unter anderem einstellen, ob der Code zuvor mehrfach für ein paar Sekunden ohne Messung durchlaufen soll, um die JVM und JIT "warmzulaufen".
Diese und andere Parameter lassen sich bei JMH ähnlich wie bei JUnit einfach durch Annotations definieren. Ein simples Beispiel für einen Benchmark sieht folgendermaßen aus:
@Benchmark
@BenchmarkMode(Mode.Throughput)
@Warmup(iterations = 4, time = 4)
@Measurement(iterations = 4, time = 4)
public void runSingleSimpleLog() {
logger.log("Hello World");
}
Das Beispiel führt vier Durchläufe zum Aufwärmen durch, gefolgt von vier Messdurchläufen. Jeder Durchlauf dauert vier Sekunden, und das Messergebnis zeigt an, wie viele Operationen pro Sekunde durchgeführt werden konnten. Konkret bedeutet das, wie oft "Hello World" geloggt werden konnte. Das Ganze bekommt man nach dem Durchlauf tabellarisch in der Kommandozeile ausgegeben, kann es aber auch beispielsweise als JSON- oder CSV-Datei speichern.
Mithilfe von JMH habe ich einen Open-Source-Benchmark für Logging-Frameworks erstellt, das bei GitHub einsehbar ist [4]. Er überprüft aktuell folgende Logging-Bibliotheken beziehungsweise Set-ups auf ihre Performance:
Für jede dieser Konstellation gibt es verschiedene Benchmarks, die die Performance vom Erstellen des Logger über das Loggen einer einfachen "Hello World"-Nachricht bis hin zu komplexen Logging-Aufrufen (Placeholder in Message, Marker, MDC Nutzung, etc.) messen.
Die Messungen zeigen, dass Logging-Frameworks generell sehr performant sind. Auf der anderen Seite führten sie aber auch ein paar Erkenntnisse zutage, die sicherlich nicht jedem direkt klar sind.
Im Folgenden findet sich eine Übersicht von Messergebnissen beim einfachen Loggen einer "Hello World" Nachricht:
Ein erstes Ergebnis der Messungen ist, dass ein Logging auf die Konsole immer deutlich langsamer ist als ein Logging ins Dateisystem. Während man beim Logging in eine Datei 200.000 bis 300.000 Aufrufe des Loggers pro Sekunde erreichen kann, sind es bei einer Ausgabe auf die Konsolen immer deutlich unter 100.000 Operationen die Sekunde gewesen. Da alle Logging-Libraries hier mit System.out bzw. System.err arbeiten, macht es auch kaum einen Unterschied in der Performance, welche Bibliothek man nutzt. Hier wird es in Zukunft spannend zu schauen, ob man durch Tricks oder Umbauten eine bessere Performance hinbekommen kann.
Einen weiteren großen Unterschied sieht man, wenn man die Messwerte von synchronen bzw. asynchronen Logging in eine Datei betrachtet. Hier wird sofort deutlich, dass asynchrones Logging deutlich schneller ist. Die folgenden Tabellen zeigen die Messwerte von asynchronen Logging im Vergleich zu synchronen Logging:
Die klar erkennbar höherer Performance liegt daran, dass die Schreiboperation der asynchronen Logger nicht blockiert. Die Logger Log4J2 und Chronicle Logger nutzen zwar intern unterschiedliche Bibliotheken intern, basieren aber beide auf einer "lock-free inter-thread communication library". Während bei Log4J hierbei LMAX Disruptor [5] als Bibliothek hinzugefügt werden muss, die intern über Ringbuffer das asynchrone Logging ermöglicht, basiert der Chronicle Logger direkt auf der Chronicle Queue Bibliothek [6].
Konkrete Beschreibung der intern genutzten Libraries und wie diese eine asynchrone Kommunikation beziehungsweise das Schreiben ins Dateisystem ermöglichen, lässt sich der Dokumentation entnehmen.
Wenn man die Performance von Log4J2 und Chronicle Logger vergleicht, kann man sehen, dass der Chronicle Logger noch einmal deutlich schneller ist. Dieser Performance-Vorteil kommt aber auch mit einem Nachteil, dem man sich bewusst sein muss: Während Log4J2 auch im asynchronen Modus weiterhin zeilenweise ein für den Menschen einfach lesbares Logging im Dateisystem erzeugt, schreibt der Chronicle Logger alle Nachrichten in einem Binärformat. Hier wird zum Lesen bzw. Parsen dann ein Tooling benötigt, das der Logger aber mitliefert. Darüber hinaus ist die Varianz der Testergebnisse des Chronicle Logger deutlich höher. Als Grund vermute ich, dass die genutzt Chronicle Queue die binären Daten zum Schreiben des Logging intern verwaltet und deren Größen immer dynamisch anpasst. Dies muss allerdings noch weiter untersucht werden. Die folgende Tabelle zeigt einmal eine Übersicht der Varianz:
Wie man sehen kann, ist nicht nur die Wahl einer Logging Bibliothek, sondern auch deren Konfiguration extrem wichtig für die Performance. Während das Logging auf die Konsole während der Entwicklung sicherlich sehr angenehm ist, kann man sich beispielsweise überlegen, ob die Nutzung des Konsolen-Logging im Live-Betrieb wirklich immer erforderlich ist. Auch zeigt sich, dass eine Nutzung von asynchronen Loggern sinnvoll sein kann, wenn die Performance des Systems wirklich kritisch ist. Das kommt aber natürlich mit einer höheren Komplexität und zusätzlichen transitiven Abhängigkeiten einher. Letztlich muss also jedes Projekt weiterhin selbst für sich entscheiden, welcher Logger am sinnvollsten ist. Durch die hier genannten Zahlen hat man aber nun eine weitere Basis, um das festzulegen.
URL dieses Artikels:
https://www.heise.de/-9278737
Links in diesem Artikel:
[1] https://www.heise.de/blog/Best-Practices-und-Anti-Pattern-beim-Logging-in-Java-und-anderen-Sprachen-7336005.html
[2] https://www.heise.de/blog/Logging-Facades-fuer-Java-7355974.html
[3] https://github.com/openjdk/jmh
[4] https://github.com/OpenElements/java-logger-benchmark
[5] https://github.com/LMAX-Exchange/disruptor
[6] https://github.com/OpenHFT/Chronicle-Queue
[7] mailto:rme@ix.de
Copyright © 2024 Heise Medien
Das Java Module System ist in der Entwicklung von Anwendungen und Bibliotheken noch immer eine selten genutzte Funktion. Dabei ist der Einstieg oft leicht.
In den letzten Jahren hat man immer wieder viele unterschiedliche Meinungen zum Java-Modulsystem gehört. Während viele Entwicklerinnen und Entwickler der standardisierten Möglichkeit zur Definition von Modulen positiv entgegenstehen, gibt es viele kritische Meinungen, die der Definition beispielsweise fehlende Features wie die Unterstützung von Versionen ankreiden. Diese Diskussion möchte ich hier allerdings überhaupt nicht aufmachen. Ich selber sehe viele Vorteile im Modulsystem und kann verstehen, dass vor allem Framework und Bibliotheksentwickler das Ganze nutzen (wollen).
Ein großer Nachteil ist hier allerdings, dass eine (transitive) Abhängigkeit, die in keiner Weise auf das Java Modulsystem angepasst ist, möglicherweise nicht zu den Definitionen und Einschränkungen des Modulsystems passt und somit nicht zum Modul-Path hinzugefügt werden kann. Das Java-Modulsystem erstellt automatisch ein Modul für jedes JAR, das es auf dem Modul Path findet. Hierbei kann es zu einigen Problemen kommen, die man allerdings oft durch kleine Anpassungen in einer Bibliothek beheben kann.
Diese Probleme möchte ich in mehreren Posts einmal genauer betrachten und mögliche Lösungen aufzeigen. Dieser Beitrag geht auf die Nutzung und Definition von automatischen Modulen einmal genauer ein.
Eine wichtige Definition des Modulsystems ist, dass jedes Modul einen eindeutigen Namen benötigt. Hierbei wird zwischen explizit deklarierten Modulen, die über eine module-info.java verfügen, und automatischen Modulen, die implizit deklariert werden, unterschieden. Weitere Infos lassen sich der JavaSE Spec [1] entnehmen. Wenn man in seinem Projekt nicht die Vorteile des Modulsystems durch die Nutzung einer module-info.java nutzen möchte, reicht es völlig aus, wenn man die eigene Bibliothek als automatisches Modul definiert.
Die einzige Voraussetzung hierfür ist, dass das Modul über einen eindeutigen Namen verfügt. Zwar kann Java für JARs auf dem Module Path zur Not sogar einen Namen aus dem Namen des JAR extrahieren, was aber ganz klar nicht empfohlen ist. Vor allem, da die Definition eines Namens für ein automatisches Modul wirklich sehr einfach ist. Es muss lediglich die Automatic-Module-Name Property in der MANIFEST.MF des JARs definiert werden. Wenn Maven oder Gradle als Buildtool genutzt werden, kann man dies über ein Plug-in sogar voll automatisiert erstellen.
Wie man im folgenden Beispiel sehen kann, muss bei einem Maven Build nur das maven-jar-plugin entsprechend konfiguriert werden:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifestEntries>
<Automatic-Module-Name>com.example.lib</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
In Gradle lässt sich das Ganze einfach durch Nutzung des Java-Library-Plug-ins umsetzen, das Bestandteil jedes Java Builds sein sollte. Eine ausführliche Dokumentation zum Einsatz in Gradle kann man hier [2] finden, während der folgende Code eine einfache Einbindung in ein Projekt zeigt:
tasks.jar {
manifest {
attributes("Automatic-Module-Name" to "com.example.lib")
}
}
Da die Änderungen wirklich sehr einfach sind, eignen sie sich auch hervorragend, um das Ganze für Open Source Libraries als Pull Request anzubieten. In einem Beispiel [3] habe ich einen PR zur Definition eines Automatic-Module-Name zu einer Open Source-Java-Bibliothek hinzugefügt. Vielleicht liest ja eine oder ein Open Source Developer mit und erstellt für eine solche Umstellung der eigenen Bibliotheken ein „Good First Issue“, das beispielsweise zum Hacktoberfest [4] von Neulingen umgesetzt werden kann.
URL dieses Artikels:
https://www.heise.de/-7434695
Links in diesem Artikel:
[1] https://docs.oracle.com/javase/specs/jls/se16/html/jls-7.html#jls-7.7.1
[2] https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_modular_auto
[3] https://github.com/offbynull/portmapper/pull/48
[4] https://hacktoberfest.com
[5] https://heise-academy.de/schulungen/virtual-threads?wt_mc=intern.academy.ix.ws_virtualthreads.newsticker.link.link
[6] mailto:rme@ix.de
Copyright © 2024 Heise Medien
This is a bug-fix release for the 1.23.0 release, addressing several regressions.
This release has been made by @Alkarex, @andris155, @math-GH, @yzqzss, @zhzy0077
Full changelog:
base_url being cleared when saving settings #5992.dockerignore #5996A few highlights ✨:
Breaking changes 💥:
amd64, arm32v7, arm64v8 with automatic detection #5808
-arm suffix anymoreThis release has been made by several contributors: @Alkarex, @ColonelMoutarde, @FireFingers21, @Frenzie, @kasimircash, @andris155, @b-reich, @foux, @jaden, @jan-vandenberg, @joestump, @jtracey, @mark-monteiro, @martinrotter, @math-GH, @passbe
Full changelog:
VARCHAR) text fields length to maximum possible #5788CRON_MIN if any environment variable contains a single quote #5795TRUSTED_PROXY environment variable used in combination with trusted sources #5853
(Bild: Andrey Suslov/Shutterstock.com)
Electron ist nicht nur sprichwörtlich das Schwergewicht in der Cross-Plattform-Entwicklung. Kleiner und sicherer will Tauri sein, das im Backend auf Rust setzt.
Viele Anwendungen wie Signal, Slack, WhatsApp, Discord oder Visual Studio Code nutzen unter der Haube Electron [1], ein Framework zur plattformübergreifenden Ausführung von Anwendungen. Die App selbst wird dabei mithilfe von Webtechnologien wie HTML, CSS, JavaScript und WebAssembly [2] implementiert. Electron verpackt die Anwendungen gemeinsam mit dem Webbrowser Chromium und der Runtime Node.js in ein plattformspezifisches Bündel. Über das sogenannte Backend in Node.js kann die Webanwendung sämtliche Schnittstellen des Betriebssystems aufrufen.
Entwickler sparen bei diesem Ansatz viel Zeit, Geld und Aufwand, da sie ihre Anwendung nur einmal mit Webtechnologien entwickeln müssen und auf einer Vielzahl von Plattformen vertreiben können, Webbrowser eingeschlossen.
Allerdings sind Electron-Anwendungen aufgrund der Bündelung gleich zweier Laufzeitumgebungen leider auch sehr groß: Schon eine einfache Hello-World-Anwendung wird in Electron verpackt rund 100 MByte groß.
Jede ausgeführte Instanz führt zu einem Mehrverbrauch an Arbeitsspeicher, und veraltete Node.js- und Chromium-Versionen innerhalb eines Anwendungsbündels können zu Sicherheitsproblemen führen. Entwickler müssen Updates nicht nur bei Aktualisierungen ihrer App vertreiben, sondern auch, wenn sich Electron aktualisiert hat.
(Bild: Tauri.app)
Hier kommt Tauri [4] ins Spiel: Der Electron-Herausforderer erlaubt ebenfalls das Verpacken von Webanwendungen in Form eines plattformspezifischen Bündels. Allerdings fügt Tauri keinen eigenen Webbrowser hinzu, sondern nutzt die Web-View des Betriebssystems, auf dem die Anwendung ausgeführt wird: WebView2 auf Windows, WebKit unter macOS und WebKitGTK auf Linux.
In Tauri 2.0, das sich derzeit noch in der Alpha-Phase befindet, sollen sich iOS und Android zur Liste der unterstützten Plattformen hinzugesellen. Diese Plattformen können mit Electron nicht adressiert werden. Tauri würde damit auch Wrapper für mobile Betriebssysteme wie Cordova oder Capacitor [5] ersetzen.
Im Backend greift Tauri nicht auf JavaScript zurück, sondern auf Rust. Insofern muss auch Node.js nicht mit der Anwendung verpackt werden. Eine Hello-World-Anwendung ist mit Tauri gerade einmal 600 KByte groß. Mithilfe von Sidecars können Anwendungen mit externen Binärdateien ausgeliefert werden, die nochmal in anderen Sprachen verfasst sind.
Und auch das Thema Security nimmt bei Tauri einen hohen Stellenwert [6] ein: So können die benötigten Programmierschnittstellen gezielt aktiviert werden. Nur dann wird der dafür erforderliche Code überhaupt in das Bündel aufgenommen. Tauri bringt auch viele erweiterte Funktionen wie einen Auto-Updater oder die Integration in das Benachrichtigungssystem der Plattform mit.
Der Nachteil von Tauri besteht allerdings gerade darin, dass die Webanwendung nun in verschiedenen Ausführungsumgebungen ausgeführt wird: Die Unterstützung bestimmter Webschnittstellen oder CSS-Features variiert zwischen unterschiedlichen Web-Engines, sodass die Anwendung auf allen Zielumgebungen getestet werden muss.
Während Electron von GitHub herausgegeben wird, ist Tauri ein Community-getriebenes Projekt. Finanziell unterstützt wird Tauri etwa von 1Password, deren Passwortmanager zumindest derzeit noch auf Electron basiert.
Auch wenn die erste Version von Tauri schon länger erschienen ist, bleibt es noch das "New Kid on the Block". Große Namen finden sich unter den Tauri-Verwendern [7] derzeit noch nicht. Nicht nur aufgrund der deutlich geringeren Bundle-Größe sollte das Framework jedoch in Betracht gezogen werden, vielleicht sogar noch vor dem Platzhirsch Electron. Eine neue Tauri-App lässt sich über den npm-Befehl npm create tauri-app , auf der Bash mit sh <(curl https://create.tauri.app/sh oder auf der Powershell mit irm https://create.tauri.app/ps | iex erstellen.
URL dieses Artikels:
https://www.heise.de/-9538237
Links in diesem Artikel:
[1] https://www.electronjs.org/
[2] https://www.heise.de/blog/WebAssembly-Das-Web-wird-nativ-er-4023451.html
[3] http://paint.js.org/
[4] https://tauri.app/%E2%80%8B
[5] https://www.heise.de/blog/Capacitor-oder-Cordova-Welche-Plattform-sollten-Entwickler-webbasierter-Mobilapps-waehlen-4690975.html
[6] https://tauri.app/v1/references/architecture/security%E2%80%8B
[7] https://github.com/tauri-apps/awesome-tauri#applications%E2%80%8B
[8] mailto:rme@ix.de
Copyright © 2023 Heise Medien
(Bild: Pixelvario/Shutterstock.com)
Um eine Webanwendung in Chromium-basierten Browsern installieren zu können, musste diese ursprünglich offlinefähig sein. Diese Bedingung ist entfallen.
Progressive Web Apps [1] sind Webanwendungen, die auf dem Gerät des Anwenders installiert werden können. Voraussetzung dafür war in Google Chrome und Microsoft Edge lange Zeit, dass die Anwendung offlinefähig sein muss. Für die User Experience ist eine Bedienbarkeit auch dann wünschenswert, wenn der Anwender offline ist – zumindest im Rahmen der Möglichkeiten. Wer also den zusätzlichen Aufwand auf sich nahm, dies umzusetzen, wurde mit der Installierbarkeit der Anwendung belohnt.
Zur Implementierung der Offlinefähigkeit bei Webanwendungen kommen Service Worker [3] zum Einsatz. Dabei handelt es sich um ein durch die Website registriertes Stück JavaScript, das als Proxy zwischen Webanwendung und Netzwerk agiert und Zugriff auf einen clientseitigen, programmierbaren Cache besitzt. Speichert man die erforderlichen Quelldateien der Anwendung im Cache zwischen und liefert sie im Offline-Fall von dort aus, lässt sich die Anwendung auch ohne Internetverbindung betreiben.
Findige Webentwickler haben um diese Anforderung jedoch herummanövriert: Manche setzten einen leeren Service Worker ein, um die Bedingung zu erfüllen. Google zog daraufhin nach und erforderte einen fetch-Ereignishandler, sodass der Service Worker zumindest theoretisch in der Lage war, die Website offline verfügbar zu machen. Also setzten Seiten einfach diesen Ereignis-Handler ein und leiteten sämtliche Anfragen gegen das Netzwerk um. Folglich war das Ziel wieder nicht erreicht, und aufseiten des Browsers führte die zusätzliche Prüfung zu einem erheblichen Mehraufwand.
Mit Chromium 109 (mobil) und 110 (Desktop) wurden daher im Januar 2023 neue Offline-Fallbackansichten für installierte Webanwendungen [4] implementiert: Die Offlineerfahrung wird automatisch generiert, indem das Icon der Anwendung und der Hinweis "You're offline" angezeigt wird.
Die Notwendigkeit eines Service Worker und damit der Offlinefähigkeit ist seitdem komplett entfallen. Damit nähern sich Chrome und Edge auch an Safari an: Denn die Installation von Websites ist auf dem iPhone seit den frühen Tagen möglich, ganz ohne Bedingungen. Im Fall von Chrome und Edge wird zunächst jedoch auch weiterhin ein Web Application Manifest gefordert sowie die Übertragung der Website über HTTPS (siehe Installationskriterien [5]).
Service Worker haben den Nachteil, dass sie in JavaScript geschrieben und erst hochgefahren werden müssen, um Websites auszuliefern oder Pushbenachrichtigungen entgegenzunehmen. Um dem entgegenzuwirken, wurde für die Beschleunigung von Netzwerkabfragen beim Service-Worker-Start Navigation Preloads [6] entwickelt, während es für Pushbenachrichtigungen einen alternativen Vorschlag gibt, Declarative Web Push [7]. Für Webentwickler ist das Verfassen von solchem Infrastrukturcode zudem recht ungewohnt.
Die Implementierung einer sinnvoll bedienbaren Offlinevariante bleibt jedoch ein zentraler Baustein einer guten User Experience. PWA-Entwickler sollten diese daher auch in Zukunft anbieten, um ihre Anwender glücklich zu machen.
URL dieses Artikels:
https://www.heise.de/-9356942
Links in diesem Artikel:
[1] https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps
[2] http://pwapraxis.liebel.io/
[3] https://www.heise.de/blog/Progressive-Web-Apps-Teil-2-Die-Macht-des-Service-Workers-3740464.html
[4] https://developer.chrome.com/blog/default-offline/
[5] https://web.dev/articles/install-criteria
[6] https://web.dev/blog/navigation-preload
[7] https://github.com/w3c/push-api/issues/360
[8] mailto:rme@ix.de
Copyright © 2023 Heise Medien
Für Apple so wichtig, dass es sogar in den Top-Neuerungen von macOS Sonoma erscheint: Die Installation von Webanwendungen aus Safari heraus.
(Bild: Apple)
Was auf dem iPhone seit der ersten Version funktioniert, geht nun endlich auch mit Safari unter macOS: Webanwendungen lassen sich auf dem Gerät installieren.
Mit der Veröffentlichung von Safari 17 [1] und macOS Sonoma sind Progressive Web Apps [2] nun auch unter Verwendung des Apple-Browsers unter macOS installierbar. Dies war unter macOS mit Chromium-basierten Browsern wie Google Chrome und Microsoft Edge schon seit einigen Jahren [3] möglich, mit Safari auf dem iPhone bereits seit Januar 2008, als iPhone OS 1.1.3 veröffentlicht wurde.
Bei der Installation wird eine Verknüpfung zur Website auf dem Dock (auf Mobilgeräten auf dem Home-Bildschirm) hinterlegt. Webentwickler können das Icon und den Namen der Verknüpfung vordefinieren und dabei auch festlegen, dass die von der Verknüpfung geöffnete Website im Standalone-Modus ausgeführt wird, also in einem eigenständigen Fenster (auf Mobilgeräten vollflächig, also ohne Browser-Steuerelemente). Dies wird über das Web Application Manifest [4] definiert. Ist kein Manifest vorhanden, werden Titel und Icon aus anderen Quellen bezogen.
Die Installation erfolgt analog zu iOS und iPadOS aus dem Teilen-Menü heraus, das sich neben der Adresszeile befindet. Darin muss der Eintrag "Add to Dock" ausgewählt werden. Als Beispiel soll hier die Produktivitäts-PWA [5] paint.js.org [6] dienen.
Die Installation müssen Anwender in einem separaten Dialog bestätigen. Safari erlaubt dabei das Ändern der Bezeichnung. Wer davon Gebrauch macht, kann mehr als eine Instanz der Anwendung auf dem Gerät installieren – etwa, um eine Anwendung mit unterschiedlichen Benutzerprofilen zu verwenden, denn Cookies werden zwischen den Instanzen nicht geteilt. Dies ist bei Chrome oder Edge in dieser Form so nicht möglich.
Beim Zustimmen zur Aufforderung wird die Verknüpfung dem Dock hinzugefügt und dort zugleich angeheftet. Außerdem erscheint die Anwendung auch im Launchpad und ist im Applications-Ordner des Benutzerverzeichnisses zu finden. Von dort kann die Webanwendung auch wieder gelöscht werden [7]. Von der Verknüpfung aus gestartet, erscheint die Webanwendung dann wie plattformspezifische Apps in einem eigenen Fenster.
Damit sind Webanwendungen nun unter Safari auf sämtlichen Plattformen offline-fähig, installierbar und können Pushbenachrichtigungen entgegennehmen: Installierte Anwendungen können wie auch unter iOS und iPadOS Pushbenachrichtigungen empfangen und Badges auf dem Anwendungs-Icon anzeigen [8]. Als einziger der großen Browser unterstützt Firefox keine Installation von Webanwendungen auf dem Desktop.
Der nächste logische Schritt wäre nun die Bereitstellung der File System Access API [9] in Safari. Diese Webschnittstelle, die bereits seit 2019 mit Chromium-basierten Browsern ausgeliefert wird, erlaubt die Bearbeitung von Dateien aus dem lokalen Dateisystem. Über die Erweiterung File Handling API können sich installierte Webanwendungen sogar als Bearbeitungsprogramm für bestimmte Dateitypen hinterlegen. Dass das interessant sein könnte, merkten Apple-Vertreter auf der vergangenen Jahreskonferenz des W3C [10] bereits an.
URL dieses Artikels:
https://www.heise.de/-9356873
Links in diesem Artikel:
[1] https://webkit.org/blog/14445/webkit-features-in-safari-17-0/#:~:text=and%20error%20handling.-,Web%20apps%20on%20Mac,-Safari%2017.0%20for
[2] https://www.heise.de/blog/Progressive-Web-Apps-Teil-1-Das-Web-wird-nativ-er-3733624.html
[3] https://www.heise.de/blog/Chrome-76-PWA-Installation-wird-einfacher-4481046.html
[4] https://www.heise.de/blog/Progressive-Web-Apps-Teil-3-Wie-die-Web-App-zur-App-App-wird-3464603.html
[5] https://www.heise.de/blog/paint-js-org-MS-Paint-Remake-als-PWA-mit-Web-Components-und-modernen-Web-Capabilities-6058723.html
[6] http://paint.js.org/
[7] https://support.apple.com/en-us/104996
[8] https://www.heise.de/blog/Web-Push-und-Badging-in-iOS-16-4-Beta-1-Mega-Update-fuer-Progressive-Web-Apps-7518359.html
[9] https://www.heise.de/blog/Produktivitaets-PWAs-auf-Desktop-Niveau-dank-File-System-Access-und-File-Handling-API-4963752.html
[10] https://blog.tomayac.com/2023/09/25/w3c-tpac-2023-trip-report/#:~:text=Apple%20noted%20that%20a%20launch%20handling%20feature%20is%20something%20that%20they%20would%20probably%20need.
[11] mailto:rme@ix.de
Copyright © 2023 Heise Medien
(Bild: Login/ Shutterstock.com)
Das Ende ist nah: Bald wird KI die Softwareentwicklung übernehmen. Das ist übertrieben und zeigt, wie unklar ist, worum es Softwareentwicklung wirklich geht.
Zunächst: KI hilft beim Produzieren von Code. Das ist zweifellos ein signifikanter Fortschritt und wird vieles ändern. Jeder kann die zahlreichen Werkzeuge ausprobieren und sich davon selber überzeugen, wie mächtig diese Werkzeuge sind.
Aber auch wenn es zunächst paradox erscheint: Code zu produzieren, ist nicht das wesentliche Problem bei der Entwicklung von Software. Das wirkliche Problem ist, herauszufinden, welcher Code geschrieben werden muss. Dazu müssten die fachlichen Anforderungen bekannt sein. Anforderungen sind in der Praxis aber meist viel zu unklar, um daraus erfolgreich Software entwickeln zu können. Selbst wenn sie klar scheinen, stellt sich oft später im Prozess heraus, dass es doch Missverständnisse gab. So kommt der Interaktion mit Domänenfachkundige eine zentrale Rolle zu. Entwickler und Entwicklerinnen müssen so viel über die Domäne lernen, dass sie die passende Software für die fachlichen Fragestellungen entwickeln können.
Außerdem ändern sich die Anforderungen. Durch die Entwicklung der Software, den Einsatz der neuen Software und den damit zusammenhängenden Diskussionen reflektieren User und Domänenfachleute über die Nutzung der Software und kommen so zu neuen Anforderungen. Auch an diesem Prozesse müssen Developer teilnehmen, um zu verstehen, was zu entwickeln ist. Zudem können sie Feedback geben, falls Anforderungen besonders leicht oder schwierig umsetzbar sind - oder Änderungen an den Anforderungen die Umsetzung deutlich vereinfachen.
Bei den Anforderungen erkennt man schon die Bedeutung des Faktors Mensch. Er ist ebenfalls zentral: Softwareentwicklung findet immer im Team statt. So ein Team besteht üblicherweise aus mehreren Developern, aber auch andere Rollen wie UX-Experten, Architektinnen oder POs. Damit kommt der Kommunikation eine zentrale Rolle bei der Entwicklung zu: Aufgaben müssen verteilt und organisiert werden. Und die Organisation beeinflusst auch die Software: Das Gesetz von Conway besagt, dass die Architektur der Software den Kommunikationsbeziehungen des Teams entspricht. Wenn das soziale Gefüge so einen starken Einfluss auf die Entwicklung hat, dann sind in diesem Bereich auch die zentralen Herausforderungen. Und so haben die meisten Probleme in den Projekten auch ihre Ursache in der menschlichen Ebene. Hier kann KI nicht helfen.
Es wäre möglich, dass durch KI die Produktivität so sehr erhöht wird, dass eine Person statt eines Teams für ein Softwareprojekt ausreicht und so der Faktor Mensch weniger wichtig wird. Das erscheint unwahrscheinlich. Und die Interaktion mit Menschen zur Klärung von Anforderungen ist immer noch notwendig. Außerdem gab es auch schon vor den KI-Tools Fortschritte bei der Produktivität. Das hat aber nicht zu kleineren Teams geführt. Die Größe der Software-Teams steigt subjektiv eher, um noch kompliziertere Systeme zu realisieren und noch mehr Bereiche mit Software zu unterstützen. Wenn sich der Trend fortsetzt, werden wir mit KI ebenfalls noch komplexere Systeme bauen und nicht etwas kleinere Teams.
Das Produzieren von Code zu vereinfachen, ist auch nichts Neues. Im Gegenteil: Es gibt eine lange Historie von technischen Ansätzen, um Softwareentwicklung zu vereinfachen. Typischerweise heben diese Ansätze die Entwicklung auf eine neue Abstraktionsebene. Begonnen hat Softwareentwicklung damit, dass man Binärcode direkt in den Speicher der Computer geschrieben hat. Assembler hat dann Befehle definiert, die den Binärcodes entsprechen, aber einfacher zu merken und zu verstehen sind. So wurde vom Binärcode abstrahiert. Hochsprachen führen Konzepte ein, die von Assembler abstrahieren und mit denen Algorithmen und Logik noch einfacher ausdrückbar ist. Parallel sind Aufgaben in die Infrastruktur gewandert und wurden so für Entwicklungsteams: Betriebssysteme und Datenbanken bieten Lösungen für Persistenz, Speicher- und Prozessverwaltung. Libraries und Frameworks bieten auf Code-Ebene fertige Lösungen für typische Teilfunktionalitäten an. Und die Cloud [2]bietet eine Abstraktion über viele vorhandene Infrastrukturelemente wie Datenbanken oder Computer, sodass Infrastruktur für Projekte einfacher umgesetzt werden kann.
KI ist ein weiterer Schritt auf diesem Weg. Tatsächlich sind die Fortschritte so beeindruckend, dass man sicher von einer neuen Abstraktionsstufe sprechen muss. Es gibt prototypische Werkzeuge wie GPT Engineer [3], die eine ganze Anwendung anhand einer Spezifikation erstellen und dabei Rückfragen stellen, falls Anforderungen unklar sind (Video [4]). Nur wie zuvor erwähnt: Softwareentwicklung mit klaren Anforderungen ist nicht das Problem. Also wird der weniger problematische Teil der Softwareentwicklung durch KI vereinfacht und nicht der Kern.
KI führt sogar zu Gefahren: Eine Studie [5] hat das Verhalten von Entwicklerinnen und Entwicklern beim Schreiben von sicherheitsrelevantem Code ausgewertet und kommt zu dem Schluss, dass diejenigen mit KI-Unterstützung ihre Lösungen als sicherer einstufen als solche ohne. Nur ist in der Realität genau das Gegenteil der Fall: Ihr Code ist weniger sicher. Und das ist offensichtlich gefährlich: Es geht eben nicht darum, Code zu produzieren, sondern ein Problem soll gelöst werden. Und sicherheitsrelevante Software mit Sicherheitsprobleme schafft in Wirklichkeit neue Probleme. Gerade der Unterschied zwischen der subjektiven Bewertung und der objektiven Realität kann verheerend sein: Man glaubt, die Software sei sicher. Das stimmt aber nicht. Sicherheitslücken sind nur leider anders als fachliche Fehler oder Performance-Probleme nicht offensichtlich und so kann der Schaden ganz im Verborgenen entstehen. Solche Risiken zu managen und Lösungen zu entwerfen, welche die Qualitäten beispielsweise bei Sicherheit bieten, kann eine KI ebenfalls kaum lösen. Au!
Das nächste Problem: Es geht meist nicht um das Produzieren von Code, sondern um das Ändern. Das bedeutet auch, dass Entwicklerinnen und Entwickler vorhandenen Code lesen und verstehen müssen, um ihn sinnvoll zu ändern. Offensichtlich wird Code am Anfang einmal geschrieben, aber öfter geändert und damit auch gelesen. Dann ist das größere Optimierungspotential aber nicht beim einmaligen Produzieren, sondern beim Lesen, Verstehen und Ändern, das viel öfter stattfindet. Aber auch in diesem Bereich kann KI helfen: Tatsächlich kann man ChatGPT darum bitten, Code zu erklären. Dabei geht es eher um kleinere Codeschnipsel. Aber das Potenzial ist sicher groß: Gerade für Legacy-Code könnte eine speziell auf ein System trainierte KI ein interessantes Werkzeug sein, um das Verständnis des Systems zu verbessern und damit Änderungen zu vereinfachen.
Das Problem der Softwareentwicklung ist nicht, Code zu produzieren, sondern zu verstehen, was implementiert werden soll. Die Produktivitätsvorteile durch KI lösen dieses Problem nicht. KI wird Softwareentwicklung wesentlich ändern, aber nicht das Kernproblem lösen.
URL dieses Artikels:
https://www.heise.de/-9336902
Links in diesem Artikel:
[1] https://heise-academy.de/schulungen/githup?wt_mc=intern.academy.ix.ws_github.newsticker.link.link
[2] https://www.heise.de/blog/Die-Cloud-Eine-Komponentenbibliothek-3354034.html
[3] https://github.com/AntonOsika/gpt-engineer
[4] https://www.youtube.com/watch?v=FPZONhA0C60&t=440s
[5] https://arxiv.org/abs/2211.03622
[6] mailto:rme@ix.de
Copyright © 2023 Heise Medien
This release contains mostly some bug fixes for the recent 1.22.0.
This version 1.22.x is also the last to support PHP 7.2 before requiring PHP 7.4+.
A few highlights ✨:
This release has been made by several contributors: @Alkarex, @Frenzie, @MHketbi, @XtremeOwnageDotCom, @math-GH, @mossroy
Full changelog:
: in OIDC_SCOPES #5753, #5764TRUSTED_PROXY environment variable #5733RemoteIPInternalProxy in Apache #5740In this release, besides adding some initial support for OpenID Connect, the focus has been on increasing the quality rather than adding new features (which will have more focus again in the next release).
This version 1.22.x is also the last to support PHP 7.2 before requiring PHP 7.4+.
A few highlights ✨:
x86_64, not Alpine, and not ARM) through libapache2-mod-auth-openidc. See our documentationThis release has been made by several contributors: @Alkarex, @Alwaysin, @ColonelMoutarde, @Exerra, @FromTheMoon85, @LleanaRuv, @Marjani, @NaeiKinDus, @Rufubi, @V-E-O, @aaronschif, @acbgbca, @aledeg, @andris155, @becdetat, @belidzs, @kemayo, @kgraefe, @marienfressinaud, @math-GH, @msdlr, @obrenckle, @otaconix, @robertdahlem, @sad270, @samc1213, @squaregoldfish, @vrachnis, @witchcraze, @yubiuser, @zhaofengli
Full changelog:
x86_64, not Alpine) through libapache2-mod-auth-openidcset_time_limit() #5675CLEANCACHE_HOURS #5144<meta name="theme-color" .../> #5105a2enmod #5464DATA_PATH to cron env #5531error_reporting for PHP 8.1+ #5199DATA_PATH environment variable) #5423lib_opml #5188lib/http-conditional #5277ConfigurationSetter #5251, #5580./data.back/ in .gitignore #5359