hubersn

Die zunehmende Entmündigung des Nutzers

 Rant  Kommentare deaktiviert für Die zunehmende Entmündigung des Nutzers
Apr 182018
 

Gerade hat sich mein Kindle eigenmächtig upgedated. Als ich ihn ein paar Minuten unbeaufsichtigt zwecks Lesepause, aber noch verbunden mit dem WLAN, liegen gelassen habe. Und es hat Minuten gedauert. Und er hat den alten Lesezustand leider vergessen. Ich hatte vor ein paar Tagen das Update noch explizit abgelehnt aufgrund von “never change a running system”.

Das ist eine zunehmende Unsitte von IT aller Art, gar nicht mehr auf die Zustimmung des Nutzers zu warten, ihn gar nicht mehr zu informieren was denn das Update so macht. Ihm die Entscheidung zu überlassen. Wäre auch nicht das erste Mal, dass Features von einer Version zur nächsten einfach Verschwinden. Zurück zu einer älteren Version kann man ja auch nur noch in den seltensten Fällen. Der Traum eines modularen Upgrademechanismuses, wo man “pick and mix” mit gewünschten und unerwünschten Updates machen kann, ist ja schon seit Jahrzehnten ausgeträumt. Langfristige Stabilität und Support etwas von gestern – Vorwärtsstrategie scheint das neue Zauberwort.

Irgendjemand wird jetzt sicher “Security” sagen. Ja, dann macht es doch einfach sicher. Ein stabiler Branch mit aktuellen Sicherheitspatches. Einen Development-Branch für die Mutigen. Das wäre das allermindeste, denn bei der üblichen Qualität heutiger Softwareentwicklung bedeutet ja jede Änderung ein neues Sicherheitsrisiko. Und bei einem komplett vernagelten System wie dem Kindle kann Security wohl kaum ein Argument sein, oder jemand hat wirklich Scheiße gebaut.

Ich hasse Intransparenz. Besonders, wenn es um meine eigenen Geräte geht. Macht im Web was ihr wollt. Aber nicht auf meinen Geräten.

Die zunehmende Nutzlosigkeit von Datenblättern

 Uncategorized  Kommentare deaktiviert für Die zunehmende Nutzlosigkeit von Datenblättern
Apr 082018
 

Wann immer ich ein Stück Technik kaufe, informiere ich mich vorher so gut es geht. Reviews bei Amazon, Testberichte, und natürlich die Hersteller-Website. Bei komplexeren Dingen hilft oft ein Blick ins Handbuch, das ja Gott sei Dank inzwischen fast immer zum Download verfügbar ist (und das auch sein muss, denn gedruckt beigelegt wird es heutzutage ja immer seltener – aber das ist eine andere Geschichte).

Seit Jahren beobachte ich dabei eine ständige Reduktion der Tiefe technischer Daten. Jahrelang habe ich z.B. bei DVD-Brennern den Strombedarf zu ermitteln versucht – meist stand nur “5V/12V” im “Datenblatt”. Sehr nützlich.

Ein besonders sparsames Beispiel ist mir gerade untergekommen: es geht um eine externe USB-Festplatte von Seagate. Was könnte es da an nützlichen Informationen geben, die man in ein Datenblatt schreiben könnte? 512 Bytes/Sektor vs. 4Kn? Strombedarf am USB, womöglich gar getrennt nach Anlaufstrom, Strombedarf im Betrieb und im Standby? rpm der verbauten Platte? Geräuschentwicklung? Ob es intern eine S-ATA-Platte ist und die USB-Schnittstelle mit SAT arbeitet? Format bei Auslieferung?

Man werfe einen Blick drauf und ergötze sich an zwei Druckseiten Nichtinformation.

Immerhin: wir wissen nun, dass in 320 bzw. 240 Hauptkartons pro Palette geliefert wird. Super!

Oracle und Java – hü, hott, oder was ganz anderes?

 Java  Kommentare deaktiviert für Oracle und Java – hü, hott, oder was ganz anderes?
Mrz 292018
 

Oracle hat die “Roadmap” für Java 11 verkündet (hier und hier). JavaFX fliegt aus Java SE raus. Das Java-Plugin und damit nicht nur das Applet, sondern auch Java Web Start (und damit ironischerweise das, was Oracle bei Abkündigung des Applets noch als Ersatzlösung propagiert hat, auch wenn jeder wusste, dass es nur eine Deployment-Lösung ist und keine Browserintegrationslösung), fliegen raus.

OK, kann man so machen. Es gibt sicher gute Gründe dafür (im Gegensatz zur Entscheidung “wir laden .properties-Dateien ab sofort immer UTF-8”, für die ich bis heute keine auch nur annähernd stichhaltige Begründung gefunden habe – auch warum JAXB nun plötzlich aus Java SE raus musste, man weiß es nicht). Aber es ist ein Rückwärtskompatibilitätsproblem. Und es ist Wasser auf die Mühlen der “Java auf dem Client ist tot”-Fraktion, obwohl es bis heute keine WORA-Alternative für grafische Oberflächen gibt. Und eine weitere Kehrtwende im scheinbar ewigen Auf und Ab, beginnend mit der Idee des AWT in Java 1.0.

Das hin- und her-Geeiere gab es ja auch schon beim Thema “Java-Datenbank” – irgendwann wurde recht überraschend die Apache Derby als “Java DB” ins JDK aufgenommen, dann hat man diese Version – mit Hinweis auf die angeblich gefährdete Rückwärtskompatibilität – nicht regelmäßig aktualisiert, um sie schließlich wieder komplett zu entfernen (Java 9).

Auch die JavaFX-Geschichte ist ja eher wechselvoll. Zuerst der Flash-/ActionScript-/Silverlight-/Flex-Konkurrent mit dieser merkwürdigen Skriptsprache, dann JavaFX 2 mit der (durchaus vernünftigen) Idee der Ablösetechnologie für Swing, ohne aber die Grundlagen einer modernen UI gleich mitzuliefern (Accessibility, Comboboxen…dafür waren Charts dabei…). Dann die Integration ins JRE und die Bestrebung, JavaFX auch auf Android und iOS zu bringen. Reichlich Manpower und – für Java-Verhältnisse – zügiges Bugfixing. Dann Abbau der Manpower, Absage an die Mobilstrategie, nun Rauswurf aus Java SE und Übergabe an (oder vielmehr Hoffnung auf Übernahme durch) die Community.

Nun ist es ja durchaus diskussionswürdig, was in den “Standardlieferumfang” gehören soll und was nicht. Und durch Project Jigsaw hatte man nun ja eigentlich die Möglichkeit, die “modular JRE” Wirklichkeit werden zu lassen. Warum also nicht einen “Kern” definieren und den bisherigen Lieferumfang “on demand” dazupacken? Man versteht es nicht.

Auch “Jakarta EE” als “community driven effort” und JavaEE-Weiterführung steht ja noch nicht wirklich in voller Blüte. Es könnte so enden wie bei Hudson und OpenOffice. Oder Glassfish. Und wie geht es eigentlich Netbeans und VisualVM?

Ist das jetzige Gewurschtel eine notwendige Konsequenz aus anderen Entscheidungen wie der erhöhten Release-Frequenz? Müsste man denn dann nicht logischerweise den Änderungsumfang eher kleiner halten – nur, weil man was entfernt, löst man doch kein Problem. Dafür schafft man massiv Unsicherheit bezüglich des Commitments von Oracle zur Langzeitstabilität der Java-Plattform. Und was spricht letztlich für Java wenn nicht das bisherige Kompatibilitätsversprechen? Versucht man, durch hektische Betriebsamkeit Dynamik vorzutäuschen?

Es bleibt spannend. Enttäuschend finde ich die an den Haaren herbeigezogenen Begründungen vor allem für das Ende von Java Web Start. Gerade Oracle müsste doch wissen, dass die IT aus mehr als “Apps aus dem App-Store” besteht, und dass die Voraussetzung “ich habe Java auf dem Client installiert” für typische Firmen-IT jetzt nicht gerade das große Hindernis ist – andere Software hat auch Abhängigkeiten, die separat installiert werden müssen (.NET anyone?). Oder will man demnächst die Oracle-Datenbank abkündigen, weil sie nicht auf Android läuft? Interessant auch die Aussage, dass alle Web Start-basierten Oracle-Produkte für immer auf Java 8 bleiben werden. Das klingt nach echtem Zukunftsplan.

Einzig positiv aus meiner Sicht: der Markt ist nun weit offen für eine andere, bessere Deployment-Art – Java Web Start hatte ja auch seine Macken. Vielleicht ist “Zero Install” vom alten RISC OS-Spezl Thomas Leonard (berühmt für den ROX-Filer und ROX Desktop) ja die Alternative, die sich durchsetzt.

Ein Swing-Layout-Manager – OneRowSameSizeLayoutManager

 Java, Swing  Kommentare deaktiviert für Ein Swing-Layout-Manager – OneRowSameSizeLayoutManager
Feb 262018
 

Jeder Java-Entwickler, der schon mal seriös mit Swing eine Oberfläche gebaut hat, hat schon einmal mit dem Layout-Manager seiner Wahl gekämpft. Die standardmäßig im JDK ausgelieferten Layout-Manager sind eher gewöhnungsbedürftig bis leistungsschwach, mindestens aber umständlich. GroupLayout für komplexe Dinge und BorderLayout für Basislayouts sind gerade noch so verwendbar. Beliebte 3rd-party-Layout-Manager sind sicherlich MigLayout (oder MiG Layout? Man kann sich nicht enscheiden…), FormLayout, TableLayout und DesignGridLayout (Jahre nach dem Ableben von java.net wohl nur noch über Maven Central beziehbar).

Für besondere Bedürfnisse ist es manchmal eine gute Idee, einen einfachen LayoutManager selbst zu bauen. Ich habe das mal beispielhaft getan für den Anwendungsfall “Layout einer typischen Reihe von Buttons unten in einem Dialog”. Im Gegensatz zum merkwürdigen Beispiel im Swing-Tutorial von Oracle namens “DiagonalLayout” hoffe ich jedenfalls, dass mein Beispiel etwas mehr Nützlichkeit ausstrahlt. Der Quellcode ist mehr auf Lesbarkeit und Nachvollziehbarkeit denn auf Eleganz getrimmt. An einem schmissigeren Namen arbeite ich noch…

Irgendwann werde ich noch mal den “Packer”, einen Layout-Manager von Tcl/Tk, für Swing nachbauen. M.E. war der “Packer” in seinem Verhalten und der Vorhersagbarkeit des programmierten Resultats absolut untadelig, etwas was ich von den meisten Swing-LayoutManagern nicht sagen kann. Aber vielleicht ist meine Erinnerung an den Packer auch rosarot verklärt – ist schon über zwei Jahrzehnte her seit meinem ersten und letzten Kontakt.

/*
 * (c) hubersn Software
 * www.hubersn.com
 */
package com.hubersn.playground.swing.layout;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager;

import javax.swing.SwingConstants;

/**
 * A layout manager supporting a row of components kept at the same width and height with specifiable alignment and gap size between the
 * components. It has its own insets to avoid having to work with empty borders.
 */
public class OneRowSameSizeLayout implements LayoutManager {

  /** Constant for default left alignment (identical to SwingConstants.LEFT). */
  public static final int ALIGN_LEFT = SwingConstants.LEFT;
  /** Constant for default centre alignment (identical to SwingConstants.CENTER). */
  public static final int ALIGN_CENTER = SwingConstants.CENTER;
  /** Constant for default right alignment (identical to SwingConstants.RIGHT). */
  public static final int ALIGN_RIGHT = SwingConstants.RIGHT;

  // calculated overall minimum/preferred size
  private int minWidth = 0;
  private int minHeight = 0;
  private int preferredWidth = 0;
  private int preferredHeight = 0;
  // calculated maximum component preferred sizes
  private int maxPreferredWidth = 0;
  private int maxPreferredHeight = 0;

  private Insets insets;

  private int componentGap = 5;

  private int alignment;

  /**
   * Creates a new layout with right alignment, 4 pixels gap and 8 pixels insets all around.
   */
  public OneRowSameSizeLayout() {
    this(ALIGN_RIGHT, 4, new Insets(8, 8, 8, 8));
  }

  /**
   * Creates a new layout with given alignment, gap between components and insets.
   * 
   * @param alignment component alignment - ALIGN_LEFT, ALIGN_CENTER or ALIGN_RIGHT.
   * @param componentGap gap in pixels between components.
   * @param insets insets to use additional to possible container border - if null, all insets are 0.
   */
  public OneRowSameSizeLayout(final int alignment, final int componentGap, final Insets insets) {
    setAlignment(alignment);
    this.componentGap = componentGap;
    this.insets = insets;
    if (insets == null) {
      this.insets = new Insets(0, 0, 0, 0);
    }
  }

  /**
   * Sets the component alignment for this layout.
   * 
   * @param alignment component alignment - ALIGN_LEFT, ALIGN_CENTER or ALIGN_RIGHT.
   */
  public void setAlignment(final int alignment) {
    this.alignment = alignment;
  }

  @Override
  public void addLayoutComponent(String name, Component comp) {
    // nothing to do - we are not interested in user-given layout constraints.
  }

  @Override
  public void removeLayoutComponent(Component comp) {
    // nothing to do.
  }

  private void calculateSizes(Container parent) {
    final int numberOfComponents = parent.getComponentCount();

    this.preferredWidth = this.insets.left + this.insets.right;
    this.preferredHeight = this.insets.top + this.insets.bottom;
    this.minWidth = 0;
    this.minHeight = 0;

    final int numberOfVisibleComponents = getNumberOfVisibleComponents(parent);
    for (int i = 0; i < numberOfComponents; i++) {
      final Component c = parent.getComponent(i);
      if (c.isVisible()) {
        final Dimension d = c.getPreferredSize();
        this.maxPreferredWidth = Math.max(this.maxPreferredWidth, d.width);
        this.maxPreferredHeight = Math.max(this.maxPreferredHeight, d.height);
        this.minWidth += c.getMinimumSize().width;
      }
    }

    this.preferredHeight += this.maxPreferredHeight;
    this.minHeight = this.maxPreferredHeight;

    if (numberOfVisibleComponents > 0) {
      this.preferredWidth += (this.maxPreferredWidth * numberOfVisibleComponents);
      this.preferredWidth += this.componentGap * (numberOfVisibleComponents - 1);
    }
  }

  @Override
  public Dimension preferredLayoutSize(Container parent) {
    final Dimension dim = new Dimension(0, 0);

    calculateSizes(parent);

    final Insets parentInsets = parent.getInsets();
    dim.width = this.preferredWidth + parentInsets.left + parentInsets.right;
    dim.height = this.preferredHeight + parentInsets.top + parentInsets.bottom;

    return dim;
  }

  @Override
  public Dimension minimumLayoutSize(Container parent) {
    final Dimension dim = new Dimension(0, 0);

    final Insets parentInsets = parent.getInsets();
    dim.width = this.minWidth + parentInsets.left + parentInsets.right;
    dim.height = this.minHeight + parentInsets.top + parentInsets.bottom;

    return dim;
  }

  @Override
  public void layoutContainer(Container parent) {
    final int numberOfVisibleComponents = getNumberOfVisibleComponents(parent);
    if (numberOfVisibleComponents == 0) {
      return;
    }

    calculateSizes(parent);

    final Insets parentInsets = parent.getInsets();

    // will all fit into parent? Which sizes to reduce?
    // width sizing strategy:
    // first, shrink gap and insets to 0
    // then, shrink button width and height
    // height sizing strategy:
    // shrink insets to 0
    final int parentWidth = parent.getWidth() - (parentInsets.left + parentInsets.right);
    final int parentHeight = parent.getHeight() - (parentInsets.top + parentInsets.bottom);
    final int heightToUse = Math.min(parentHeight, this.maxPreferredHeight);
    // width shrinking - toUse values are used for final layout bounds setting step
    int widthToUse = this.maxPreferredWidth;
    int buttonGapToUse = this.componentGap;
    int leftInsetToUse = this.insets.left;
    int rightInsetToUse = this.insets.right;

    int amountToReduceWidth = this.preferredWidth - parentWidth;
    if (amountToReduceWidth > 0) {
      // we need to save some pixels...
      // check for left/right insets
      if (leftInsetToUse + rightInsetToUse >= amountToReduceWidth) {
        int reduceInsetBy = amountToReduceWidth / 2;
        leftInsetToUse -= reduceInsetBy;
        amountToReduceWidth = 0;
      } else {
        leftInsetToUse = 0;
        amountToReduceWidth -= (this.insets.left + this.insets.right);
      }
      if (amountToReduceWidth > 0) {
        // check for button gaps
        if (numberOfVisibleComponents > 1 && (numberOfVisibleComponents - 1) * buttonGapToUse >= amountToReduceWidth) {
          buttonGapToUse -= amountToReduceWidth / (numberOfVisibleComponents - 1);
          amountToReduceWidth = 0;
        } else {
          buttonGapToUse = 0;
          amountToReduceWidth -= (numberOfVisibleComponents - 1) * this.componentGap;
        }
        // now shrink the button size itself as a last resort
        if (amountToReduceWidth > 0) {
          widthToUse = parentWidth / numberOfVisibleComponents;
        }
      }
    }

    // height shrinking - toUse values are used for final layout bounds setting step
    int topInsetToUse = this.insets.top;
    int amountToReduceHeight = this.preferredHeight - parentHeight;
    if (amountToReduceHeight > 0) {
      // we need to save some pixels...
      // check for top/bottom insets
      if (topInsetToUse + this.insets.bottom >= amountToReduceHeight) {
        int reduceInsetBy = amountToReduceHeight / 2;
        topInsetToUse -= reduceInsetBy;
      } else {
        topInsetToUse = 0;
      }
    }

    // finally size and place the components
    int x = parentInsets.left + leftInsetToUse;
    // alignment is only relevant if we have enough space
    if (parentWidth > this.preferredWidth) {
      if (this.alignment == ALIGN_CENTER) {
        x += (parentWidth - this.preferredWidth) / 2;
      } else if (this.alignment == ALIGN_RIGHT) {
        x += parentWidth - this.preferredWidth;
      }
    }

    final int y = parentInsets.top + topInsetToUse;

    final int numberOfComponents = parent.getComponentCount();
    for (int i = 0; i < numberOfComponents; i++) {
      Component c = parent.getComponent(i);
      if (c.isVisible()) {
        c.setBounds(x, y, widthToUse, heightToUse);
        x += widthToUse + buttonGapToUse;
      }
    }
  }

  private static int getNumberOfVisibleComponents(final Container parent) {
    final int numberOfComponents = parent.getComponentCount();
    int numberOfVisibleComponents = 0;

    for (int i = 0; i < numberOfComponents; i++) {
      Component c = parent.getComponent(i);
      if (c.isVisible()) {
        numberOfVisibleComponents++;
      }
    }

    return numberOfVisibleComponents;
  }
}

Eine Swing-Komponente – JVM-Memory-Indicator

 Java, Swing  Kommentare deaktiviert für Eine Swing-Komponente – JVM-Memory-Indicator
Feb 242018
 

Ich entwickle grafische Oberflächen in Java Swing seit der Zeit, als man Swing noch separat herunterladen musste und es noch im Package com.sun.java.swing wohnte. JDK 1.1. In JDK 1.0.2 hat man sich kurz AWT angeschaut, gelacht und es zu den Akten gelegt. Swing hingegen war ein seriöser Versuch eines leistungsfähigen und trotzdem plattformübergreifenden UI-Toolkits.

Drei Dinge jenseits von Java SE braucht der Swing-Entwickler bis heute: Komponenten, Layout-Manager und ggf. ein Application Framework. Neulich war ich auf der Suche nach einer kleinen schmalen Komponente für eins meiner zahlreichen Swing-basierten Inhouse-Tools, um den Zustand der JVM-Speicherverwaltung zu signalisieren, ähnlich wie Eclipse es standardmäßig anbietet wenn man es aktiviert unter “Window -> Preferences -> Global -> Show heap status”.

Als erfahrener Googler hätte ich erwartet, eher ein Problem mit zuviel als zuwenig Auswahl zu haben. Aber Pustekuchen: letztlich fand ich nur eine Frage auf StackOverflow (witzigerweise wenige Stunden nach meiner Antwort als off-topic geschlossen – und das bei einer Frage von 2009!) nach einer solchen Komponente, die lediglich zwei komplett falsche Antworten der Kategorie “Thema verfehlt” nach sich zog. Also habe ich mir mal eine Stunde Zeit genommen, um mit minimalem Aufwand eine solche Komponente zu bauen. Als Basis habe ich JProgressBar verwendet. Das Ergebnis ist natürlich weit weg von der wünschenswerten Flexibilität einer solchen Komponente, wenn sie in unterschiedlichen Kontexten wiederverwendbar sein soll, aber als ein schönes einfaches Beispiel taugt es dennoch. Die Komponente ist lizenztechnisch frei verwendbar allüberall. Eigene Anpassungen ausdrücklich erwünscht. i18n-Unterstützung, MiB vs. MB, Text und Tooltip über extern vorgebbare Texte mit Platzhaltern realisieren, ein “Trash”-Icon zum Auslösen des GC anstatt der nichtoffensichtlichen Doppelclick-Variante, eine “Mark”-Funktionalität ähnlich Eclipse – die Erweiterungsideen sind beinahe endlos.

/*
 * (c) hubersn Software
 * www.hubersn.com
 * 
 * Use wherever you like, change whatever you want. It's free!
 */
package com.hubersn.playground.swing;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JProgressBar;
import javax.swing.Timer;

/**
 * JVM Memory Indicator based on JProgressBar.
 */
public class ProgressBarBasedJVMMemoryIndicator extends JProgressBar {

  private static final long serialVersionUID = 1L;

  private static final int TIMER_INTERVAL_IN_MS = 1000;

  /**
   * Creates a new instance of ProgressBarBasedJVMMemoryIndicator.
   */
  public ProgressBarBasedJVMMemoryIndicator() {
    super(0, 100);
    setStringPainted(true);
    setString("");
    addMouseListener(new MouseAdapter() {
      @Override
      public void mouseClicked(final MouseEvent mev) {
        if (mev.getClickCount() == 2) {
          System.gc();
          update();
        }
      }
    });
    final Timer t = new Timer(TIMER_INTERVAL_IN_MS, new ActionListener() {
      @Override
      public void actionPerformed(final ActionEvent aev) {
        update();
      }
    });
    t.start();
    update();
  }

  private void update() {
    final Runtime jvmRuntime = Runtime.getRuntime();
    final long totalMemory = jvmRuntime.totalMemory();
    final long maxMemory = jvmRuntime.maxMemory();
    final long usedMemory = totalMemory - jvmRuntime.freeMemory();

    final long MEBIBYTE_FACTOR = 1024 * 1024;
    final long totalMemoryInMebibytes = totalMemory / MEBIBYTE_FACTOR;
    final long maxMemoryInMebibytes = maxMemory / MEBIBYTE_FACTOR;
    final long usedMemoryInMebibytes = usedMemory / MEBIBYTE_FACTOR;
    final int usedPercentage = (int) ((100 * usedMemory) / totalMemory);
    final String textToShow = usedMemoryInMebibytes + "MiB of " + totalMemoryInMebibytes + "MiB";
    final String toolTipToShow = "Heap size: " + usedMemoryInMebibytes + "MiB of total: " + totalMemoryInMebibytes + "MiB max: "
        + maxMemoryInMebibytes + "MiB - double-click to run Garbage Collector";

    setValue(usedPercentage);
    setString(textToShow);
    setToolTipText(toolTipToShow);
  }
}

Aus mir unerfindlichen Gründen habe ich danach angefangen, eine superflexible, i18n-fähige, effiziente, JComponent-basierte Variante davon zu bauen. Hat auch nicht viel länger gedauert. Soll “demnächst” im Rahmen meiner ultimativen Swing-Bibliothek das Licht der Welt erblicken – das soll diese Bibliothek aber schon seit ungefähr 2001…

Beknackte Oberflächen – heute: Toshiba 32XV733G

 UI  Kommentare deaktiviert für Beknackte Oberflächen – heute: Toshiba 32XV733G
Jan 282018
 

Wer es nicht gleich an der Typenbezeichnung erkannt hat: es soll heute um ein kleines Detail der Benutzungsoberfläche eines Fernsehers gehen. Ein Fernseher nach altem Schrot und Korn, kein “Smart TV” oder sowas. 32″-LCD Standardtechnologie ohne Schnick und Schnack.

In einem heroischen Versuch, die Bedienung für das elterliche Gerät etwas einfacher zu gestalten, habe ich die Eingänge “beschriftet”, also mit einer sprechenderen Bezeichnung als “Input 1″ oder HDMI 3” versehen.

Texteingabe mit einer Standard-Fernsehfernbedienung ist natürlich immer mühsam, egal wie man das technisch löst (Grundig hatte bei einem S-VHS-Topmodell mal eine komplette Tastatur auf der Rückseite der Fernbedienung untergebracht – das war eine seriöse Lösung!). Texteingabe ohne volle Tastatur ist immer eine Kompromisslösung. Der ist diesmal gar nicht so schlecht gelungen, man kann “umschalten” zwischen Groß- und Kleinbuchstaben sowie Ziffern und Sonderzeichen. Amüsanterweise kann man dann über eine andere Farbtaste noch Sonder-Sonderzeichen wie Umlaute einblenden. “Häh”, denkt sich da der gemeine Benutzer – aber egal. Wer schon mal bei einem Yamaha-Receiver die Eingänge mit Text versehen wollte, wird die Toshiba-Lösung für das Allerbeste halten.

Jedenfalls wollte ich einen Eingang mit dem Text “Blu-Ray-Recorder” versehen (lobenswertes Detail am Rande: es gibt die Möglichkeit, vorgefertigte Texte zu verwenden wie “Receiver” oder “DVD” – sehr gut mitgedacht, Toshiba!). Mühsam eingetippt. Bestätigt mit der blauen Farbtaste (warum? In anderen Teilen des Menüs sind es andere Tasten). Das Gerät erfreut mich mit der Meldung, dass nur maximal 10 Zeichen Text erlaubt sind.

Tja…das Gerät ist von 2010, da war so fortschrittliche UI-Technologie wie ein längenbeschränktes Eingabefeld natürlich noch unbekannt.

Nun gut, in der Welt der Fernsehbedienung sicher nicht das allergrößte Problem der Benutzungsoberflächen. Wer mal ein paar Stunden damit verbracht hat, Sender nach einem Sendersuchlauf in eine sinnvolle Reihenfolge zu bringen wird wissen, dass es noch viel größere Ergonomiekatastrophen gibt – ich hätte schon lange einen Artikel darüber verfasst, aber das Thema macht mich depressiv. Nicht mal ein positiver Artikel zur Sendersortierung beim Macrosystem Enterprise wollte meiner Feder entspringen. Vielleicht irgendwann…

Oracle und VisualVM

 Java  Kommentare deaktiviert für Oracle und VisualVM
Dez 302017
 

Eines meiner Lieblings-Java-Tools ist die VisualVM – vor wenigen Tagen wurde Version 1.4 released, mit offiziellem Java 9-Support. Die Vorgänger-Version 1.3.9 funktionierte schon leidlich mit Java 9, aber “offiziell” ist bekanntlich immer besser.

Und das führt uns zum traurigen Teil der Geschichte, nämlich Oracle’s Entscheidung, JDK 9 ohne die VisualVM auszuliefern (neben der grandiosen Idee, die bisher per Definition in ISO-8859-1 vorliegenden .properties-Dateien einfach mal in UTF-8 zu lesen, sicher die schlechteste). Und das ohne vernünftigen Ersatz – Java Mission Control hat bekanntlich eine üble Lizenzeinschränkung bezüglich kommerziellem Einsatz, und die gute alte JConsole ist eben genau das – alt. Mit VisualVM war es schön einfach, selbst unbedarfte User “mal schnell” einen Heapdump oder Threaddump ziehen zu lassen. Vorbei.

Immerhin ist die Version 1.4 ein Lebenszeichen, ich hatte schon Schlimmeres befürchtet. Der Hinweis, dass 1.4 nun auf der NetBeans-Plattform Version 9 basiert (wenn auch einer Entwicklungsversion), ist gleichzeitig auch ein Lebenszeichen von NetBeans, das bekanntlich vor einiger Zeit von Oracle zu Apache gewechselt ist – seither hoffen alle, dass das besser läuft als bei OpenOffice. NetBeans 8.2 war ja von Oktober 2016, seither waren die News eher sparsam. Ich bin zar nie mit NetBeans warm geworden, aber etwas Konkurrenz tut sowohl Eclipse als auch IntelliJ immer gut.

Amüsantes Detail aus den Release Notes von VisualVM 1.4: Windows 10 ist offenbar keine unterstützte Plattform…

Frohes Fest, guten Rutsch

 Uncategorized  Kommentare deaktiviert für Frohes Fest, guten Rutsch
Dez 252017
 

2017 war ein eher sparsames Blog-Jahr in meiner IT-Abteilung. Gewisse Dinge in der IT frustrieren mich zunehmend. Sei es die beinahe grenzenlose Naivität gewisser Teile der agilen Bewegung, die Entscheidung von eBay einen unglaublich schlechten automatischen Übersetzungsmechanismus für Angebote aus dem Ausland einzusetzen (natürlich nicht abschaltbar), die unentwegte Ankündigung des autonomen Fahrens ohne auch nur die grundlegenden Probleme KI-technisch im Griff zu haben, das ständige Erfinden neuer Programmiersprachen mit denselben alten Schwächen ohne aus der Historie zu lernen, die Unfähigkeit von Windows einfach nur eine Menge Dateien unfallfrei zu kopieren (unbedingt lesen: der Fehler 0x80070057)…aber man kann doch nicht jede Woche einen Abkotzartikel schreiben. Das macht doch schlechte Stimmung.

Vielleicht bin ich im neuen Jahr ja erfolgreicher beim Aufstöbern von positiven Entwicklungen im IT-Bereich. Die Hoffnung stirbt zuletzt (aber sie stirbt…) – immerhin hat die IT noch nicht den Frustfaktor der Politik erreicht.

MediaWiki-Gefrickel

 Uncategorized  Kommentare deaktiviert für MediaWiki-Gefrickel
Nov 242017
 

Ich konnte gerade durch beherzte Recherche ein nerviges Problem lösen, das mich fast in den Wahnsinn trieb. Die Zutaten: PHP, MediaWiki, Perl und PCRE. Und ein gehosteter Server ohne Shellzugriff.

Ich verwende MediaWiki seit einiger Zeit als mein privates Wiki – nicht gerade der ursprüngliche Einsatzzweck eines Wikis, wo ja eher Kollaboration im Mittelpunkt steht, aber was soll’s – es taugt für meine Zwecke. Da ich der Backup-Strategie von Profis mehr vertraue als meiner eigenen, läuft das Dingens bei einem bekannten Hoster in deutschen Landen. Problem: ich habe dort keinen Shell-Zugriff, nur FTP-Zugriff. Was das Updaten von “Apps” wie MediaWiki oftmals schwierig macht. Also laufen hier gerne mal etwas ältere Versionen, wenn neuere DB-Updates brauchen, die nur über die Shell möglich sind.

Von einem Tag auf den anderen entschied sich MediaWiki nun, die Wiki-Seiten nicht mehr anzuzeigen. Oder genauer: nur noch den Seitentitel, nicht aber den Inhalt. Über “Bearbeiten” konnte man aber sehen, dass die Inhalte nach wie vor vorhanden waren, die Datenbank selbst also keinen Schaden davongetragen hatte – irgendwo in der Aufbereitung durch PHP steckte also der Wurm.

Zunächst dachte ich, dass vielleicht eine Datei korrupt ist. Also das Backup zurückgespielt. Keine Änderung. Dann das Original-Release von MediaWiki drüberkopiert. Keine Änderung. Die neueste MediaWiki-Version installiert. Kann nicht mit der vorhandenen Datenbank zusammenarbeiten, der Web-Updater versagte ebenfalls den Dienst. Mit einer frischen Datenbank funktioniert alles – also prinzipiell sind die beteiligten Komponenten auf dem Server immer noch MediaWiki-tauglich.

Also den Google angeworfen. Nach diversen Irrungen und Wirrungen durch die Weiten des Webs fand ich einen Hinweis, dass das Problem durch ein Update von PCRE von 8.33 auf 8.34 ausgelöst wurde. Klar, wer käme nicht auf die Idee, dass ein mickriger Patch mal kurz gravierend die Rückwärtskompatibilität bricht.

Die schmutzigen Details: hier die Info aus dem Mediawiki-Wiki. Hier der entsprechende Thread im MediaWiki-Bugtracker. Hier kann man den Diff im Gerrit sehen. Man muss lediglich in include/MagicWord.php eine Zeile löschen und zwei hinzufügen. Einfach, wenn man weiß wie…

Die Konsequenz? Ich werden wohl das Wiki auf einen Server umziehen müssen, bei dem ich Root-Zugriff habe, um das Einspielen von Updates zu vereinfachen.

Java Forum Stuttgart 2017

 Java  Kommentare deaktiviert für Java Forum Stuttgart 2017
Jul 072017
 

Das Java Forum Stuttgart fand 2017 zum nunmehr zwanzigsten Male statt, und ich war mal wieder vor Ort dabei, da das Vortragsprogramm aus meiner Sicht recht ansprechend war. Ich nutze das Java Forum hauptsächlich, um mal wieder dran erinnert zu werden, wie riesig das Java-Universum ist und wie viele Technologien und Frameworks es da gibt, Hype inklusive. Es gab zum Abschluss als Pecha-Kucha-Vortrag einen Rückblick auf die letzten 19 Veranstaltungen inklusive Blick auf die damals aktuellen Themen, da war einiges an damals hippem Zeugs dabei, das schon wenige Jahre später komplett in der Versenkung verschwunden war.

Aber das Thema soll ja weniger die Vergangenheit als die Gegenwart sein.

Los ging’s mit der JAX-RS 2.1-Schnellbleiche durch Markus Karg, der in der Expert Group des dazugehörigen JSR 370 mitarbeitet. Meine Expertise in diesem Bereich ist sehr begrenzt, aber ich konnte dem Vortrag inhaltlich sehr gut folgen und habe auf meine Todo-Liste “REST-API für CinePoll” geschrieben. Wie bei fast allen Technologien kann man ja viel drüber lesen, aber verstehen wird man es erst wenn man es nutzt. Interessant fand ich die Anmerkung, dass ja “im Prinzip” keiner mehr den großen Server am Start hat, sondern stattdessen alle Microservices im Docker-Container deployen. Dazu kann ich nur sagen: in manchen Branchen ist man noch lange nicht soweit.

Im nächsten Zeitslot habe ich ReactiveX mit RxJava besucht. Ursprünglich wollte ich da nicht hin, weil der vorgesehene Vortragende bei mir bei einer vorherigen Ausgabe des Java Forum einen eher durchwachsenen Eindruck hinterließ, und ich die Erfahrung gemacht habe, dass ein guter Referent wichtiger ist als ein spannendes Thema. Jan Blankenhorn hat hier seine Sache jedenfalls sehr gut gemacht, inklusive Live-Coding, was ja immer einen gewissen Risikofaktor beinhaltet. Jedenfalls nahm ich mindestens zwei Erkenntnisse mit: ich muss doch IntelliJ IDEA eine zweite Chance geben, und ich muss dringend Routine bei den neuen Java 8-Features bekommen – bei der Lambda-Notation muss ich immer zweimal hinschauen, um den Code zu verstehen. Da ich täglich im Beruf auf Java 7 limitiert bin, fehlt einfach der routinierte Blick darauf.

Dann war es wieder Zeit für Michael Wiedeking, diesmal mit dem Thema Über den Umgang mit Streams. Wie immer sowohl unterhaltsam als auch lehrreich. Und wieder ein Knoten im Taschentuch für “Java-8-Features”. Und sehr plastische Beispiele für die Komplexitätsbetrachtung von Operationen.

Auch den Slot vor dem Mittagessen bestritt ein alter Bekannter: Björn Müller von der CaptainCasa GmbH mit dem Thema Von Java-Swing, über JavaFX zu HTML für operativ genutzte Geschäftsanwendungen. Er berichtete von der Reise des CaptainCasa-Frameworks von der Swing-UI über die JavaFX-UI hin zur neuen HTML-UI. Der Ansatz von “RISC-HTML” führt zu höchst erstaunlichen Ergebnissen, die damit erreichte Performance der Oberfläche im Browser war aus meiner Sicht verblüffend. Die nicht immer ganz hasenreinen Ausführungen und Analogien zu CISC-vs-RISC bei den Prozessoren habe ich da gerne verziehen. Interessant auch die Einschätzungen und Erfahrungen zu JavaFX, die sich durchaus mit meinen Beobachtungen decken: am Markt gescheitert, Zukunft ungewiss. Die Krise der Cross-Platform-UI-Toolkits geht weiter.

Nach der Mittagspause ging es bei mir weiter mit Mobile hybride Applikationen – Investment-App der BW-Bank, präsentiert von Manfred Heiland von der avono AG. Cross-Platform-Lösungen interessieren mich seit Anbeginn der Java-Zeit mit dem Versprechen “Write Once, Run Anywhere”. Was auf der Serverseite nach wie vor prima funktioniert, ist im Bereich der grafischen Oberfläche ja schon längere Zeit eher schwierig. Swing war der letzte aus meiner Sicht einigermaßen erfolgreiche Versuch, ein Cross-Platform-UI-Toolkit an den Start zu bringen. Aber bezüglich mobiler Plattformen bringt das halt auch nix. Dort hat man im Prinzip die Wahl auf WebViews zu setzen, oder halt mehrfach native Apps zu bauen – ob Technologien wie Gluon hier irgendwann adäquate Lösungen erlauben, die auch über viele Jahre stabil bleiben, ist aus meiner Sicht noch unklar. Die Tatsache, dass iOS Objective C oder Swift nahelegt und Android Java erleichtert die Sache nicht. Und hier bietet das vorgestellte Projekt mit seinem Hybridansatz eine interessante Alternative. Die fachlogisch einfachen Teile, die die Steuerung der App übernehmen, werden nativ implementiert, diverse komplexere Inhalte hingegen, die hauptsächlich der Anzeige dienen, werden über WebViews gemacht. Offenbar gibt es inzwischen sowohl unter Android als auch unter iOS einigermaßen elegante Lösungen, per JavaScript in beide Richtungen zu kommunizieren, so dass mir der hybride Ansatz sehr plausibel erscheint. Laut Referent gab es auch keine Probleme, die Apps in die App-Stores zu bringen – das ist bei “ich kapsle meine Webanwendung einfach als App”-Variante ja nicht immer so problemlos.

Als passionierter Frontend-Entwickler habe ich dann natürlich UI Technologieradar besucht. Das erwies sich als nicht so besonders fruchtbar. Die versprochene “objektive Entscheidungshilfe bei der UI-Technologiefindung” erwies sich als eher simple Ansatz einer Bewertungsmatrix verschiedenster (aber immer noch sehr lückenhafter) UI-Technologien, wobei die Bewertungen sich als durch und durch subjektiv erwiesen. Die ausgearbeiteten Kriterien entsprachen ungefähr dem, was ein etwas erfahrener Consultant oder Entwickler nach 30 Minuten scharfem Nachdenken selbst erarbeitet hätte. Und es traten verschiedene Einschätzungen und Aussagen zu diversen Technologien hervor, die die Glaubwürdigkeit der ganzen Idee doch in einem ziemlich schalen Dämmerlicht erscheinen ließen – beispielsweise wurde die These aufgestellt, dass mit Java Swing ja nie jemand eigene Komponenten erstellt habe, während das bei diversen Webtechnologien gängige Praxis sei. Aus meiner Sicht eine komplett absurde Einschätzung und nur durch sehr enge Scheuklappen aus der eigenen Projekterfahrung zu erklären – was der Consultant noch nicht gesehen hat, gibt es nicht. Zu allem Überfluss bildeten die beiden Vortragenden auch noch einen scharfen Kontrast bezüglich ihrer präsentatorischen Fähigkeiten, was sich als sehr störend herausstellte. Präsentieren im Duo geht aus meiner Sicht nur, wenn beide sich entweder gut ergänzen oder gut aufeinander eingespielt sind. Keines von beidem war hier der Fall. Und als Schlusspunkt: das “UI Technologieradar” wurde in der Vortragsankündigung als fertig einsetzbares Tool charakterisiert – im Vortrag stellte sich allerdings heraus, dass es sich noch in einem sehr frühen Stadium der Entwicklung befindet. Ebenfalls in der Ankündigung: man würde Technologien wie React.js oder Spring MVC kurz kennenlernen. Das entpuppte sich als stark übertrieben: Spring MVC beispielsweise tauchte nur namentlich auf einigen Folien auf. Interessant auch ein innerer Widerspruch: auf mehreren Folien tauchte die These auf, dass GWT stark auf dem absteigenden Ast sei. Empfehlung: nicht mehr für neue Projekte verwenden. Kann man so sehen. Aber die Begründung, warum AngularJS so eine gute Wahl sei, war, dass eine große Firma wie Google dahinter steht. Finde den Fehler.

Den Abschluss bildete für mich die Pecha-Kucha-Session. Auch dieses Mal muss ich feststellen: das Format gibt mir überhaupt nix. Wenn der Vortragende gut ist (wie in diesem Falle mal wieder Michael Wiedeking), merkt man im Vortrag gar nicht, dass es im Pecha-Kucha-Style abläuft. Wenn der Vortragende schlecht ist (bzw. den Ablauf nicht häufig genug geübt hat, um das passende Timing zu entwickeln), passt die Folie nicht zum Gesprochenen. Und das Format scheint zur Nutzung nichtssagender Bilder zu animieren, denn dann passt die Folie auch automatisch zum gesprochenen Wort. Auf die einzelnen Vorträge (klassisches 20×20-Format, 5 Vorträge für die zur Verfügung stehenden 45 Minuten) will ich gar nicht detailliert eingehen und will nur den von Michael Wiedeking lobend hervorheben, der unter dem Titel “Schall und Rauch” sehr plastisch ausführte, wie kompliziert es ist sprechende Methodennamen zu finden. Aus meiner Sicht übrigens der Knackpunkt der CleanCode-Bewegung und ihrem Mantra “Kommentare überflüssig, der Code erklärt sich von selbst”. Das zeigte sich, als das Publikum abstimmen durfte, welcher Methodenname am passendsten zur beschriebenen Operation sei. Da herrschte kein klares Meinungsbild, was die Problematik doch sehr verdeutlicht. Essenz daraus: entscheide Dich für ein Wording, aber ziehe das dann auch konsistent durch – Du wirst es nie allen recht machen können.

Wer Beispiele für gelungene Pecha-Kucha-Vorträge kennt (also nicht nur: guter Vortrag, sondern Mehrwert durch die Tatsache, dass er dem Format folgt): gerne Links an mich schicken, vielleicht ändere ich meine Meinung.

Unterm Strich fand ich die Veranstaltung sehr gelungen. Die Vielfalt der Vorträge gefällt mir gut, preislich ein Schnäppchen, Top-Organisation, Verpflegung OK. Gut, die Liederhalle ist etwas in die Jahre gekommen, aber das stört nicht sonderlich. Also: nächstes Jahr wieder dabei. Hoffentlich wieder bei Vorträgen von Michael Wiedeking und Björn Müller.