Rubys FastGettext ist tatsächlich schnell
Thursday, 19. December 2019
Ich war mal wieder am Performance-Debuggen von pc-kombo. Die Seite soll schneller laden, wenn der Cache noch nicht befüllt ist, was doch immer wieder Besucher trifft. Dabei stolperte ich über diesen Abschnitt des Flamegraphs:
tt
ist der Übersetzungshelfer, lru-redux der genutzte Cache, Grundlage das Gem i18n. Und dieser Abschnitt machte einen gewichtigen Teil des Seitenladevorgangs aus.
Also habe ich das alte Übersetzungssystem auf FastGettext umgestellt. Der Code in Sinatra sieht in etwa so aus:
helpers do include FastGettext::Translation def t(token, opts = {}) _(token.to_s) % opts end end configure do FastGettext.add_text_domain('pckombo', path: 'locales', type: :yaml) end before do FastGettext.text_domain = 'pckombo' if request.env['HTTP_ACCEPT_LANGUAGE'] languages = HTTP::Accept::Languages.parse(request.env['HTTP_ACCEPT_LANGUAGE']) languages.each do |language| case language.locale when /en[_]*/ FastGettext.locale = "us" break when /de[_]*/ FastGettext.locale = "de" break when /fr[_]*/ FastGettext.locale = "fr" break when /es[_]*/ FastGettext.locale = "es" break end end end end
Die alten yaml-Übersetzungen konnten weiterverwendet werden. So beginnt z.B. die locales/de.yml:
de: cpu: Prozessor
Es ist also fast eine einfach so einsetzbare Alternative mit minimalen Codeänderungen.
Das Ergebnis:
Die Übersetzungen beim ersten Laden brauchen nun einen Bruchteil der Zeit. Das beste daran: Das wird nicht nur den speziellen Seitenaufruf beschleunigen den ich da betrachtet hatte, sondern generell der gesamten Webseite helfen.
Wer Übersetzungen in Ruby umsetzen muss, für den ist FastGettext ist definitiv einen Blick wert.
Categories setzen mit Rubys RSS-Modul
Wednesday, 18. December 2019
Ruby kann ja RSS lesen und schreiben, aber die Dokumentation für das Modul ist ungenügend und es scheint generell wenig genutzt zu werden, sodass man auch wenig Hilfe findet. Ich stand jetzt vor einem Rätsel: Wie kann ich den Items in einem erstellten RSS-Feed Kategories hinzufügen, also category
setzen? Doch jetzt habe ich es gelöst. Und zwar geht das so:
rss = RSS::Maker.make("rss2.0") do |maker| … maker.items.new_item do |newItem| … categories = [{name: 'abc', scheme: 'https://www.example.com'}] categories.each do |category| target = newItem.categories.new_category target.content = category[:name] target.domain = category[:scheme] end end
Xapian/Omega in Ruby/Sinatra integrieren
Tuesday, 10. December 2019
Wie baut man am besten eine Suchmaschine für eine einzelne Webseite? In meinem Fall war das Szenario so: Ich habe eine Sammlung statischer HTML-Dokumente, will aber eine Suchfunktion anbieten. Also brauchte ich etwas, was die ganzen HTML-Dokumente indexiert und dann durchsuchen kann. Genau das kann Xapian. Speziell für Webseiten gibt es vom Xapian-Projekt die vorgefertigte Omega-Suchmachine.
Also, Xapian kann alles mögliche durchsuchen, man könnte dem Xapian-Index auch programmatisch Elemente der Datenbank hinzufügen. Und es muss nicht für eine Webseite sein, es kann auch sonstwo eingebunden werden – mancher mag sich an xapian als nervenden Prozess in Ubuntu erinnern. Ich aber wollte nur HTML-Seiten durchsuchbar machen und das online anbieten, und genau dafür ist Omega gedacht. Allerdings: Omega hat ein eigenes Webfrontend, das per CGI eingebunden wird. Das wollte ich nicht nutzen, denn ich habe sowieso schon ein zusätzliches dynamisches Backend laufen, und die Template-Funktion von Omega sah unschön und kompliziert aus.
Xapian und Xapian-Fu installieren
Xapian samt Omega sollte in den Quellen sein. Bei mir mit void:
sudo xbps-install xapian-omega
Dazu empfehle ich für die Sinatra-Integration das Gem xapian-fu. Also in die Gemfile:
gem 'xapian-fu'
und dann installieren mit bundle install
.
Allerdings reichte das nicht. Xapian-fu braucht die Ruby-bindings von xapian, und die waren bei mir nicht in den Quellen enthalten. Also muss in dem Fall noch das Archiv xapian-bindings heruntergeladen und die Ruby-Bindings kompiliert werden:
unp xapian-bindings-* cd xapian-bindings-VERSION ./configure --with-ruby cd ruby make sudo make install
Mit omindex indexieren
Omindex installierte sich in den PATH und ist einfach bedienbar. Meine HTML-Dateien liegen im Ordner public/, Bilder sollten ignoriert werden, dafür kam ich auf diesen Befehl:
omindex --db omega/data/default/ --filter image/*:skip public/
Der Code in Sinatra
Statt jetzt den CGI-Part von Omega zu nutzen übernimmt Sinatra mit Xapian-Fu die Suche:
require 'sinatra' require 'xapian-fu' include XapianFu get '/search' do searchterm = params['searchterm'] db = XapianDb.new(:dir => 'omega/data/default/', :create => false) results = db.search(searchterm).map{|match| {url: match.data.split("\n").detect{|x| x.start_with?('url=')}.to_s.sub('url=', ''), caption: match.data.split("\n").detect{|x| x.start_with?('caption=')}.to_s.sub('caption=', '')} } erb :search, locals: {searchresults: results, searchterm: searchterm} end
Man sieht: Der Code nimmt die Datenbank als Quelle, die vorher omindex angelegt hat.
Die Zuweisung in den results-Hash ist hässlich. Ich fand leider keinen Weg, mit xapian-fu die Suchergebnisse richtig strukturiert auszulesen. Nur match.data
ist zugänglich, womit man etwas anfangen kann. Der Weg über einen XapianDocValueAccessor, mit dem man wohl die Felder gezielt auslesen können sollte, funktionierte bei mir nicht. Eventuell codiert omindex den Suchindex zu speziell.
Die Suchergebnisse gehen dann an ein ERB-Template:
<h1>Search results for <%= h searchterm %></h1> <% if searchresults.size > 0 %> <ol id="searchresults"> <% searchresults.select{|item| ! item[:caption].empty? }.each do |result| %> <li> <a href="<%= result[:url] %>"> <span><%= result[:caption] %></span> </a> </li> <% end %> </ol>
Xapian/Omega ist keine Lösung, wenn die Webseite nur aus statischen HTML-Seiten bestehen darf. Aber es ist wohl eine gute Lösung wenn es einen echten Server gibt. Die Integration in Ruby/Sinatra ist relativ einfach.
Dass die xapian-bindings nicht einfach per gem installierbar sind ist der problematischste Punkt, auch das vorgelagerte indexieren wird nicht in jedes Projekt gut passen. Ohne statischen Webseitengenerator im Zentrum würde ich omega und omindex ignorieren und stattdessen nur mit xapian-fu arbeiten. Dann kämen die Daten eben direkt aus der Datenbank.
Hier aber war das Parsen der HTML-Seiten die perfekte Lösung.
Robocop (2014)
Monday, 9. December 2019
Die Geschichte des Remakes ähnelt sehr der Geschichte der Vorlage, soweit ich mich an sie erinnere. Ein guter Polizist wird schwer verletzt. Anstatt ihn sterben zu lassen wird er in einen Robocop verwandelt, noch ein Cyborg, aber einem Großteil seiner Menschlichkeit beraubt. Was natürlich keine gute Sache ist und entsprechend schiefgeht - wobei hier mit weniger direktem Kampf um Kontrolle über ihn als vielmehr Robocop als Mittel zum Zweck.
Da gibt es dann wenige Überraschungen. Aber dafür ordentliche Actionszenen, eine geradlinige Story, keine schlechten Schauspieler. Mir gefiel, wie offensichtlich die Parallele zwischen dem Bestreben nach Robotern als Sicherheitskräfte und der schon bestehenden Praxis des Mordens per Roboter gezogen wird, zu Fox News als Propagandamaschine und dem US-Nationalismus als Faschismus.
An ein paar Stellen stolpert die Story, z.B. wenn der eigentlich als positive Figur positionierte Doktor ohne besonderen Zwang seine Prinzipien verrät und Robocop manipuliert. Wie der dann dieser Manipulation auf einmal entgehen kann, wunderbarerweise. Und wie der Oberbösewicht am Ende sich bewusst blöd verhält. Eben alles ein bisschen sehr einfach.
Fraglich auch was das Remake über das Original hinaus liefert. Und das war ja wohl schon kein besonders guter Film. Aber ich erwartete einen sehr schlechten Film, und so schlecht war das gar nicht. Eher ein kompetenter Actionfilm ohne besondere Größe mit einer mittlerweile nicht mehr originellen Story.
Arrival
Saturday, 30. November 2019
Story of Your Life von Ted Chiang habe ich tatsächlich gelesen, bevor der darauf basierende Film herauskam. Immerhin, sie blieb im Gedächtnis. Aber insgesamt habe ich die kurze Geschichte nicht übermäßig gemocht und daher auch bisher den Film gemieden.
Es gibt ja verschiedene Arten von Science-Fiction. Die Skala reicht in etwa von leicht futuristisch angehauchter Fantasy bis hin zu hochintellektuellen Zukunftsvisionen. Chiangs Geschichte war eher letzteres, sogar mehr nur eine Gedankenübung mühsam ausgebaut zu einer Geschichte – wobei ich es lieber mag, wenn die Geschichte im Vordergrund steht und der intellektuelle Hintergrund eben im Hintergrund bleibt (also Star Trek, Interstellar, Blade Runner). Keine gute Voraussetzung für den Film, nicht nur um mir zu gefallen, sondern wie will man so etwas verfilmen?
Das gelingt Arrival überraschend gut. Um den losen Rahmen der Buchhandlung herum wird die Geschichte aufgefüllt. Das Verhalten der Menschen um die Forscher herum, der Nationen, auch der Aliens rückt mehr in den Fokus. Und was im Buch nur angedeutet wurde wird im Film einfach gezeigt. Erklärungsmodelle werden auch gegeben. Das ist dann zwar nicht mehr ganz wie in der Vorlage, aber die Grundidee kommt sehr wohl rüber. Ebenso wie die enthaltene Traurigkeit; besonders durch Amy Adams, die ausspielt was vorher nur skizzierte Pointe war.
Trotzdem finde ich die Grundlage des Filmes weiterhin nicht stark, das macht das ganze Drumrum dann doch nicht ganz wett.
Jack Reacher
Friday, 29. November 2019
Ein Flohmarktkauf! Jack Reacher ist ein Actionfilm mit Tom Cruise und leider kein Edge of Tomorrow, sondern ziemlich mittelmäßig. Ein Scharfschütze hat mehrere Menschen erschossen und sagt gegenüber der Polizei nur eines: Holt Jack Reacher. Der taucht dann tatsächlich auf, zusammen mit der Anwältin gilt es ein Mysterium aufzuklären und die typischen Stunts aufzuführen.
Wobei die Actionszenen irritierend sind. Mehr noch als in den Mission Impossibles funktionieren sie oft genug logisch nicht, ist ihre Konstruktion seltsam. Aber leider ist Jack wie Ethan Hunt ein typischer Tom Cruise Charakter, also eindimensional und omnipotent. Hmpf.
Klar kann man das schauen, aber man kann es auch bleiben lassen.
Begley: Memories of a Marriage
Wednesday, 27. November 2019
Zwei Menschen am Lebensabend: Der Erzähler und Lucy. Beide sind verwitwet und begegnen sich zufällig wieder. Lucys Zustand überrascht ihn, auch ihr Hass auf den verstorbenen Thomas Snow, von dem er nur positive Erinnerungen hat. Was ist in dieser Ehe passiert, ist ihre Einschätzung fair? Ähnlich einem Biographen recherchiert der Erzähler dieser Sache nach, lässt sich erzählen und stöbert in eigenen Erinnerungen.
Gleichzeitig hat ja auch er seine Frau verloren und muss sein Leben weiterleben. Also eine ähnliche Ausgangssituation wie in Schmidt, auch ein ähnliches Milieu, wenn auch die Erzählebene oft weiter in der Vergangenheit liegt. Und doch ist es eine andere Art Geschichte. Wiederkehrend sind zwar die Themen Treue und Affären, psychische Krankheiten und Verlust. Doch mit einem Schriftsteller als Protagonisten und den Beschreibungen seiner Arbeit begleitet man nicht so sehr einem alten Mann und seinen Eskapaden, sondern taucht in diese Ehe hinab. Ein Urteil zu fällen, darauf soll es wohl hinauslaufen.
Elegant und gelungen.
Zukunftspläne für pc-kombo: 4 Aufgaben, 3 Seiten, mehr FOSS
Thursday, 7. November 2019
Damit der Hardwareempfehler seine PC-Builds zusammenstellen kann muss pc-kombo vier Aufgaben auf einmal erledigen:
- Er muss sich eine Liste aller möglichen Komponenten zusammenstellen.
- Dann muss er herausfinden, was wieviel kostet.
- Um dann aus diesen Komponenten zu wählen zu können muss er wissen, welche Hardware wie schnell ist.
- Schließlich kann er zusammenpassende Builds zusammenstellen, also per Algorithmus optimieren und dabei bedenken, welche Hardware zusammenpasst (welche Prozessor in welches Motherboard, welche Grafikkarte in welches Gehäuse, welches Netzteil stark genug ist etc).
Ich sitze derzeit daran, das weiter aufzusplitten. Natürlich ist es jetzt schon in einer gewissen Weise aufeteilt: Die Webanwendung holt ja nicht bei jeder Anfrage alle Komponenten aus Crawlern und die Preise von den APIs, sondern erledigt vieles vorher im Hintergrund (die Preiserfassung gar per Micoservice). Aber letzten Endes ist es doch eine Seite, eine Interface, ineinander greifende Arbeitsschritte. Stattdessen möchte ich am Ende drei spezialisierte Seiten haben – eine namensgemäße Kombination von Anwendungen erschaffen.
Eine PC-Hardwaredatenbank
Sie soll alle Prozessoren, alle Grafikkarten, alle Motherboards usw umfassen, samt ihren Spezifikationen, Reviews und was sonst noch anfällt. Der Clou: Das soll offen werden. AGPL-lizenzierter Code, API-Zugriff auf die Datensammlung. Denn als ich pc-kombo startete war das Sammeln der Hardware eine unvermutete Mammutaufgabe, wofür es keinen guten Grund gibt. Das sind keine Geschäftsgeheimnisse, keine geheimhaltungswürdige Informationen. Und doch gibt es da eine kleine Industrie drumrum, die solche Daten sammelt und zu Mondpreisen verkauft.
Mit dieser Datensammlung und der API wäre nicht nur pc-kombo gedient, sondern viele andere Projekte könnten davon profitieren. Für pc-kombo und mich wäre es aber besonders praktisch: Ein zentraler Ort für die Hardwaredatensammlung. Wo ich nochmal Zeit und Arbeit darein investieren kann, die Datensammlung besser und einfacher zu gestalten. Gleichzeitig immer im Blick halten kann, auf jeden Fall auch das zu sammeln war das Empfehlungssystem mindestens braucht.
Für die Einzelansicht einer Grafikkarte habe ich bereits einen Entwurf:
Nebenbei: Statische Seiten zu generieren entstammt als Ansatzpunkt natürlich dieser Projektidee.
Falls jemand als Mitentwickler einsteigen will, gerne! Einfach in Kontakt treten. Softwaretechnisch wird das ein statischer Seitengenerator in Ruby; Das, sowie HTML, CSS und vielleicht Javascript muss geschrieben werden, und mit dem angedachten Backend und der Datensammlung gibt es nochmal eine ganz andere Aufgabe zu bewältigen.
Eine Metabenchmarkseite
Der Metabenchmark verdient mehr Aufmerksamkeit. So oft wollen Leute wissen, wie gut Prozessoren und Grafikkarten im Vergleich mit anderen sind, welche Spiele und Anwendungen sie wie gut bewältigen. Und viel zu oft schauen sie dabei auf die falschen Daten: Künstliche Vergleiche von Spezifikationen oder Ergebnisse artifizieller Benchmarks, die über die Praxis fast nichts aussagen. Echte Benchmarks der Zielanwendungen sind der viel bessere Weg, Prozessen und Grafikkarten zu vergleichen.
Gleichzeitig ist das nicht einfach. Verschiedene Benchmarks mit teils disjunkten Teilnehmerlisten vergleichbar zu machen ist komplizierter, als ich anfangs dachte. Doch mittlerweile meine ich, das Problem algorithmisch so gut gelöst zu haben wie möglich. Wenn es mal offensichtlich falsche Ergebnisse gibt, dann liegt das mittlerweile immer an fehlenden Daten. Was sehr selten geworden ist.
Und doch beobachte ich für den Benchmark wenig Popularität, außer ich stoße Leute drauf. Deswegen soll der Metabenchmark seine eigene Seite bekommen, mit einer besseren Oberfläche, und so besser sichtbar werden. Und ebenfalls eine API bekommen, sodass andere Projekte ihn benutzen können. Wobei er selbst seine Prozessoren und Grafikkarten aus der API der Hardwaredatenbank ziehen würde.
Und wie gehabt: Ein PC-Builder
An pc-kombo würde sich laut diesem Plan erstmal gar nicht viel ändern. Die Daten der anderen Seiten benutzt er ja jetzt schon und bräuchte sie auch weiterhin. Aber mit einem kleineren Kern, besserer Automatisierung und reduzierten Ansprüchen an die Datenbank kann ich vielleicht ein paar der Verbesserungen umsetzen, zu denen ich bisher nicht kam.
Im Grunde will ich nehmen, was pc-kombo sowieso schon macht, es besser kapseln, automatisieren und zugänglich machen. Dabei mir und anderen helfen, daher sind die APIs geplant und eine freie Lizenz für die Datenbank. Es muss sich natürlich erst noch zeigen, ob ich das wirklich gebaut kriege und dann auch so wird, wie ich mir das derzeit vorstelle.
이날치 - 범 내려온다
Wednesday, 6. November 2019
Youtube empfiehlt mir gerade seltsame abgefahrene Musikvideos. Der Titel heißt wohl sowas wie "Tiger is coming", was ein paar der Gesten und Kostüme erklärt.
(Und ich wollte sehen ob Serendipity den Titel darstellen kann. Mit Sqlite scheint das problemlos zu gehen. UTF-8 FTW!)
Gegen die Nazis
Wednesday, 6. November 2019
Diese Art von beschämender und widerwärtiger Geschichtsklitterung zeigt, wes Geistes Kind dieser Björn Höcke ist. Höcke ist für mich ein Nazi und die AfD mit ihm auf dem Weg zur NPD 2.0.
…
Dass die AfD am Rand der Verfassungsordnung steht, wird ebenso durch ihre grenzüberschreitende Schmähkritik am Parlamentarismus und den Institutionen unseres Staates deutlich. Wenn im Grundsatzprogramm der AfD von einem "politischen Kartell" gesprochen und damit das Bild einer korrumpierten politischen Clique entworfen wird, delegitimiert die AfD unseren Staat und das parlamentarische System. Das ist weder bürgerlich noch konservativ. Das ist eine staatsfeindliche Politik.
Alternativer Startpunkt: Generator statischer Seiten
Tuesday, 5. November 2019
Ich versuche diesmal etwas anderes. Normalerweise baue ich Webanwendungen mit Ruby um Sinatra herum, zum Beispiel die Blogsoftware ursprung. Auch der PC-Hardwareempfehler pc-kombo ist im Grunde so eine Ruby/Sinatra-Anwendung. Aber man will ja nicht immer das gleiche machen, sondern dazulernen und neue Lösungen ausprobieren. Bei Pipes z.B. war das der grafische Editor. Gerade versuche ich mich daher an einem statischen Seitengenerator als technischen Kern eines neuen Projekts.
Worum geht es dabei? Performance und Architektur. Zum einen verspreche ich mir eine schnellere Seite, wenn ihr Kern statisches HTML ist und nur von nginx ausgeliefert wird, ohne Datenbankabfrage oder Kontakt mit Ruby. Zum anderen will ich auch sehen, wie anders die Daten strukturiert werden können und wie viel kleiner der Code wird, wenn der Fokus mehr auf das generierte HTML und CSS und eventuell Javascript liegt und beim Seitenaufruf nicht direkt auf die Datenbank zugegriffen werden muss.
Bisher setzte ich sehr auf Konfiguration. So gibt es einen Ordner pages/ mit JSON-Dateien, die bestimmen welche HTML-Seiten erstellt werden sollen. Als Beispiel die gpu.json:
{ "view": "gpus", "target": "gpus.html", "collection": "gpus" }
Die Felder hier bestimmen das Verhalten des Generators: view
welches Template verwendet wird, target
welche Datei erstellt werden soll, collection
welche Datenbankdaten dem Template mitgegeben werden sollen.
Dazu gehören noch zwei Templates: Zuerst die implizit aufgerufene layout.erb:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>generatortest</title> </head> <body> <%= yield %> </body> </html>
Und die gpus.erb:
<h2>Gpus</h2> All the gpus we know: <ol> <% collection.each do |item| %> <li><%= item[:name] %></li> <% end %> </ol>
All das beachtet die generator.rb:
require 'erb' require 'tilt' require 'json' require 'moneta' store = Moneta.new(:Memory) store[:gpus] = [{id: 1, ean: '123', name: 'WindForce RTX 2080'}, {id: 2, ean: '456', name: 'Sapphire RX 590'} ] # foreach page definition in pages, get the specified data collection, give it to the template and save the html at the target destination Dir.glob(File.expand_path('../pages/*.json', __FILE__)).each do |file| control = JSON.parse(File.new(file).read, symbolize_names: true) collection = store[control[:collection].to_sym] if control[:collection] view = File.join('../views/', control[:view] + '.erb') view = File.expand_path(view, __FILE__) if File.exists?(view) layoutpath = File.expand_path('../views/layout.erb', __FILE__) layout = Tilt::ERBTemplate.new(layoutpath) output = layout.render { # this construction ensures the layout is used template = Tilt::ERBTemplate.new(view) # the final render has nothing to evaluate but needs the # the local collection, thus the empty Object as param template.render(Object.new, collection: collection) } targetpath = File.join('../public/', control[:target]) targetpath = File.expand_path(targetpath, __FILE__) File.write(targetpath, output) end end
Man sieht: Das ist absolutes Anfangsstadium. Aber es funktioniert schonmal! Nach Aufruf des Generators landet fertiges HTML im Ordner public/. Was dann der wäre, den der Webserver ausliefern könnte, inklusive dieser gpus.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>generatortest</title> </head> <body> <h2>Gpus</h2> All the gpus we know: <ol> <li>WindForce RTX 2080</li> <li>Sapphire RX 590</li> </ol> </body> </html>
Überlegungen
Um zwei Entscheidungen habe ich mich gedrückt bzw sie ungewöhnlich flexibel gelassen. Mit Moneta vermeide ich die Entscheidung für eine Datenbank. Normalerweise wäre das sqlite, aber ich bin noch nicht sicher ob das hier wirklich passt oder ob es mehrere Prozesse geben wird. Deswegen landen die Datenbanktestdaten bisher auch nur im Arbeitsspeicher. Und tilt würde es später einfach machen, statt erb eine andere Templatesprache zu benutzen.
Bedenken habe ich noch wegen der Filter. Ich weiß, dass ich später Nutzer Listen – wie die im Beispiel erstellte – filtern lassen will. Soll das komplett per Javascript geschehen? Oder baue ich dafür Seiten ein, die mit Ajax auf die angepassten Datenbanksets zugreifen? Dass es einen dynamischen Teil der Anwendung geben wird ist immerhin bereits vorgesehen, als Backend für den Administrator.
Ob der Seitengenerator nicht ein Monster werden wird? Ich werde versuchen müssen ihn schlank zu halten. Andererseits sehe ich gerade nicht, dass ihm noch viel fehlen würde, um die Seite umzusetzen die ich bauen will.
Erstes Fazit
Das könnte funktionieren. Wie schlüssig sich das Konzept anfühlt und wie schnell dieser Prototyp zu bauen war erklärt mir etwas, warum die letzten Jahre diese static site generators so beliebt wurden. Es ist eben nicht nur etwas für Blogs oder eine Homepage. Die HTML-Erstellung nicht erst beim Seitenaufruf zu machen ist auch generell ein gutes Prinzip.
Aber es wird sich zeigen, ob mit diesem Weg dann auch wirklich eine performante und wartbare Webanwendung entsteht.
Großartig: Die neue Steam-Library
Thursday, 31. October 2019
Meine Spielesammlung ist ganz schön groß geworden! Und nicht nur mir geht es so, verglichen mit vielen anderen Sammlungen sind meine 314 Steamspiele sogar eine richtig kleine Sammlung. Was sicher vor allem daran liegt, dass ich nur relativ selten Geld in die Hand nehme um Spiele zu kaufen. Steam reagierte auf diese großen Sammlungen jetzt und hat eine neue Libraryansicht veröffentlicht (via).
Und die ist wirklich toll geworden, denn sie erfüllt zwei erklärte Grundziele:
- Die Spiele in der Sammlung sehen jetzt besser aus. Valve verweist selbst darauf, dass Spielesammlungen in Regalen Vorbild waren. Dementsprechend sind die Spiele mit ihrem Cover gelistet und sehen einfach gut aus. Ein bisschen so, wie GOG das schon länger macht.
- Man kann die Spiele filtern und eigenen Kategorien zuweisen, eigene Regale erschaffen. Offensichtlich dabei: Favoriten. Weniger offensichtlich: Dynamische Filter! Zum Beispiel kann eine Auswahl alle Actionspiele umfassen, oder auch alle Actionspiele mit dem Tag Puzzle. Und trotz der dynamischen Auswahl kann man dann noch nachbessern, wenn zum Beispiel wie bei mir die ursprüngliche Version von Deus Ex: Human Revolution sowie Wasteland 2 nicht als RPG erkannt werden.
Auch die Einzelspielansicht wurde überarbeitet, die empfinde ich als weniger gelungen. Viel Platz geht für Aktivitäten von Entwicklern und der Community (Workshop etc) drauf, was bei vielen Spielen einfach leer ist. Immerhin sieht die Ansicht bei Spielen mit aktiver Community (wie bei Cities: Skylines) oder eigener Spielhistorie besser aus.
Was ich mir noch wünschen würde: Eine direkte Anzeige der protondb-Bewertung. Aber auch ohne diese Funktion ist die neue Libraryansicht echt nett geworden. Ein guter Anlass, einen Blick darauf zu richten was man schon alles in der eigenen Spielesammlung besitzt.
Rezo zu Seehofer
Friday, 25. October 2019
Wer meinen Kommentar zu Seehofers Spielerhetze minus des haarigen Anfangsvergleichs zur Kolumne ausgebaut lesen will, kann das jetzt auf Zeit.de tun. Wie bitte, ob das Neid sei? Aber nicht doch.
Tatsächlich freue ich mich, dass mit Rezo jemand in die Massenmedien kommt, der bisher so viel meiner politische Denke geteilt und einen ähnlichen Hintergrund hat und noch dazu sie massenkompatibel zu vertreten versteht. Klar, die Positionen werden nicht überall übereinstimmen, wer vernünftig und lautstark ist teilt z.B. zumindest öffentlich nur selten meine Haltung gegen Diskriminierung. Aber das kann ich später bewerten, wenn es soweit kommt. Jetzt erstmal wichtiger: Der Zeit gratuliere ich zu dem Coup, Rezo zu gewinnen.
GNOME zieht gegen den Patenttroll und sammelt Spenden
Tuesday, 22. October 2019
Letzten Monat wurde die GNOME Foundation von einem Patenttroll verklagt, der via eines offensichtlich invaliden Patents Geld für Shotwell verlangte, GNOMEs Bildverwaltungsprogramm. Wahrscheinlich kein geschickter Schachzug. Und tatsächlich wehrt sich GNOME: Die Forderungen werden verneint, das Vergleichsangebot zurückgewiesen, das Patent angegriffen.
Sie schreiben es auch in der Ankündigung, aber es ist gleichzeitig der richtige und der harte Weg. Es ist kurzfristig riskanter und teurer, als sich erpressen zu lassen. Aber es sendet ein Signal an andere Patenttrolle, sogar über GNOME hinaus, das freie Software kein geeignetes Angriffsziel ist. Zu kämpfen schützt auch ganz konkret andere Projekte vor diesem Angreifer, indem seine Ressourcen gebunden werden, das Patent möglicherweise invalidiert wird. In früheren Fällen sind Betreiber solcher Patenttrolle auch schon ins Gefängnis gewandert.
Eine gute Aktion von GNOME also, völlig egal wie man zur Desktopumgebung selbst steht. Sie sammeln hier Spenden, um die Kosten tragen zu können. Ich habe mich daran gerade beteiligt. Jeder, der mit freier Software zu tun hat, sollte das wenn möglich ebenfalls machen. Und sei es nur aus Eigeninteresse.
Warum Smartwatches mit Wear OS so unangenehm zu bedienen sind
Wednesday, 16. October 2019
Weil das System zu oft zurückspringt, dabei nicht konsistent ist und dem Nutzer nicht genug Steuerungsmöglichkeiten gibt. In Usability-Sprech: Das Prinzip der Steuerbarkeit und der Erwartungskonformität ist verletzt, so stark, dass die Aufgabenangemessenheit gefährdet ist. Ein Nachtrag mit Beispielvideos zu meiner Besprechung vom letzten Jahr.
Smartwatches zeigen die Uhrzeit, können aber noch viel mehr. Dafür startet man zumindest bei Google auch mit ihnen Apps, wie bei Telefonen. Aber bei den Uhren wird nach wenigen Sekunden der Bildschirm wieder dunkler. Und dann können zwei verschiedene Dinge passieren:
1. Manche Apps schalten in einen Ambiance-Modus. Sie werde farblos, um die Batterie zu schonen, aber sie bleiben aktiv:
2. Andere unterstützen diesen Modus nicht. Sie schließen sich ganz, es geht zurück zum Startbildschirm. Das ist ungeheuer nervig.
Vor allem, weil die große Frage dann ist: Wie kommt der Nutzer wieder zu der App zurück, die er eben noch nutzen wollte? Antwort: Er weiß es nicht.
Manchmal reicht es, den Bildschirm der Uhr wieder zu berühren. Dann wird er wieder hell und die App erscheint:
Aber das funktioniert nicht immer. Oft genug – je nach Speicherverwaltung? Wartezeit? – bleibt WearOS dann bei der Uhrzeitanzeige stehen:
Das passiert auch dann, wenn der Nutzer per Knopfdruck zur Uhrzeitanzeige gewechselt ist. Kein Berühren des Bildschirms und keiner der beiden Knöpfe führt dann zur vorher geöffneten App zurück:
Was man hier auch schön sieht: Wie viele meiner Wischgesten ignoriert werden. Auch das macht die Benutzung der Uhr frustrierend.
Die Bedienung der Uhr leidet schon unter anderen Erschwernissen. Die Oberfläche stockt gerne mal, der Bildschirm ist klein, damit auch die Bedienfläche. Das ist aber nicht das Hauptproblem: Es macht es nur noch unangenehmer, immer wieder in das Menü gehen und Apps neustarten zu müssen. Das eigentliche Problem ist die fehlende Task/App/Fensterverwaltung im Bedienkonzept. Das erinnert mich ein bisschen an die Anfangszeit von Android auf den Smartphones, als es ebenfalls genau in dieser Disziplin schwächelte und das später kopierte webOS zeigte, wie es richtig geht. Bei Smartwatches muss diese Inspiration wohl noch gefunden werden.