Using Flying Saucer PDF offline

Flying saucer is a nice tool for quick PDF generation from a (X)HTML page. Everything worked fine when we tested it at home but when we had a demo at a client’s site, no PDF could be generated. The problem was caused by a little snippet in the header of the HTML:

<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

The DTD declaration! So we took a look at the flying saucer issue database and found someone who had the same problem.
But another solution is even simpler:
Xerces has a default setting which tells the parser to load external dtds.
Turning this off solved our offline problems:

  DocumentBuilderFactory builderFactory =
    DocumentBuilderFactory.newInstance();
  builderFactory.setFeature(
    "http://apache.org/xml/features/nonvalidating/load-external-dtd",
    false);

When as Set is not what you want

When you want to filter out duplicates in a list in groovy you normally do something like:

        def list = [2, 1, 2, 3]
        def filtered = list as Set
        assertEquals([1, 2, 3], filtered as List)

This kicks out all duplicates in a one-liner. But what if the list is sorted (e.g. in reverseOrder)?

        def list = [3, 2, 2, 1]
        def filtered = list as Set
        assertEquals([3, 2, 1], filtered as List) // this fails!

One solution would be to use a small closure:

        def list = [3, 2, 2, 1]
        def filteredList = []
        list.each {
            if (!filteredList.contains(it)) {
                filteredList << it
            }
        }
        assertEquals([3, 2, 1], filteredList)

This closures preserves the order and filters out the duplicates.

Multipage Flows with Grails Part One – The traditional way

When you are developing web apps once in a while you need a flow of multiple pages just like a shopping cart at Amazon. Since there are different ways to implement such a multipage flow in Grails I thought of recording our experiences here.

The scenario

We model the process of submission of a proposal for different kinds of technologies. First you have to decide which type of proposal (once, long-term, in house) you want to submit. On the second page you give your personal infos and a general description of your intentions using the chosen technologies. Here you also choose the technologies you want. This has an impact on the following page which holds the information for the different technologies. Last but not least you save the proposal and show it to the user so he can see what data he entered. This flow could look like this:

-> chooseType -> enterGeneralInfo -> enterSpecificInfo -> save -> show

In each of the steps we need different parts of the full proposal. So we decided to use Command Objects in Grails. These objects are filled and are validated automatically by Grails. To use them you just have to delare them as parameter to the closure:

def enterSpecificInfo = {GeneralPartCommand cmd ->
  if (!cmd.hasErrors()) {
    Proposal proposal = new Proposal(cmd.properties)
    proposal.specificInfos = determineSpecificInfos(proposal.technologies)
    render(view: 'enterSpecificInfo', model: ['proposal': proposal])
  }
  else {
    render(view: 'enterGeneralInfo', model: ['proposal': cmd])
  }
}

You can then bind the properties in the command object to the proposal itself. The GeneralPartCommand has the properties and constraints which are needed for the general information of the proposal. This imposes a violation of the DRY (Don’t Repeat Yourself) principle as the properties and the constraints are duplicated in the proposal and the command object but more about this in another post.

How to collect all the data needed

Since you can only and possibly want to save the proposal at the end of the flow when it is complete you have to track the information entered in the previous steps. Here hidden form fields come in handy. These have to store the information of all previous steps taken so far. This can be a burden to do by hand and is a place where bugs arise.

How to go from one state to another

To transition from one state to the next you just validate the command object (or the proposal in the final state) to see if all data required is there. If you have no errors you render the view of the next state. When something is missing you just re-render the current view:

if (!cmd.hasErrors()) {
  Proposal proposal = new Proposal(cmd.properties)
  proposal.specificInfos = determineSpecificInfos(proposal.technologies)
  render(view: 'enterSpecificInfo', model: ['proposal': proposal])
}
else {
  render(view: 'enterGeneralInfo', model: ['proposal': cmd])
}

The errors section in the view takes the errors and prints them out. The forms in the views then use the next state for the action parameter.

Summary

An advantage of this solution is you can use it without any add-ons or plugins. Also the URLs are simple and clean. You can use the back button and jump to almost every page in the flow without doing any harm. Almost – the transition which saves the proposal causes the same proposal to be saved again. This duplicates the proposal because the only key is the internal id which is set in the save action.
Besides the DRY violation sketched above another problem arises from the fact that the logic of the states and the transitions are scattered between several controller actions and the action parameters in the forms. Also you have to remember to track every data in hidden form fields.
In a future post we take a look at how Spring (WebFlow) solves some of these problems and also introduces others.

Give your project a voice

We are all very into Extreme Feedback Devices (XFD), so we decided to use all our senses to gather feedback from our projects. This becomes a real challenge once you think about it, because we are naturally very focused on (and limited to) visual feedback.

So we decided to put audible feedback to work.

All our projects get continuously built by two servers in parallel. The first server checks for compilation and test errors, just like a good CI server should. The second server applies every quality metric we found helpful to the code and spits out huge amounts of numbers for every single build.

We identified the numbers that really matter to us and established a simple mechanism to scrape them from the result web pages. Then we associated a sound sample with all possible changes and plugged some speakers to our feedback server.

So now, expect our projects to clearly articulate their news.

To give you an idea of how it sounds, here’s a short list of possible audio samples:

  • Fixed an important bug: “Impressive”
  • Reduced code crap: “Excellent”
  • Introduced a bug: “Humiliation”

Imagine the words spoken like in an old Quake game. Now you can have an eventful build and be yelled at like “Impressive Excellent Humiliation”.

We reserved the biggest coding failure we can imagine happening here to a special audio sample. If somebody introduces new code crap (as determined by Crap4J), he gets ordered to “CUT THE CRAP!” at incredible volume. We used the voice of the inventor of XFDs, Alberto Savoia, taken from his delightful training video for management by numbers (position 2:03ff). The audio quality isn’t convincing, his command surely is.

If you wonder what it’s like to be suddenly interrupted by different voices rebuking or praising you – it’s healthy. You get used to it very quickly, yet the information always catches on. And the information is always relevant.

We call it our “audible remorse”.


Read more about our Extreme Feedback Devices:

Der blinde Fleck von Continuous Integration

Blinder FleckAn english version of this blog entry can be found at https://schneide.wordpress.com/2009/12/28/a-blind-spot-of-continuous-integration/

Am Montag früh brach nach einem Routine-Update unseres CI-Servers und anschließendem manuell gestartetem Baudurchgang plötzlich ein Test in einem Projekt, das seit Wochen keine Änderung mehr erfahren hatte.

Die Analyse des Tests zeigte relativ schnell, dass offensichtlich die A-TRIP Regeln für gute Unit Tests verletzt wurden und der Test unter Verwendung des aktuellen Zeitpunkts Datumsberechnungen in die Zukunft und die Vergangenheit testet. Am Sonntag früh wurde auf Sommerzeit umgestellt, so dass dem Test plötzlich eine Stunde in der Vergangenheitsberechnung fehlte.

Den Test zu beheben war einfach, allerdings war er bereits seit Mai 2006 im Projekt enthalten. Seitdem muss dieses Projekt immer um die Zeitumstellung herum inaktiv gewesen sein. Unser Continuous Integration hat das Problem jedenfalls erst jetzt (und auch da nur durch den Zufall einer CI-Aktualisierung zum richtigen Zeitpunkt) gefunden.

Die Phänomene, die durch ungeschickte Unit Tests hervorgerufen werden, sind mit einem verdachtunabhängigen Nightly Build scheinbar zuverlässiger zu finden als mit Continuous Integration. Eine Kombination beider Techniken scheint uns nach dieser Erfahrung lohnenswert zu sein.

Unabhängig von CI oder Nightly Builds gilt: Ein Unit Test, der den Konstruktor von Date, DateTime, Calendar oder einer ähnlichen Klasse aufruft, ist vermutlich ein schlechter Unit Test.

Gedanken zu Online-Hilfen

Eine gute moderne Software hat eine kontextbezogene Online-Hilfe. Bei einer sehr guten modernen Software wird diese nie benutzt, aber das ist ein anderes Thema.

Wir haben in der Schneide verschiedene Ansätze ausprobiert, die alle einen großen Nachteil hatten: Die eingestellten Inhalte waren an manchen Stellen unverständlich oder zu knapp und der Benutzer konnte nicht viel dagegen tun. Daher befassen wir uns gerade mit der Idee, eine Online-Hilfe mit einem Wiki zu koppeln. Auf diese Weise könnten die Benutzer ihre Online-Hilfe selbst verbessern und fortschreiben, so dass die Inhalte hilfreicher werden.

Um die Vor- und Nachteile dieses Ansatzes nicht erst durch den Kunden testen zu lassen, haben wir einen Selbstversuch gestartet. Die Online-Hilfe betrifft allerdings keine Software, sondern die Schneide selbst.

Eine Online-Hilfe für den Arbeitsplatz

Wir haben uns das Konzept der “WikiTags” ausgedacht, kleine Aufkleber mit einer Wiki-Adresse und einem Symbol, das auf diesen Umstand hinweist.

Thumb Spoon WikiTag 

Mit diesen WikiTags rüsten wir gerade alle Räume und Gegenstände in Reichweite aus, so dass sie einem Eintrag in unserer Firmen-Online-Hilfe (unserem Wiki) zugeordnet sind. Über ein kleines Eingabefeld in unserem Intranetportal gelangt man direkt auf die betreffende Wiki-Seite (der sogenannte WikiWarp), kann dort die Informationen zum Gegenstand (z.B. Bedienhinweise oder Bezugsquellen) einsehen und auch gleich verbessern und ergänzen.

Spoon Wiki Page

Wir haben also eine halbautomatisch aktivierbare Online-Hilfe für unsere Firma implementiert und die ersten Erfahrungen damit gesammelt. Was ist die einprägsamste Erfahrung? Wir brauchen kleine, portable Anzeigegeräte für spezielle Anwendungsfälle (siehe Bild).

Special WikiTag

Das Ende einer Ära

Seit kurzer Zeit hat die Schneide den ersten Vertreter einer neuen Ära in der Computertechnik in Besitz: einen mechanikfreien Rechner.

Bisherige Elektronik funktionierte nie ohne einen Restbestand an Mechanik, die dann in bester Tradition auch zu den beliebtesten Verschleißteilen gehörte. Herausragendstes Beispiel waren/sind Festplatten (hier sei besonders die IBM DTLA/IC35-Todesserie genannt, die in der Schneide damals in Massen starb). Aber auch Lüfter gehören unüberhörbar zur Mechanik.

Unser neuer Rechner ist ein Hilfsserver, d.h. ein “Immer-an”-Rechner mit einer Aufgabe, die nur geringe Anforderungen stellt. Mehr zu dieser Aufgabe in den folgenden Beiträgen. Dementsprechend ist er kompakt und stromsparend konzipiert.

Ozone von vorne Ozone von der Seite

Wir entschieden uns für den kochbuchgroßen Thin-Client “Linux Via C7” der deutschen Firma Thinking Wires. Der Via C7 Prozessor ist als Nachfolger des in der Schneide vielfach eingesetzten C3 ein gerne gesehener, endlich vollständig 686-kompatibler Rechenknecht. Er lässt sich lüfterlos betreiben, so dass die Kühlung lautlos geschieht. Das passende Netzteil ist ein ebenfalls lautloses externes 65 Watt Netzteil. Die Festplatte wird durch ein sogenanntes Flash-IDE-Modul ersetzt, das bei uns mit 2GB Kapazität genug Platz für eine Ubuntu Server Installation hat.

Dieses Flash-Laufwerk ist garantiert kein Geschwindigkeitswunder (die Installation des Betriebssystems dauerte fast zwei Stunden gegenüber 10 Minuten auf einem normalen Server), aber dafür wirklich komplett lautlos.

Der ganze Rechner liefert im Betrieb nur ein leises Summen (bzw. Bruzzeln, wenn man pessimistisch formuliert), das in einem Meter Abstand nur noch hörbar ist, wenn sonst keine Geräuschquelle in der Nähe ist. Da unser Rechner direkt neben dem Code Flow-O-Meter steht und dieses entsprechend unserer Produktivität meistens läuft, ist das kein Problem.

Wir haben den Rechner “Ozone” genannt. Dabei ist uns selbst nicht klar, was der Name wirklich aussagen will:

  • Ozon: Mehr als Ozon wird durch den Rechner nicht emittiert
  • 0Sone: Das Betriebsgeräusch liegt bei fast Null Sone
  • Onoez: Mal wieder alles falsch geschrieben…

Und wofür brauchen wir diesen Rechner? Das verraten wir erst in den nächsten Beiträgen. Nur ein Tipp: Die ONOZ-Lamp gehört zum Einsatzzweck dazu.

Mein Bug, dein Bug

Historisch wertvolles TerminalIm Jahr 2002 entwickelten wir Software für eine Messapparatur, die unter anderem mit einer historisch wertvollen Datenbank über eine VT3270-Terminalemulation kommunizieren musste. Der Datenaustausch geschah über kleine Textdateien, die ausgelesen oder geschrieben wurden. Das Format der Textdateien war strikt spezifiziert und auf ein Minimum reduziert. Einige Messwerte mussten im “wissenschaftlichen Format” übergeben werden:
1.32E-01 ist gleichwertig zu 0.132

Wichtig an der Spezifikation war, dass das Format nach dem Exponententrenner “E” immer ein Vorzeichen haben musste, d.h. es wurde für den Wert 132 nicht 1.32E02, sondern 1.32E+02 erwartet.

Dummerweise hatte das damals verwendete Java 1.4.0 genau an dieser Stelle einen Bug:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4691683
Das Format +0.00000E00 erzeugt Wertrepräsentationen wie “+1.32E+02”, aber auch solche Kuriositäten wie “+1.32E-+01”.

Interessant ist dabei, dass das Vorzeichen des Formats im Exponenten wiederholt wird. Manuelles Entfernen der überflüssigen “+”-Zeichen brachte damals das gewünschte Ergebnis in die Dateien.

Dummerweise war das nicht der einzige Bug in Hinsicht auf das wissenschaftliche Formatieren in Suns DecimalFormat, so dass mit der Version Java 1.5 das Format “+0.00000E00” Wertrepräsentationen wie “+1.32E02”, aber auch Kuriositäten wie “+-1.32E02” erzeugt.

Mit der Änderung der Java-Version kam also ein vor Jahren durch Workaround behobener Fehler zurück, da jetzt (unter anderem) der Workaround zum Fehler wurde.

Was habe ich aus dieser Episode gelernt? Liefere möglichst kein spezifiziertes Format aus, das nicht mit Unit Tests vollständig abgesichert wurde. Und vor allem: Sichere jeden Bugreport, der nach außen geht, mit einem entsprechenden Test ab. Denn wenn der Bug nicht mehr da ist, wird auch der Workaround hinfällig und im schlimmsten Fall sogar selbst zum Bug.

Lethal risks of bugfree software

Bei der routinemäßigen Kontrolle unserer Continous Integration Server Hardware fanden wir heute eine tote Spinne auf dem Mainboard. Das ist sehr bedauerlich für das arme Tier, wir glauben aber zu wissen, woran sie gestorben ist: Verhungert wegen zu wenigen Bugs.

Eventuell hätte sie in einen Entwicklerrechner ziehen sollen.

It’s not a bug, it’s coolness

In alten Eclipse-Versionen wurden Anwendungen meistens über den “Run-Button” gestartet. Ein Klick und die vorher gestartete Anwendung wurde erneut gestartet. Das war an sich ganz praktisch, aber für “Code->Run Test->Run Application”-Zyklen leider unpassend.

Also erfanden das Eclipse-Team eine neue Funktionalität für den alten Knopf: Context launching. Leider wurde vergessen, dies dem Benutzer mitzuteilen. Der Knopf sieht aus wie früher, verhält sich (meistens) wie früher und hat auch sonst keine neuen Features. Nur manchmal, heimlich, wechselt der Kontext und man startet völlig unvorhergesehene Dinge.

Zuerst mal ein paar gute Nachrichten zu diesem Feature:

Damit hören die guten Nachrichten aber auch schon auf und die Probleme fangen an. Eine kleine Sammlung an Bugs zum Thema findet sich in den Links.

Das Feature wird bleiben – und damit eine meiner Meinung nach mittlere Usability-Katastrophe.

  • Alle Veteranen des “Run-Button” müssen umlernen oder die Funktion deaktivieren (anstatt es bei geeigneter Coolness bewusst zu aktivieren). Ok, das ist nur ein temporäres Problem der nächsten Monate
  • Der Kontext, und damit die “Intelligenz” im Hintergrund der Entscheidung, bleibt unsichtbar. Keine Farbe, kein Sinnbild, kein Ton. Ich bin wahrlich geübt im Umgang mit interrelationsreichen Computerprogrammen und Geräten, aber diesen Kontext habe ich nicht intuitiv erfasst.
  • Der Knopf bietet keinerlei Hinweis darauf, dass er jetzt etwas anderes tun wird als gerade eben noch. Er bietet auch keinen Hinweis darauf, was er jetzt tun wird. Schon eine leichte Umfärbung bei einem Kontextwechsel wäre zumindest ein Anfang.
  • Der Knopf funktioniert entweder mit Kontext oder ohne (im sogenannten Last-launch-Modus). Eine Art “Modus-Umschaltung” durch gedrückte Shift-Taste oder ähnlich gibt es nicht. Hier hilft nur der Weg durch die globalen Einstellungen oder das Bewusstmachen des Kontextes.

Fazit: Intention des Eclipse-Teams war die Erhöhung der Coolness der IDE. Erreicht wurde meiner Meinung nach eine Verhöhnung versierter Anwender: “Ihr habt es nicht mehr im Griff!”. Echte Coolness braucht den Überraschungsmoment nicht, um zu wirken.


Nachtrag/Ergänzung: In einem Kommentar zum verlinkten Blog-Eintrag des Eclipse-Teams wird davon geredet, dass das Feature sehr praktisch ist, wenn Eclipse im Tutor-Betrieb vor Studenten eingesetzt wird. Ich hoffe, trotz der unbestrittenen Wichtigkeit der Lehre, dass dies nicht der anvisierte bzw. hauptsächliche Einsatzzweck für Eclipse sein soll.