Posts mit dem Label Groovy werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Groovy werden angezeigt. Alle Posts anzeigen

Donnerstag, 24. Dezember 2009

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

Prime Factors Kata - First Try

This is my first try of the Prime Factors Kata. It's my first Katacast of a kata at all. I performed it with Groovy.

Stefan wrote about katas (in German) a while ago, where he described his experience as an attendee of the contest "TDD with the pros" ("TDD mit den Profis", TmdP) at the XP Days Germany 2009 in Karlsruhe. TmdP is similar to "Programming with the Stars" at Agile 2009 in Chicago, where I was an attendee of.

Stefan was in the final of TmdP with his pair partner Franziska Widmaier. Their task was to calculate all prime factors of a given number, which is the same task as in the Prime Factors Kata. Stefan and Franziska had to finish this task in less than 7 minutes - and they failed to do it in time.

Stefan and I started to work on that kata right after the XP Days ended. Our first shot was in the train from Karlsruhe back to our home town Hamburg. After that we met once via Skype and wrote each step we took during the kata. I practiced a few times per week for the last five weeks or so and showed my performance to Stefan today. He said that it'd might be time to show the result to the world, and here it is:

On Youtube:




I've also shared the Katacast on vimeo and on viddler.

My to-do list for the next try so far:
  • Use a parameterized JUnit test instead of not isolated parameters in a map
  • Use more of TextMate's shortcuts and optimize on a keystroke level
  • Find out why 63 is too big... wtf? [Update: @datenreisender found out that this is related to a bug in Groovy.]
  • [Update: @datenreisender suggested in the comments to use primefactors instead of numbers2primeFactors[number] in the assertion.]
My heartfelt thanks to Stefan, with whom it was a lot of fun preparing that kata!

Happy Christmas!

P.S.: If you want to rate my performance, then post a comment with the number 0 (very bad) to 10 (very good). This kind of rating was inspired by Micah Martin. Any additional feedback is very welcome!

[Update: Stefan Roock made a Kata Bunkai - a commented kata - for this kata. Check it out!]

Donnerstag, 17. September 2009

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

Grails on Rails


Gleisanzeiger an der Haltestelle Berliner Tor in Hamburg


Das war mal etwas anderes: Vorgestern habe ich zusammen mit meinem it-agile-Kollegen Stefan Roock (Blog, Twitter, Xing) beim ObjectForum Nord in Hamburg einen Vortrag über Grails gehalten - in der Historischen S-Bahn Hamburg.

Grails auf Rails war das, und zwar wortwörtlich. Der Inhalt der Veranstaltung handelte von it-agiles Erfahrungen mit Grails und sollte dem Publikum aufzeigen, für welche Arten von Webanwendungen sich Grails gut eignet und wo es Fallstricke erwarten kann.

In einer S-Bahn vortragen, das war für uns neu. Während der Fahrt funktioniert kein Vortrag, da es einfach durch die Fahrtgeräusche zu laut ist. Wir haben die Zuhörer an der Haltestelle Berliner Tor in Hamburg abgeholt, nach Blankenese auf ein für uns reserviertes Gleis gebracht, dort in Ruhe den Vortrag gehalten und sie dann wieder zurück zum Berliner Tor gefahren. Die ganze Aktion dauerte etwa zweieinhalb Stunden bei einer Stunde Vortrag.

(Böse Zungen munkeln, dass das eine Butterfahrt war. Das stimmt aber nicht, denn wir haben nicht eine einzige Heizdecke an die Teilnehmer ausgegeben. Ehrenwort!)

Der Vortrag selbst war auch nicht so einfach: Durch die Sitzgruppen im durch eine dünne Trennwand zweigeteilten Abteil konnten wir Kraft eigener Stimme nicht jeden Zuhörer erreichen. Die eingebaute Lautsprecheranlage war dagegen ziemlich verrauscht, so wie es das Klischee der unverständlichen Lautsprecherdurchsagen vom Schaffner passend beschreibt. Eine eigene Boxenanlage musste her - akkubetrieben, da es keinen 240-Volt-Stromanschluss in einer historischen S-Bahn gibt.

Und dann die Sache mit den Folien und dem Beamer. Kein Strom, kein Beamer. Und selbst, wenn wir Strom gehabt hätten, wohin hätten wir die Folien projizieren können? Wir haben uns dann mit Riesen-Post-Its beholfen, die sechs it-agile-Kollegen auf Stefan und mein Zurufen hin umgeblättert haben. Und trotz aller Unkenrufe - Was da nicht alles hätte schief gehen können! -  verlief die Aktion reibungslos.

Die Resonanz: Sowohl Inhalt des Vortrags wie auch die Location kamen gut an. Uns hat es sehr viel Spaß gemacht.

Ein paar Fotos haben wir auch geschossen:



Freitag, 7. August 2009

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

Beispiel für Refactoring von Beispiel für Closures

Vor ein paar Wochen hat mein Kollege Stefan Roock (Xing, Twitter) auf seinem Blog von einem "Beispiel für Closure" geschrieben. Wie so oft geht mir beim Lesen (fremden) Codes mein Das-ist-nicht-DRY-Alarm an. So auch bei Stefans Post. Es folgt ein Refactoring.

Stefan will die Laufzeit je Methode für eine Menge von Methoden messen. Die Menge hat er so bechrieben:


Ich konnte in seinem Post die Implementierung von tueA(), tueB() und tueC() nicht finden. Meine Annahme ist, dass sie ein wenig Laufzeit verbrauchen und etwas ausgeben:

Führt man nun die Menge an Methoden aus, so ist das die Ausgabe:

Stefan misst nun die Laufzeit der Methoden, und sein Output sieht (mit meiner Implementierung der Methoden) so aus:

Da ich ein Refactoring beabsichtige, darf sich das Verhalten des Codes, in diesem Falle der Output, nicht ändern.

Aber warum eigentlich Refaktorisieren? Mit Stefans Implementierung als solcher bin ich eigentlich zufrieden. Naja, da kann man noch ein Semikolon weglassen sowie eine Variable duration einführen und im GString hinterm println substituieren. Aber das ist Kleinkram, nebenbei machbar und hier kaum der Rede wert. Stefans Implementierung der Closure:

Nein, es geht mir um den Aufruf von Stefans Lösung (siehe Stefans komplette Lösung). Was muss ich tun, um die Laufzeit einer Menge von Methoden zu messen? Wo ist der Schalter, den ich einschalten muss? Stefan legt diesen Schalter um:

Seht Ihr die Redundanz? Stefan legt nicht einen Schalter um, sondern drei. Drei Mal muss er vor die Methoden timeLogged schreiben, inklusive geschweifte Klammer vor und nach der zu messenden Methode. Das ist nicht DRY.

DRY wäre es, eine Menge von Methoden einzeln zu messen. Das hier schwebt mir vor:

Und das geht. Die Closure-Magie, mit der das geht, hat Ted Naleid (Twitter, LinkedIn) in seinem Blogpost "Groovy closures make unit testing with “soft asserts” simple" ausführlich beschrieben. Hier ist meine Lösung:

Keep on DRYin', Stefan! "Bleib trocken, Stefan!" lag mir auf der Zunge, ging aber hier nun echt nicht... :-)

Links:

Samstag, 5. Juli 2008

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

Groovy und JavaScript und die Kunst, geschweifte Klammern zu setzen

Vor ein paar Jahren bin ich in ein Projekt gekommen, in dem darüber abgestimmt werden sollte, wie die Klammern in Java zu setzen seien. Es gab zwei Alternativen: den K&R-Stil und den Allman-Stil. Das Ergebnis damals war deutlich knapp. Nach einigen Wochen Gemurre programmierte aber jeder so, wie abgestimmt wurde. Es blieb der Eindruck zurück, dass sehr viel heiße Luft erzeugt und viel produktive Arbeitszeit sprichwörtlich verbrannt worden ist.

Nach hitzigen Diskussion vor der Abstimmung (vielen war "absolut klar", was denn die einzig wahre Art geschweifte Klammern zu setzen sein müsse) wurde mir damals klar, dass es eine Frage von Geschmack und Ästethik sein müsse und nicht objektiv beantwortbar sein könne, welcher Stil besser wäre als der andere. Es gab damals einfach kein rationales Argument für den einen oder den anderen Stil. Die Argumente beruhten auf Spekulation oder subjektivem Empfinden der Beteiligten.

Die Diskussion und die Entscheidung wären vermutlich anders verlaufen, wenn wir damals in Groovy oder JavaScript programmiert hätten. Dort gibt es jeweils ein Beispiel dafür, dass der Allman-Stil nicht immer durchgängig angewendet werden kann. Da der Klammersetzungs-Stil aber gerade eine einheitliche Formatierung des Quelltextes ermöglichen soll, würde eine inkonsistente Anwendung des Stils - mal soll er eingehalten werden, mal nicht - das Aus für diesen Stil bedeuten. Schon rein praktisch stelle ich es mir sehr kompliziert vor: IDEs bieten eine automatische Quelltext-Formatierung, die bei den folgenden Beispielen entsprechende Fehler einbauen würden. Keine schöne Vorstellung.

Zu den Beispielen: Das JavaScript-Beispiel steht in Douglas Crockfords "JavaScript: The Good Parts", das Groovy-Beispiel war dann nicht schwer davon abzuleiten. Hier das von mir adaptierte Beispiel in JavaScript im K&R-Stil:

var assertEquals = function(expected, actual) {
if(expected === actual) return;
alert('AssertionError! Expected: <' + expected + '>, but was <' + actual + '>');
}

var foo = function() {
return {
key: 'value'
};
}

assertEquals('value', foo().key);


Die erste Methode assertEquals ist ein Ersatz für JavaScripts Assertions-Losigkeit. assertEquals hier ist das, was man von JUnits assertEquals als Java-Entwickler kennt. Die Methode vergleicht einen erwarteten mit einem tatsächlichen Wert: Sind sie gleich, passiert nichts (ergo: Alles okay), andernfalls wird eine entsprechende Fehlermeldung als modaler Dialog ausgegeben. Dies ist noch nicht das eigentliche Beispiel, erleichtert aber die Lesbarkeit im Folgenden.

Die Methode foo gibt ein Objekt zurück. In JavaScript können Objekte literal durch geschweifte Klammern dargestellt werden. Das Objekt hat eine Instanzvariable key mit dem Wert value.

Die letzte Zeile ist die Zusicherung: Wenn foo aufgerufen wird, dann kann ich auf die Variable key zugreifen und erhalte den Wert value. So weit, so alles gut.

Nun formatiere ich die Methode foo nach dem Allman-Stil:
var foo = function()
{
return
{
key: 'value'
};
}


Es gibt eine Fehlermeldung in der Zeile mit dem Aufruf der Zusicherung: foo() has no properties, foo() hat keine Variable key. Warum?

JavaScript kennt das Konzept des Semicolon Insertion: Fehlt am Ende einer Zeile ein Semikolon, dann wird es dort von JavaScript automatisch hinzugefügt. Das ist vielfach praktisch, aber ungünstig beim Allman-Stil und dem return-Statement. Was da nun eigentlich steht, ist dies:
var foo = function()
{
return;
{
key: 'value'
};
}


JavaScript kümmert sich nicht um das, was nach dem return-Statement kommt, es wird ignoriert, ohne Fehlermeldung. Wenn wir foo() ausgeben, dann sehen wir den wahren Rückgabewert: undefined. Klar, dass undefined keine Variablen kennt.

In Groovy sieht's ähnlich aus. Dieses Beispiel ist im K&R-Stil formatiert:
def foo() {
return { ->
return 42
}
}

assert 42 == foo().call()


Die Methode foo() gibt eine Closure zurück, die, wenn aufgerufen, 42 zurückgibt. In Groovy ist das return-Statement optional: Die letzte Anweisung einer Methode wird automatisch als return-Statement benutzt. Viele Entwickler schreiben aber gerne noch das return-Keyword hin, um explizit zu machen, dass hier etwas zurückgegeben wird.

Die Zusicherung (im Gegensatz zu JavaScript hat Groovy die schon eingebaut) erwartet 42, wenn die Closure, die foo() zurück gibt, ausgeführt wird. So weit, so alles gut.

Nun formatiere ich die Methode foo nach dem Allman-Stil:
def foo()
{
return
{ ->
return 42
}
}


Es gibt eine Fehlermeldung in der Zeile mit dem Aufruf der Zusicherung: java.lang.NullPointerException: Cannot invoke method call() on null object, auf foo() kann kein .call() aufgerufen werden. Warum?

Auch in Groovy darf man die Semikolons weglassen. Und auch in Groovy wird alles nach dem ersten return-Statement ignoriert. Folglich liefert foo() den Wert null zurück, was die NullPointerException erklärt; die folgende Closure wird ohne Fehlermeldung ignoriert.

Fazit: Ich möchte hier keinen Religionskrieg um den Klammersetzungs-Stil ausrufen oder Öl ins Feuer derer gießen, die sich da bekriegen. Ich fand es nur interessant, dass der Klammersetzungs-Stil in einigen Sprachen Konsequenzen außerhalb von subjektiv empfundener Ästethik oder Benutzungsfreundlichkeit haben kann. Ich sehe diese Beispiele nicht als Argument gegen Semicolon Insertion oder (optionalen und) mehrfachen return-Statements von Groovy und JavaScript; die Vorteile dieser Eigenschaften der beiden Sprachen überwiegen die Nachteile meiner Ansicht nach deutlich.

Meine Lehre, die ich aus den Beispielen ziehe: In Groovy oder JavaScript würde ich Abstand vom Allman-Stil nehmen, weil er nicht konsistent durchgehalten werden kann.

Übrigens I: Python- und Haskell-Entwickler können wirklich froh sein, dass sie durch derartige Religionskriege nicht durch müssen; Python und Haskell ordnen Blöcke durch tiefere Einrückung unter. Eingebaute Schönheit - meinem subjektiven Empfinden nach, versteht sich ;-)

Übrigens II: Bei den Sourcen von werkannwann.de und bei denen vom Grails-Buch formatieren wir Groovy und JavaScript nach K&R mit zwei Ausnahmen:
  1. Geschweifte Klammern einzeiliger Closures oder Methoden schreiben wir mit einem Leerzeichen Abstand zwischen den geschweiften Klammern und dem Inhalt in die gleiche Zeile wie den Closure-/Methoden-Inhalt. Beispiel:
    [1, 2, 3].each{ println it }
    Im oberen Beispiel würde foo() so aussehen:
    def foo() { return { return 42 } }

    Wobei wir das return-Keyword immer dort weglassen, wo es möglich ist. Dann wird daraus:
    def foo() { { 42 } }
  2. if-, do-, while- und for-Statements schreiben wir ohne geschweifte Klammern, wenn es sich beim folgenden Block um einen Einzeiler handelt. Wenn diese Statements einen einzeiligen Block haben, dann schreiben wir ihn in die gleiche Zeile direkt nach dem Statement. Beispiel:
    if(guardCondition) return
Von beiden Ausnahmen machen wir recht häufig Gebrauch, da sowohl Groovy als auch JavaScript einen wesentlich kompakteren Code erzeugt als beispielsweise Java, und wir so auf relativ viele Einzeiler kommen.

Donnerstag, 3. Juli 2008

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

[JFS 2008] Grails-Vortrag

Vorhin habe ich auf dem Java Forum Stuttgart einen Vortrag über Grails gehalten. Ich habe die Folien online zur Verfügung gestellt:

Samstag, 26. April 2008

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

[JAX 2008] JAX Innovation Award 2008 2. Gewinner: Grails (Bericht & Fotos)

Am Abend des 23.04.2008 wurden auf der JAX in Wiesbaden die Vertreter der nominierten Projekte für den JAX Innovation Award auf die Bühne von Saal 1 gebeten. Darunter befand sich auch Guillaume Laforge, Project Lead von Groovy. Groovy gewann im letzten Jahr den JAX Innovation Award - ein Umstand, der die Chancen für Grails in diesem Jahr leider negativ beeinflusste, so munkelte man zumindest vor der Verleihung. Dennoch: Grails war dieses Jahr unter den Top Ten und alleine dieser Fakt ist schon super!

Guillaume machte eine tolle Figur, als er Grails dem Publikum vorstellte - und überraschte damit, dass er seine ersten Sätze in doch recht brauchbarem Deutsch formulierte. Weiter so, Guillaume, dann brauchst Du Dir diesen Blog bald nicht mehr übersetzen zu lassen ;-)

Die Verleihung der Preise fing bei Platz 5 an. Platz 2 und damit EUR 5000 gingen an Grails. Ein tolles Ergebnis! Herzlichen Glückwunsch an dieser Stelle an Graeme Rocher, Project Lead von Grails, und allen Grails-Comittern, -Patchern, -Doku- und Plugin-Schreibern, sowie G2One, der Firma hinter Groovy und Grails! Platz 1 ging übrigens, nach Spring im Jahre 2006 und Groovy im Jahre 2007, an dynaTrace. dyna-was? Ja, genau, haben wir uns im Publikum auch gefragt ;-)

Der Publikums-Award wurde durch Handzeichen vom Publikum noch am gleichen Abend ermittelt, unmittelbar nach der Verleihung des JAX-Innovation-Awards. Das war relativ spaßig: Außer für Grails gab's nur noch Handzeichen für GreenFire, der Open-Source-Heizungssteuerung (!) von Adam Bien. Und im Gegensatz zur Jury-Verleihung des Hauptpreises konnte ich die Abstimmung des Publikums gut nachvollziehen: Adam Bien hat wirklich eine gelungene Vorstellung von GreenFire gegeben und das Publikum in seinen Bann gezogen. Kommt noch erschwerend hinzu, dass GreenFire auf der Ökowelle reitet, Adam Bien seit Jahren Publikums-Magnet auf der JAX ist (und damit hohes Ansehen beim JAX-Publikum genießt) und GreenFires letztes Feature eine Schnittstelle zum iPhone ist. Damit schlug GreenFire problemlos Grails mit einem Verhältnis von etwa 80 zu 20 Handzeichen. Herzlichen Glückwunsch an Adam Bien und seinem GreenFire! Grails wird's verkraften, immerhin 2. Platz, sowohl beim Jury-, als auch beim Publikums-Awards. Und GreenFire nutzt massiv Groovy - ergo bleibt's in der Familie :-)

Freitag, 4. Januar 2008

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

Kata in Groovy ge-DRY-t

Neulich schrieb mir ein it-agile-Kollege...

Von: Sanitz, Sebastian (Blog) (07.12.2007)
====================================
Hallo Bernd,
zur Zeit tue ich mir doch Groovy und bald auch Grails an. Unter anderem probiere ich mich an den CodeKatas vom pragmatischen David um die Sprache richtig kennen zulernen.

Jetzt habe ich da ein paar Fragen. Meine Lösung zum Wetterproblem ist angehängt, sie funktioniert mittlerweile, ist zum Vergleich mit meinen stümperhaften Anfängen "grooviger" bzw. kleiner gemacht. Das Ergebnis sieht so aus:

Tag: 14 Spread:  2 Min: 59 Max: 61
Tag: 15 Spread: 9 Min: 55 Max: 64
Tag: 13 Spread: 11 Min: 59 Max: 70
Tag: 24 Spread: 13 Min: 77 Max: 90
Tag: 12 Spread: 15 Min: 73 Max: 88
Tag: 2 Spread: 16 Min: 63 Max: 79
Tag: 7 Spread: 16 Min: 57 Max: 73
Tag: 28 Spread: 16 Min: 68 Max: 84
Tag: 4 Spread: 18 Min: 59 Max: 77
Tag: 25 Spread: 18 Min: 72 Max: 90
Tag: 27 Spread: 19 Min: 72 Max: 91
Tag: 6 Spread: 20 Min: 61 Max: 81
Tag: 10 Spread: 20 Min: 64 Max: 84
Tag: 16 Spread: 20 Min: 59 Max: 79
Tag: 19 Spread: 20 Min: 61 Max: 81
Tag: 8 Spread: 21 Min: 54 Max: 75
Tag: 3 Spread: 22 Min: 55 Max: 77
Tag: 23 Spread: 22 Min: 68 Max: 90
Tag: 29 Spread: 22 Min: 66 Max: 88
Tag: 5 Spread: 24 Min: 66 Max: 90
Tag: 17 Spread: 24 Min: 57 Max: 81
Tag: 22 Spread: 26 Min: 64 Max: 90
Tag: 20 Spread: 27 Min: 57 Max: 84
Tag: 21 Spread: 27 Min: 59 Max: 86
Tag: 1 Spread: 29 Min: 59 Max: 88
Tag: 18 Spread: 30 Min: 52 Max: 82
Tag: 11 Spread: 32 Min: 59 Max: 91
Tag: 26 Spread: 33 Min: 64 Max: 97
Tag: 30 Spread: 45 Min: 45 Max: 90
Tag: 9 Spread: 54 Min: 32 Max: 86

Hier meine Anfänger-Fragen:
  • Kann ich mit Groovy noch einfacher ein Integer aus dem String machen, als mit Integer.valueOf? (asType wirft natürlich eine Exception...)
  • Gibt es noch eine einfachere Lösung Exemplare von WeatherData mit den Daten zu erzeugen? Meine die Zeile:
    data {{ new WeatherData(day: day, min: min, max: max)
    (Anmerkung: da gehören statt geschweifte spitze Klammern hin, aber damit kommt Blogspot nicht klar :-( )
  • Benutze im Beispiel String.format() für die Ausgabe - gibt es da was groovigeres?
  • Obwohl ich seit über zehn Jahren mit regulären Ausdrücken (früher nur in Perl) hantiere, dauert es sehr lange bis ich eine funktionierende Lösung finde. Hast Du eine schnelle Herangehensweise? Und vielleicht ein anderes Muster für die Aufgabe?
  • Hast Du für die Aufgabe eine ganz andere Lösung?
Viele Grüße - Sebastian

PS
Glaube das liegt an Groovy, man schreibt sehr viel weniger Code und
textet in Emails mehr als sonst ;-)

Von: Schiffer, Bernd (07.12.2007, 23:09 h)
====================================
Hi Sebastian.

> Hier meine Anfänger-Fragen:
> * Kann ich mit Groovy noch einfacher ein Integer aus dem String machen,
> als mit Integer.valueOf? (asType wirft natürlich eine Exception...)
'2'.toInteger()
> * Gibt es noch eine einfachere Lösung Exemplare von WeatherData mit den
> Daten zu erzeugen? Meine die Zeile:
> data {{ new WeatherData(day: day, min: min, max: max)

Nope, das wäre die einfachste mit einem impliziten Konstruktor. Wenn Du einen expliziten Konstruktor benutzt hättest, dann könntest Du über Positional Parameter einfachere WeatherDatas erzeugen:
def data = [day, min, max] as WeatherData
oder
WeatherData data = [day, min, max]
Du brauchst allerdings für Skripte dieser Kürze gar keine Klassen und Objekte, wenn Du so tolle Dinge hast wie literale Maps - später mehr.

> * Benutze im Beispiel String.format() für die Ausgabe - gibt es da was
> groovigeres?

Jein, komme ich gleich zu.

> * Obwohl ich seit über zehn Jahren mit regulären Ausdrücken (früher nur
> in Perl) hantiere, dauert es sehr lange bis ich eine funktionierende
> Lösung finde. Hast Du eine schnelle Herangehensweise? Und vielleicht ein
> anderes Muster für die Aufgabe?

Mein Muster ist ähnlich wie Deines.
Deins:
~/\s+(\d+)\D+(\d+)\D+(\d+).*/
Meins:
def number = /\W+(\d+)/
/(?m)^${number * 3}.*/
Der Unterschied: Deins ist nicht DRY. Du wiederholst zweimal \D+(\d+). Du kannst statt Deines \d+ und Deines \s+ auch ein \W+ nehmen. Dann sind sogar dreimal \D+(\d+). Groovys Slashed Strings sind GStrings, d.h. Du kannst sie substituieren per $-Schreibweise. So kannst Du die Duplikation entfernen.

Mein (?m)^ am Anfang hat mit der Art zu tun, wie ich die Daten einlese.
Deins:
def pattern = ~/\s+(\d+)\D+(\d+)\D+(\d+).*/
new File("weather_orginal.dat").each{ line ->
matcher = pattern.matcher(line);
if (matcher.matches()) {
def day = matcher.group(1)
int max = Integer.valueOf(matcher.group(2))
int min = Integer.valueOf(matcher.group(3))
...
}}
Meins:
def number = /\W+(\d+)/
new File('weather.dat')
.text
.eachMatch(/(?m)^${number * 3}.*/){
all, tag, max, min ->
...
}
(Anmerkung: Wenn man das nicht im Blog schreibt, dann ist das ein Zweizeiler.) Dein Code kompiliert übrigens nicht mit Groovy-1.5.1 (da gibt's kein file.each mehr). Abgesehen davon: Was wir eigentlich gerne hätten wäre ein file.eachLineMatch auf File, aber da es das nicht gibt, nutze ich halt die lange Version file.text.eachMatch (was um ein Zeichen länger ist ;-) ). Und dann habe ich auch die Möglichkeit, sprechender die Gruppen zu benennen mit all, tag, max, min.

Der Grund für (?m)^: ?m ist der MULTILINE-Mode (siehe JavaDoc zu Pattern). Nichts Neues, wenn man JavaRegExp kennt. Über diesen Mode wird ^ zum Beginn einer Zeile, nicht mehr zum Beginn des Strings.

Reguläre Ausdrücke ertüftel ich mir testgetrieben. Sofern es "technische" Probleme gibt, weiche ich auf die GroovyConsole aus. Mit diesem Snippet bekommst Du ganz brauchbare Aussagen darüber, welche Group was gemacht hat:
def regexp = ...
def text = ...
text.eachMatch(regexp){ println it }
> * Hast Du für die Aufgabe eine ganz andere Lösung?

Nein - drei :-)

Schau Dir diese Version an:
def number = /\W+(\d+)/
def eintraege = []
new File('weather.dat')
.text
.eachMatch(/(?m)^${number * 3}.*/){
all, tag, max, min ->
def spread = max.toInteger() - min.toInteger()
eintraege << [tag, spread, min, max] // #1
}
eintraege
.sort{ it[1] } // #3
.each{
println String.format('Tag:%3s Spread:%3s Min:%3s Max:%3s',
*(it*.toString())) // #2
}
Bei #1 erzeuge ich Einträge als Liste von Listen. In den inneren Listen sind die Werte in der Reihenfolge, wie sie von String.format gebraucht werden. Das komische Konstrukt bei #2 - *(it*.toString())) - ruft erst auf allen Werten toString() auf (ich habe ja spread als int gespeichert) um dann das Ergebnis nochmal zu spreaden (*. ist der Dot-Spread-Operator und macht aus einer Liste [a, b] eine kommaseparierte Wertefolge a, b, die man etwa in anderen Listen oder zwecks Parameterübergabe benutzen kann; hat jetzt überhaupt nichts mit dem Spread aus der Kata zu tun!), damit die Parameter für String.format() erzeugt werden. Ich kann auch schreiben it*.toString().toArray() - ist aber länger.

Diese Lösung hatte ich zuerst gebaut. Und dann fiel mir auf, dass die nicht DRY ist: Wenn Du die Reihenfolge der Spalten ändern willst, also z.B. Spread vor Tag oder so, dann musst Du an zwei völlig unterschiedlichen Stellen schrauben, nämlich an der Liste bei #1 und beim beschreibenden String bei #2. Du mußt sogar noch bei #3 etwas ändern, wenn sich Spread nicht mehr an 2. Stelle befindet. Und Du hast das Padding auf 3 gesetzt - an vier Stellen. Fazit dieser Variante: Sehr fragil, unflexibel, redundant - naja, eben nicht DRY.

Dann bin ich auf das hier gekommen:
def number = /\W+(\d+)/
def eintraege = []
new File('weather.dat')
.text
.eachMatch(/(?m)^${number * 3}.*/){
all, tag, max, min ->
def spread = max.toInteger() - min.toInteger()
eintraege << [tag:tag, spread:spread, min:min, max:max] //#1
}
eintraege
.sort{ it.spread } // #3
.each{
println it.collect{ // #2
def label = format(it.key)
def wert = it.value.toString().padLeft(3)
"$label:$wert "
}.join()
}

def format(label) {
label[0].toUpperCase() + label[1..-1]
}
Bei #1 übergebe ich jetzt keine Liste mehr, sondern eine Map (da wird bereits eine LinkedHashMap erzeugt, damit die Einträge in der entsprechenden Reihenfolge bleiben). Da habe ich zwar immer noch Redundanz zwischen Key und Value, aber dazu später mehr. Durch die Map kann ich bei #3 jetzt explizit auf den Key verweisen. Ändere ich die Reihenfolge bei #1 ist davon #3 nicht betroffen. Zu #2: Das ist jetzt die groovyfizierte Version von String.format(). Statt %3s ist der Ausdruck it.value.toString().padLeft(3) gekommen - finde ich jetzt nicht so schön, wo man doch mit %3s so eine nette DSL hat. Besser finde ich da schon format(label), denn damit kann ich mir das Label aus dem Key der Map erzeugen (und wenn Du alles lowercase haben möchtest, dann reicht auch def label = it.key - aber Du hast ja mit der Formatierung angefangen ;-) ).

DRY ist das Ding aber jetzt: Wenn ich an #1 die Reihenfolge ändere, dann zieht #2 schön mit und nichts geht in die Brüche.

Frage mich, ob DRY und String.format() geht. Geht. Hier:
eintraege
.sort{ it.spread }
.each{ // #2
def format = it.keySet().collect{
format(it) + ':%3s'
}.join(' ')
def values = it.values()*.toString()
println String.format(format, *values)
}
Hier ist jetzt nur #2 zu sehen, der Rest blieb gleich. Dachte, dass wäre simpler, als die Variante zuvor, aber wenn ich mir das jetzt so anschaue, dann "gewinnt" mein zweiter Vorschlag. Beide sind DRY, aber die zweite Variante ist IMHO verständlicher als die erste. Ist jetzt aber nur mein Bauchgefühl.

> PS
> Glaube das liegt an Groovy, man schreibt sehr viel weniger Code und
> textet in Emails mehr als sonst ;-)

Echt? Ist mir gar nicht aufgefallen ;-) Mist, Kaffee alle, muß ins Bett!

Viele Grüße,
Bernd

====================================

Die Codesnippets gibt's hier als Nicht-DRY, DRY, und String.format-DRY.

Mittwoch, 24. Oktober 2007

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

[Grails eXchange] Nachtrag: Folien und Videos

Nun haben mich schon mehrere Leser angesprochen und -geschrieben, wo sie denn der Folien der Konferenz habhaft werden können. Euch werd' ich helfen: Die Folien werden in der nächsten Zeit nach und nach online gestellt. Ihr findet sie auf den Seiten der jeweiligen Speaker; Guillaumes Folien zu Keynote und DSL-Session stehen schon online zur Verfügung.

Aber nicht nur das: Jede Veranstaltung wurde auf Video aufgezeichnet. Die werden online gestellt, sobald das Rohmaterial geschnitten wurde. Schaut einfach mal öfter auf den Speakerseiten vorbei.

Und wer's gar nicht abwarten kann: Jeder Teilnehmer hat eine CD mit den Folien aller Sessions bekommen. Die sind allerdings nicht auf dem letzten Stand; es gab da ein paar Mutige, die die Nächte vor ihren Sessions noch kräftig an den Folien gewerkelt haben. Falls also jemand diese Folien haben möchte, der möge mir eine E-Mail an bernd(dot)schiffer(at)gmail(dot)com schicken und ich sende sie Euch dann zu.

Freitag, 19. Oktober 2007

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

[Grails eXchange] Session GORM-ORM with Hibernate Demystified (Graeme Rocher)

Graeme, Project Lead von Grails, zeigt den Object-Relational Mapper in Grails (GORM, wobei G für Groovy steht). Dieses Tool ist auch separat von Grails einsetzbar. In Grails ist es einer der Hauptstützfeiler der Architektur.

Hibernate steckt unter der Haube von GORM. Anders als bei Ruby on Rails (RoR) nutzt Grails kein ActiveRecord-Pattern, um die Persistenzgeschichte zu erledigen. Grails leitet via GORM die Informationen direkt aus den Domainklassen ab. Da stecken gut durchdachte Defaulteinstellungen dahinter. Tatsächlich gibt es, sofern man nichts tweaken muss, keinen Bedarf an Mapping-Files, wie man sie in Hibernate normalerweise nutzt.

Graeme führt gerade die Vorteile von Hibernate aus und begründet damit den Einsatz in Grails. Ich spare mir das mal hier: Hibernat ist gut und daher in Grails enthalten.

Interessant ist, wie GORM das Mapping aus den Domainklassen zieht. Groovy ist dynamisch und statisch typisierbar. In Domainklassen nutzt man das statische Typisieren, um Informationen zu bekommen für den Typ der Tabellenspalte in der Datenbank.

Mit statischen Maps wie hasMany oder belongsTo steuert man die Abbildung der Assoziationen zwischen Domainklassen, zumindest was die Aggregationen angeht. Es können Sets und SortedSets benutzt werden, ebenso wie Maps und Lists.

Früher konnte man Legacy Datenbanken anbinden, indem man in Grails Mapping-Dateien einbindet, um die Domainklassen mit den Alttabellen zu verbinden. Jetzt gibt es die neue Mapping-DSL, mit der man das in der Domainklasse selbst machen kann, und zwar eben genau so viel, wie man braucht. Dort, wo man nichts angibt, fällt man zurück auf das Default-GORM-Verhalten.

GROM bietet dynamisch Methoden an den Domainklassen zur Verfügung, etwa save(). Hat man eine Aggregation etwa zwischen Author und Book, dann kann man sagen


autor.addToBooks(book)
autor.removeFromBooks(book)


Constraints, wie man sie früher entkoppelt vom Domänenmodell in der Datenbank pflegen musste, werden nun abgeleitet aus einer Deklaration im Domänenmodell. Ist das DRY oder was?! In jeder Domänenklasse kann man, naürlich via einer ausgeklügelten DSL, Constraints definieren.

Graeme zeigt Teile der oben beschriebenen Features nun live. Interessant dabei: Die Constraints beeinflussen auch die Validierung von an der Oberfläche eingegebenen Werten. Die Fehlermeldungen werden dabei aus einer message.property (normales I18n-Verhalten aus Java) angezeigt, die man zur Laufzeit ändern kann. Die zur Verfügung stehenden Validierungsmöglichkeiten sind vielfältig. Die Validierungen werden automatisch beim Speichern eines Domänenobjektes validiert. Kann man alles sehr schön schnell live erleben, wenn man sich mal eine kleine Beispielapplikation scaffolded.

Wieder zurück in den Folien zeigt Graeme die dynamichen Finder-Methoden. Hat ein Book ein en Title, dann kann man schreiben
Book.findByTitle("Harry Potter and the Goblet of Fire")


Nett: Graeme bemüht die GroovyConsole, die in Grails eingebettet ist. Damit kann man auf so ziemlich Alles, insbesondere hier auf die Domainklassen, zugreifen, und mal eben schnell etwas ausprobieren. Wird aufgerufen über grails console Wie bei Hibernate auch, kann man etwas suchen, wenn man ein Beispielobjekt zur Verfügung stellt. Und schließlich kann man auch via Hibernate-Kriterien suchen - mit dem HibernateCriteriaBuilder, der eine gute DSL dafür zur Verfügung stellt.

Alle Aktionen sind transaktional, wenn man möchte. Das wird durch Spring zur Verfügung gestellt. Das transaktionale Verhalten kann wiederum via Grails beeinflusst werden. Optimistisches Locking ist Default, kann aber via lock()-Methode umgestellt werden aufs Pessimistische Locking.

(Fast) Nichts Neues für mich; guter Vortrag. Empfehlenswert.

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

[Grails eXchange] Session: Canoo Web Test & Grails (Dierk König)

Dierk ist (einer der) der Entwickler von Canoo WebTest, Autor von GinA und Comitter von Groovy und Grails. WebTest wird für die Entwicklung funktionaler Tests verwendet (aka Akzeptanztests). Es ist Opensource, obwohl der Name (Canoo) da vielleicht fehlleitet.

Dierk zeigt zuerst mal, wie der Nicht-Grails-Webtest aussieht: eine XML-Datei, in der man Schritt für Schritt angeben kann, wie man eine Webseite bedienen möchte: Klick hier, trage dort BlaBla ein und dann verifiziere, dass im Titel danach Foo steht. Diese XML-Datei ist ein valides Ant-Skript und so führt man es auch aus.

Das Ergebnis wird in einem Report dargestellt, in dem man im Browser surfen kann, da es sich um HTML-Seiten handelt. Der Report ist sehr aussagekräftig. Lustig: es gibt da eine Auflistung der Schritte, die man im Test bereits gemacht hat. Dierk meint, wenn jemand manuell testen möchte, dann hat man es hier super aufgeschrieben und kann einem dann das sog. Storyboard geben :-)

Dierk zeigt vier Pattern beim Testen: Capture/Replay, Modelbasiertes Testen, Dategetriebenes Testen und geskriptete Automatisierung, worauf Dierk kurz eingeht. Je weiter in der Liste, desto effizienter das Pattern. Dierk mag definitiv keine Capture/Replay-Tools ("the least cost-effective way of test automation"!).

Typische Projekte werden vorgestellt und die Strukturen hinter einem Webtest. Dierk erzählt davon, dass er am Ende eines Projektes, dass er mit WebTests versieht, bei 5000-7000 Tests landet! 5 bis 7 Kilo!

Zu den Zusicherungen meint Dierk, dass man sie so spezifisch wie nötig und so "loose" wie möglich definieren sollte. Wie wahr! Er favorisiert XPath für die Zusicherungen, um sich die zu untersuchenden Elemente herauszupicken. Dabei macht Dierk anhand eines Beispieles deutlich, wie man schlechte und gute Ausdrücke unterscheidet.

Auf der Webseite ist eine sehr gute Dokumentation zu sehen - kann ich bestätigen, die ist wirklich super!

Wie wird nun WebTest groovyfiziert? Erstmal zeigt Dierk, wie man Groovy per Ant-Task in einem Ant-File einbinden kann, um feine Veränderungen in z.B. der Konfiguration zu machen. Einfach scheint auch das Einfügen eines neu erstellten Schrittes (Step) zu sein. Dierk zeigt da gerade noch mehr interessanten Kram: Er erweitert XPath um eine neue Funktion mit Groovy. Abgefahren :-)

Nun aber kommt endlich die DSL, die man aus Grails auch kennt - keine spitzen Klammern mehr, willkommen in der Curly-Braces-World! Im Endeffekt ist das eine 1-zu-1-Abbildung von XML nach Groovy.

Dierk setzt hin sich zur Live-Demo. Übrigens der erste Speaker, der an einem PC arbeitet. Alle seine Vorgänger, die ich hier erlebt habe, brachten einen Mac mit. Egal, Details.

Juchu, Dierk macht TDD. Naja, so fast: er erzeugt die Domainklasse, ohne die Tests vorher rot laufen zu lassen (die ja noch nicht da sind). Aber das bekomme ich gleich aufs Brot geschmiert, indem er dem Publikum erläutert, dass ich das getan hätte. Puh, TDD-Ehre gerettet :-)

Dierk erstellt also eine Domain-Class, danach generiert er das Scaffolding und den Webtest hierzu und läßt das ganze Laufen per Grails. Es poppt eine Webseite mit dem Report auf. Der generierte Webtest beeinhaltet schon rudimentäre Tests für die CRUD-Methoden.

Cool: in dem Report kann man mitlerweile wie mit dem Daumenkino durch die Schritte blättern, die der Test durchlaufen ist. Tolles Feature, wenn man rote Tests hat!

Genial: Es gibt einen WebTest-Rekorder, den man in Firefox einbinden kann. Wow, das Tool rockt total! Schaut Euch das mal an! Und schaut Euch auch (und ganz besonders) die Warnung im roten Rahmen an. Darauf geht Dierk gerade in den weiteren Folien ein. Kann ich ganz dick unterstreichen, seine Ausführungen.

So schaut übrigens ein typischer Test aus:


invoke(description: "Get the page: Google", url: "http://www.google.de/")
invoke(url: "http://www.google.de/")
setInputField(name: "q", value: "Groovy")
clickButton(label: "Google-Suche")
verifyTitle(description: "Verify page's title", text: "Groovy - Google-Suche")


Toller Vortrag (bin noch nie enttäuscht worden, wenn ich zu einem Vortrag von Dierk gegangen bin). Sehr empfehlenswert.

Donnerstag, 18. Oktober 2007

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

[Grails eXchange] Session Dynamic Groovy: Meta Magic (Graeme Rocher)

Graeme, Project Lead von Grails, gibt sein Bestes zum Thema MOP (Meta Object Protocoll). Er gibt eine kleine Einführung in Groovys dynamische und gleichzeitig auch statische Typisierung. Dann geht's gleich los mit einer Rundreise in der Groovy-MOP-API: MOP Hooks, Categories, ExpandoMetaClass.

MOP Hooks sind invokeMethod, methodMissing, get/setProperty und propertyMissing. Diese Methoden sind jeweils an einer Klasse zu überschreiben, will man das Verhalten dieser Klasse auf der Metaebene beeinflussen. Graeme greift jetzt zur Tastatur und schreibt ein Beispiel.

class XmlBuilder {
def invokeMethod(String name, args) {
if(name == 'text') {
println args[0]
} else {
println "<$name>"
def callable = args[0]
callable.delegate = this
callable()
println ""
}
}
}

html = new XmlBuilder()

html.html {
head {
title {
text "This is a Test"
}
}
body {
ul {
li {
text "Groovy is great!"
}
li {
text "Grails rocks!"
}
}
}
}



So schnell kommt man zu einem kleinen HTML-File :-) Graeme fügt dann noch das Feature "Links" dem Skript hinzu, also das Zurechtkommen mit Attributen in den Tags.

Jetzt kommt die ExpandoMetaClass unters Mikroskop. Methoden und Properties können on-the-fly hinzugefügt werden. Statische Methoden und Konstruktoren sind auch kein Problem mehr. Also sehr einfach.

Graeme spricht über Meta Patterns. Strings können als Methodennamen benutzt und dynamisch aufgerufen werden. Caching ist ein weiteres Pattern: wenn eine neue Methode aufgerufen wird, die vorher nicht bekannt war, dann wird sie erzeugt, Inhalt hinzugefügt und dann ausgeführt. Das ist relativ teuer von der Performance her. Hier kann man einen Cache einführen, der die Methode nachschlägt und nur dann erzeugt, wenn sie noch nicht existiert hat (Hookmethode methodMissing wird hier benutzt). Davon wird in Grails Gebrauch gemacht, z.B. bei den Codecs. Ziemlich clever gemacht, schaut mal bei Erscheinen in die Folien für Codebeispiele. "Intercept, Synch, Cache, Invoke" ist das Pattern insgesamt, denn Groovy läuft auf der Multithreaded JVM, und da ExpandoMetaClass mutable ist, muss man eben entsprechend synchronisieren - und zwar in eben genau der Reihenfolge intercept, synch, cache, invoke.

Guter Code, nette Beispiele, Einsicht in Grails - was will man mehr :-) Empfehlenswert.

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

[Grails eXchange] Panel Discussion (Grame Rocher, Guillaume Laforge, Dierk König, Scott Davis)

Das sollte jetzt mal eine interaktive Session werden - und hochkarätig, haben sich doch da vorne große Namen niedergelassen: Graeme Rocher, Project Lead des Grails-Projektes; Guillaume Laforge, Project Lead des Groovy-Projektes; Dierk König, Groovy- und Grails-Comitter und Autor von GinA; Scott Davis, Entwickler von aboutgroovy.org.

Inwiefern sei Grails mehr als ein Webframework? Graeme hatte soetwas bei der gestrigen Keynote gesagt. Graeme erklärt, dass Grails viele Dinge beinhaltet, die man auch außerhalb von Grails sehr gut einsetzen kann, beispielsweise GORM oder SpringBuilder.

Wie bringt man Javaentwickler das Arbeiten mit Groovy bei? Einerseits kann man (fast) jedes Javaprogramm auch in Groovy ausführen und dann Stück für Stück groovyfizieren. Die Lernkurve ist zudem sehr günstig. In Grails läßt sich viel arbeiten, ohne allzu tief in Groovy einzutauchen. Man muß nicht alles wissen, was hinter den Kulissen passiert, z.B. bei den Buildern. Groovy ist zudem Java und hat daher auch den gleichen Mindshare. DSLs sind ein weiteres Mittel, um die Benutzbarkeit von Grails einfach zu halten. Dierk weißt darauf hin, dass Javaentwickler meist Probleme mit der Magic haben. Dem kann ich zustimmen.

Noch zu den DSLs: Graeme ist stolz drauf, dass bislang Grails' DSLs immer noch ohne Annotations auskommen :-)

Reloading von Grails wird angesprochen und gelobt. Graeme meint, dass war eines der hartesten Implementierungen innerhalb von Grails, weil es extrem schwierig sei. Eine JVM lädt normalerweise eine Klasse - und gibt sie nicht mehr frei. Das im Hinterkopf habend erklärt, warum Reloading innerhalb eines Webcontainers nicht so einfach ist, was aber nichts desto trotz gemanaged wurde von Grails.

Warum sollte man Groovy nehmen, wenn man auch Javascript hätte nehmen können? Kurz: Weil Groovy die bessere Syntax hat, demnach ausdrucksfähiger ist. Als Beispiel werden Closures ausgeführt, die bei Javascript viel umfangreicher ausgedrückt werden müssen als in Groovy. Allerdings wird auch darauf hingewiesen, dass immer auch der Kontext der Anwendung und der Entwickler in Betracht gezogen werden muss. Grame meint, dass Javascript ganz nett sei, jedoch nicht so mit Liebe auf den ersten Blick bei den Entwicklern daherkomt. Es sei etwas, an das man sich langsam gewöhnt und zu schätzen lernt. Dierk wirft ein, dass man aus Sicherheitsgründen doch eher eine Sandbox haben möchte - die Javascript so nicht bieten kann. Scott spricht sich gegen Javascript aus, weil es außer den ersten vier Buchstaben nicht viel gemein hat mit Java.


G2One ist gegründet worden. Inwiefern wird das die Groov-&-Grails-Welt beeinflussen? Die Community wird davon profitieren, sei es im besseren Marketing, in der besseren Dokumentation, der beschleunigten Entwicklung. Es werden vergleiche angestellt zwischen G2One und Interface12 (Spring) oder RedHat, Suse, Novell (Linux). G2One wird weiterhin die Community brauchen und wird diese auf keinen Fall ersetzen.

Die Rolle von Sun bei Groovy wird besprochen. Nichts Neues: Einerseits ist Sun interessiert in Groovy (wie in dynamische Sprachen generell), andererseits investiert Sun auch viel Ruby. Es scheint weiterhin ein spannendes Thema zu sein.

Und natürlich viel Kleinkram, den ich nicht mitschreibe(n möchte).

Nett, nichts dolles.

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

[Grails eXchange] Nach dem ersten Drittel

Da ich gerade nur noch das Ende der Keynote von Scott Davis, Macher von und hinter aboutgroovy.org, gesehen habe (blöde Zeitzonenumstellung :-( ), gebe ich mal kurz einen Zwischenbericht ab:

Das erste Drittel ist geschafft und es macht sehr viel Spaß hier. Es ist immer wieder schön, auf solchen Konferenzen alte Bekannte wiederzutreffen und neue Bekanntschaften zu schließen. Die Umgebung hier ist auch super: das Barbican Center ist ein großes Entertainment-Ding (Theater, Kino, Konferenzen) in einer riesige Wohnanlage. Die Räume der Konferenz sind zwar weit verteilt, aber sowohl von der Einrichtung als auch von der Akustik super. Sehr nett: man sitzt in den Pausen bei Kaffee und Kuchen in einem tropischen Garten mitten in dem Barbican Center und kann die Kois im Teich streicheln :-)

Ansonsten ist das Publikum kleiner, als erwartet (ich schätze mal so an die 150 Leute), aber hat viel Ahnun und ist sehr euphorisch. Es sind auch relativ viele Leute mit Jetlag aus den USA hier; Jeff Brown hat bei seinem Vortrag bei so ziemlich jeder Gelegenheit seine 36-Stunden-Wachphase als Erklärung für Mißgeschicke und Versprecher hingehalten. Glen Smith, Macher von groovyblogs.org, hat 33 Stunden Anreise aus Down Under auf sich genommen - und ist fit wie ein Turnschuh.

So, gleich geht die nächste Veranstaltung los und ich will mir noch einen Kaffee besorgen. Viele Grüße aus London!

Mittwoch, 17. Oktober 2007

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

[Grails eXchange] Session Test Driven Development with Groovy & Grails (Jeff Brown)

Jeff Brown, einer der sieben Groovy Grails Core Comitter, fängt an mit den Herausforderungen und den Benefits des Testens dynamischer Sprachen: Kein Compiler, wenig Tool-Support und unbekannte Dinge zur Compile-Zeit bzw. sehr testbare dynamische Sprachen, einfaches Testen dynamischer Sprachen und dem Zwang, dass man das macht, was man eh tun sollte. Starke Worte, dann mal los.

In Groovy soll man schnell reinkomen, wenn man Groovy testet. Groovy unterstützt Testen unter anderem dadurch, dass es einen GroovyTestCase anbietet und einige zusätzliche Assertions bereitstellt. Dieses Unit-Tests sind ähnlich wie Java-Unit-Tests vielfältig ausführbar.

Code Coverage Tools ist das nächste Thema: Cobertura, EMMA und Clover werden genannt, wobei Cobertura auch für Groovy funktioniert.

Expandos werden gezeigt als Alles-Testbar-Machen-Wunderwaffe in Zusammenspiel mit Duck-Typing. So wird isoliertes Testen möglich. Mocks und Stubs werden in Groovy bereitgestellt und vereinfachen ebenfalls das isolierte Testen (oder ermöglichen es in vielen Fällen sogar erst).

Enttäuschend: Es geht nur ums Testen, nicht ums Design oder gar ums Treiben des Designs.

Der Unterschied zwischen Unit- und Integrationstests wird diskutiert. Grails unterscheidet ebenfalls zwischen diesen beiden. Jeff zeigt, wie er eine Domain-Klasse in Grails integrativ tested. Endlich: Er erläutert den TDD-Zyklus und kommt auch auf Refactoring zu sprechen - für etwa 20 Sekunden :-(

Und wir sind bei den Functional Tests, also den Akzeptanztests. Hier bringt Jeff Selenium und Canoo WebTest ins Spiel. WebtTest rocks! Insbesondere mit der tollen DSL, die Grails da noch drüberstülpt.

Naja, nich' so pralle. Es ging um Tools und ums Testen - nicht so das, was ich hören wollte. Aber ich bin wahrscheinlich schon zu betriebsblind mit meinen TDD-Augen. Es kam aber ganz sicher nicht das Agile Feeling rüber, dass ich erwarten würde in einer TDD-Session.

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

[Grails eXchange] Session Domain Specific Languages in Groovy (Venkat Subramaniam)

Venkat Subramaniam ein weiteres Mal für heute. Diesmal: DSLs.

Venkat geht auf den Unterschied von internal und external DSLs ein. Groovy ermöglicht internal DSLs. Venkat betont die Wichtigkeite der Kontextsinsitivität ("Two Venti Latte with two Shot Expresso" means Coffee at Starbucks aka the Starbucks DSL).

Fluent Interface beschreibt Venkat etwas anders, als ich es bislang gehört habe und selbst beschreiben würde. Für ihn sind alle DSLs, auch die Builder in Grails, Fluent Interfaces.

Eine Pizzabestellung wird flüssig gemacht, indem alle Setter das Objekt selbst zurückgeben. Venkat entwickelt das Beispiel weiter: ein Setter gibt nicht sich selbst zurück, sondern die Zeit, die die Bestellung bis zur Auslieferung benötigen wird. Hier benutzt Venkat auf clevere Weise Closures.

Jetzt kommen die Builder ins Spiel. Venkat demonstriert die Power des MarkupBuilders, um XML zu erzeugen. Er spielt ein wenig mit MOP rum, und kommt dabei durcheinander mit Ruby (er erzeugt zum Beispiel eine Klasse test.rb) - interessanter Marketingeffekt, muss ich mir merken :-)

Venkat demonstiert noch ein weiteres Beispiel:


players 'Scott', 'Venkat', 'Neal'

Scott 7
Venkat 5
Neal 8

printScores

Das ist Groovy-Code! Wie macht er das? So:

printScores = [:]

def players(Object[] player) {
player.each{ printScores."$it" = 0 }
}

def invokeMethod(String name, args) {
printScores[name] = args[0]
}

Sehr schön!

Dann gibt's ein größeres Beispiel, mit dem er folgende Syntax als DSL etablieren kann:

2.days.ago.at(4:30)

Zuerst zeigt er das Ganze mit Categories, danach mit der ExpandoMetaClass.

Auf IntelliJs MPS sollte man ein Auge halten, meint Venkat.

Tolle Session!

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

[Grails eXchange] Session A Groovy Build System with Gant (Russel Winder)

Russel Winder zeichnet verantwortlich für Gant, das Pendant zu Ant und/oder Maven in Groovy. Grails macht reichlich Gebrauch von Gant: Alle Skripte wie etwa create-domain-class sind in Gant geschrieben.

Russel vergleicht Gant mit Rant/Rake, Ant, Maven, Scont und anderen Build-Sprachen. Seine Meinung ist, dass Gant, Rant (Ruby) und Scont (Python) werden die Gewinner sein in der Evolution der Build-Sprachen. Beispielsweise sind Sie internal DSLs, während Ant und Maven lediglich external sind, was Gant/Rant/Scont entsprechende Vorteile gibt.

Probleme mit Ant: Russel präsentiert eine Folie, auf der "Low level", Too declarative" und "No programmable target generation steht", und diese Punkte sind verteilt unter sechs Punkten, die da "XML" heißen. Man gewinnt den Eindruck, Russel mag kein XML. Laut Russel ist XML gut, um Daten zu repräsentieren, aber Ant und Maven repräsentieren eben nicht nur Daten, sondern eine komplette Build-Spezifikation. Allerdings wird Maven gelobt für seine Projektstruktur, welche als Standard daherkommt für alle Mavenprojekte.

Gant wird vorgestellt an einem Beispiel. Es geht um eine Javaprogramm: Hello World. Es ist wirklich nur eine Klasse mit einer Main-Methode, die den bekannten String ausgibt. Jetzt zeigt Russel die Build-Spezifikation in Ant auf einer Folie, allerdings schon arg gequetscht, so viele Klammern sind da drin. Es sind nur drei Targets: compile, test und clean. Dann komen vier Seiten Maven: Wahnsinn, was Maven so alles haben möchte (unter anderem jede Menge Zeugs über denjenigen, der für das Build-Skript verantwortlich ist, einschließlich der E-Mail-Adresse! "Just to blame somebody if the stuff not builds!"). Es scheint da wenig Default-Einstellungen zu geben; vieles muss explizit gemacht werden. So muss der Compilelevel (1.6) angegeben werden. Nee, sieht nicht gut aus, Michael ;-) Dann kommt Gant: auch eine Seite, allerdings ist die Schrift doppelt so groß wie bei Ant.

Das nächste Beispiel ist ziemlich cool: Das Gant-Skript stellt auf eindrucksvolle Weise dynamisch (!) Targets her. Alle LaTeX-Files aus einem bestimmten Verzeichnis können nach PDF übersetzt werden, da jeweils ein Target für ein File bereit gestellt werden. Das kann man nicht mit Ant schaffen. Auch nett: durch GStrings kann man einfach aussagekräftige Beschreibungen von Targets erstellen. Schonmal versucht, in einer Ant-Description eines Targets eine Variable auszuwerten, damit's sprechender wird? Viel Spaß damit...

He, Stefan, das will ich mir mal genauer anschauen für unser Buch. Ich wußte bislang nicht, dass Gant auch mit LaTeX kann, sogar ein eigenes Package dafür besitzt. Will Russel mal nach der Session drauf ansprechen.

Russel operiert da vorne gerade auf einem Uralt-PC mit Linux, weil sein Nagelneu-PC nicht mit dem Uralt-Beamer hier im Raum spricht. Es ist alles improvisiert, aber Russel macht eine gute Figur: Emacs-Hacker, wie er im Buche steht :-)

Zuletzt geht Russel auf die Einsatzmöglichkeiten von Gant ein: Ant zu ersetzen, dafür ist Gant gemacht worden, und Ant mit Gant zu ersetzen sei ein No-Brainer. Maven mit Gant zu ersetzen ist schon etwas schwieriger, aber möglich. Er geht da gerade näher drauf ein, aber ich verstehe nichts von Maven und damit auch nicht, wie das mit Gant gehen soll. Was ich mitbekomme habe ist, dass Gant eigene Maven-Targets mitbringt und so die Migration relativ einfach sein soll.

Netter Vortrag. Brachte mich auf Ideen. Gant, auf jeden Fall einen tiefergehenden Blick wert, auch für Java-Projekte!

Dienstag, 16. Oktober 2007

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

[Grails eXchange] Keynote Guillaume Laforge

Es sind etwa 150 Leute hier im Kino des Barbican-Centers in London und hören zu, wie Guillaume, Project Lead des Groovy-Projektes, eine Zeitleiste zeigt, die die Entwicklung von Groovy darstellt ("Wie alles begann"). Er erzählt, wie er die Leitung übernommen hat im Groovy-Projekt, als das Projekt 2004 fast tot war. Stimmt, erst Anfang 2007 ist Groovy in der Version 1.0 herausgekommen - Groovy ist noch so jung! Weiter geht's mit der Auflistung der einzelnen Entwicklerkonferenzen (DevCon#1 bis #4).

Die Zeitleiste endet mit dieser Konferenz - und mit der Gründung der ersten Firma, die sich alleine um die Belange von Grooy und Grails kümmern wird: G2One. Graeme Rocher, Project Lead des Grails-Projektes. und Guillaume sind die Gründer. Guillaume hat das Logo gemacht. Die Firma berät, trainiert und schult an Groovy und Grails interessierte und entwickelt die Sprache, das Framework und spezielle Erweiterungen für Drittfirmen. Mal schauen, wie sich das entwickelt. Interessant: die arbeiten alle von zu Hause aus.

Werbung für Groovy: zig Sessions auf zig Konferenzen, zig Downloads, zig Mailinglisttraffic etc. pp. Es gibt bereits dutzende von Büchern zu Groovy, und das populärste, GinA von Dierk König, ist bereits ins Deutsche übersetzt worden. Groovy gewann den JAX-Innovation-Award. Groovy wird in zig Firmen eingesetzt, prominentes Beispiel: 50 KiloLOC bei Mutual of Omaha (US Fortune 500), ein Versicherer, bei dem Groovy zur Risikoberechnung eingesetzt wird.

Man kann hier auch gerade Buzzwordbingo spielen: DSLs, Java, Groovy, Grails, Big Player, Scripting, ...

Es werden Firmen vorgestellt (Big Player), die Groovy nutzen: Oracle, IBM, Sun, JBoss, JetBrains. Weiter geht's mit dem Einsatz von Groovy im Enterprisebereich: Groovy verträgt sich gut mit Java, läßt sich einfach in Javaanwendungen integrieren.

Neuigkeiten in Groovy 1.1 werden vorgestellt: Annotations, Generics, Enums, Verbesserungen bei der Metaprogrammierung, Performancesteigerungen - und die alte for-Schleife :-) Groovy ist übrigens momentan die einzige dynamische Programmiersprache, die Java 5-Features unterstützt.

Hihi: Guillaume zeigt kurz das Eclipse-Plugin für Groovy ("Nice.") - und dann JetGroovy, das Plugin für IntelliJIDEA ("Great!!"). Was für ein Unterschied, wenn man nur jeweils einen Screenshot sieht!

Es war eine Bestandsaufnahme und ein verdientes Schulterklopfen.

Samstag, 29. September 2007

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

Semi-Automatische Folien mit Groovy

Letzte Woche habe ich eine dreitägige Grails-Schulung gegeben. Ziel dieser Schulung war, dass die Teilnehmer einfache Webanwendungen nach der Schulung selbst schreiben können. Es ist wichtig, dass die Teilnehmer zum einen die Grundlagen von Grails verstehen und zum anderen wissen, wo und wie sie den Rest selbst herausfinden können. Zu den Grundlagen zählt z.B. das Wissen um das Model-View-Controller-Pattern (MVC) und wie man es in Grails benutzt, aber auch natürlich Groovy, denn in Grails macht man in der Regel häufig Gebrauch davon. Spätestens, wenn man mehr Informationen über Grails haben möchte, hilft die Sourcecodeexegese, wobei man hier an Groovy nicht mehr vorbeikommt. Daher gliedert sich die Schulung auch in einen Teil Groovy (der erste Tag) und einen Teil Grails (die verbleibenden zwei Tage).

Natürlich kann man an einem Tag nur einen kleinen Teil von Groovy vermitteln, etwa die häufigsten Sprachfeatures wie Closures und Operator-Overloading sowie Teile des GDKs, also der Groovy-API. In der Vorbereitung dieser Schulung habe ich also Grails und Grailsanwendungen durchforstet nach Groovy-Eigenschaften, die der gemeine Grailsentwickler kennen sollte. Und das ist eine ganze Menge - zumindest, wenn man mehr machen möchte als Scaffolding ;-)

Wie vermittelt man das notwendige Wissen um Groovy, wenn man als Teilnehmer Tag 2 und 3 der Schulung überstehen möchte? Ein Weg wäre, einen reinen Theorievortrag zu halten und die Groovy-Spec quasi in Folien zu gießen - aber das wäre langweilig, für mich als Trainer, beim Vorbereiten der Schulung und dem Vortragen der Folien, und für die Teilnehmer sowieso. Außerdem hat das wenig Praxisbezug, was die Transferleistung erhöht, das Gelernte in Grails umzusetzen.

Dierk König und Co-Autoren machen gute Wissensvermittlung in GinA vor: Beispiele noch und nöcher! Daran habe ich mir ein Beispiel genommen und die Präsentation für Tag 1 fast ausschließlich über kleine und überschaubare Codeschnipsel gestaltet. Dabei steht auf den Folien außer der Folie kein weiterer Text, nur Code. Was es zu dem jeweiligen Beispiel zu sagen gab, habe ich gesagt. So sind etwa 90 Folien mit Code zustandegekommen, die zusammen mit Übungen den ersten Tag der Schulung in einen Workshop verwandelten. So sieht eine Beispielfolie aus:
Wer hat schon Lust, 90 mal Code auf Folien zu schreiben? Typischerweise schreibt man diese Codeschnipsel in einem Editor, wo man ihn auf Funktion prüfen kann, und copy-paste-d ihn dann nach Kraftpunkt, einschließlich Syntaxhighlighting. Dieses Verfahren impliziert, dass ich pro Folie eine Datei mit dem entsprechenden Code anlege. So weit, so langweilig, so naja.

Der Haken ist der, dass der Code sich ändern kann! So aus dem Bauch heraus würde ich schätzen, dass ich Foliencode pro Folie etwa drei Mal ändere im Laufe der Vorbereitung einer Präsentation. Bald kommt Groovy 1.1 raus, dann gibt's auch wieder haufenweise Verbesserungen, die ich in den Folien ändern muss. Und schließlich mache ich Fehler, und ein Reviewer (oder aufmerksamer Schulungs-Teilnehmer) hat immer Korrektur- und Verbesserungsvorschläge.

Änderungen ziehen mit jenem manuellen Verfahren Probleme nach sich: Wie halte ich die Folien synchron zu den Dateien mit den Codeschnipseln? Nur manuell, und damit wird's stupide und fehleranfällig: Ich möchte an einer Folie etwas im Code ändern, also suche ich mir die entsprechende Datei raus, ändere und überprüfe den Code in der Datei und dann copy-paste ich den Code wieder in die Folie.

Nee, das macht keinen Spaß, ist unökonomisch (die vielen manuellen Schritte, immer und immer wieder), fehleranfällig (was dabei alles schief gehen kann) und überhaupt total ungroovy. Ich möchte die Synchronisation automatisieren. Außerdem möchte ich die Schnipsel automatisiert testen können. Und schließlich möchte ich die Schnipsel klein halten: Als brauchbar haben sich maximal 55 Zeichen pro Zeile und maximal 15 Zeilen pro Folie erwiesen. Da läuft man ohne Hilfe schnell aus dem Folienrahmen, aber merkt das erst nach dem Copy-Paste-Vorgang, also zu spät. Das ist vielleicht ein Gefummel, kann ich Euch sagen!

Wie automatisiere ich das nun? Naiver erster Versuch: Textdatei mit Groovy-Skript in Kraftpunkt als Verknüpfung referenzieren. Geht aber nicht, denn Kraftpunkt kann den Text nur importieren, was den Bezug zur Datei verloren gehen läßt. OpenOffice ist da keinen Deut besser. Wenn's doch gehen sollte, hab ich's nicht hinbekommen. Und außerdem gibt's mit diesem Verfahren kein Syntaxhighlighting, und ich will niemandem 90 Folien voll Code ohne Farben zumuten.

Ich hab's dann doch geschafft, und so sieht der Weg aus:


  1. Ich erstelle ein normales Groovyscript mit einem Codeschnipsel drin, z.B. für die Fälle bei der Groovy-Truth.

  2. Dann lasse ich ein Magic-Build-Groovy-Skript laufen und erhalte eine Grafik im PNG-Format, die den gleichen Namen hat wie das entsprechende Skript.

  3. Diese Grafik verknüpfe ich in Kraftpunkt. Fertig.


Wenn ich jetzt den Codeschnipsel ändern möchte, dann ändere ich das entsprechende Groovy-Skript, werfe den Magic-Build-Vorgang an und mehr nicht: Kraftpunkt merkt die Veränderung und aktualisiert die Folien entsprechend.

Aber so richtig interessant wird's, wenn man bedenkt, was da eigentlich passiert: Das Magic-Build-Groovy-Skript durchforstet ein Verzeichnis nach Groovy-Dateien, den Codeschnipseln aus der Folie. Diese werden gelesen, volumengeprüft, übersetzt und evaluiert, also intern übersetzt. Hätten meine Schnipsel zu lange Zeilen oder zuviele davon, dann würde ich das bei der Methodenprüfung merken. Gäbe es Compile-Fehler, dann würde ich das beim Übersetzen merken. Wären meine Inlinetests (die vielen asserts) kaputt, dann würde ich das beim Evaluieren merken. Rundumsorglos abgesichert :-) Schließlich werden aus den Textdateien png-Grafiken generiert und diese in ein anderes Verzeichnis geschrieben.

Wie's funktioniert zeigt die Power von Groovy: das Lesen der Dateien ist ein simples new File('pfad/zum/skript.groovy').text. Die Volumenprüfung erfolgt ebenfalls im Skript mit Groovy (ein paar mehr Codezeilen, aber sehr überschaubar). Das übersetzen und evaluieren schafft man wieder mit einem Einzeiler:
evaluate(skriptAlsString)

Den Teil mit dem Bildgenerieren habe ich dann wieder in Java geschrieben und vom Magic-Build-Groovy-Skript aus aufgerufen. Beim Bildermalen gibt's fast keine Logik, sondern nur viele API-Calls gegen Javas AWT, wobei Codecompletion doch recht praktisch ist, was in Java eben noch besser geht als in Groovy. Toll ist, dass ich einfach wechseln kann, wenn ich das möchte, dank Groovy und dessen grandioser Interaktion mit Java.

Das Syntaxhighlighting erfolgt auch noch in Java (selbstgeschrieben), aber das möchte ich nach Groovy portieren vor der nächsten Schulung - es wäre dort einfacher zu schreiben und weiterzuentwickeln. Da ich von Java aus auch Groovy aufrufen kann, mache ich mir auch keine Sorgen, dass ich damit Probleme bekommen könnte :-)

Der aufmerksame Leser wird auf der Folie weiter oben diese Zeile bemerkt haben:
assert new Bar() && !null

Wo kommt denn da das Bar her? Wie kann denn das übersetzt werden? Das passiert mit einem kleinen Trick. Das Skript hierzu sieht so aus:
assert new Bar() && !null
/* ### */
class Bar {}

Bei der Evaluierung wird das komplette Skript betrachtet. Daher gibt's keine Fehler aufgrund desssen, dass die Klasse Bar nicht hätte gefunden werden können. Die drei Rauten (###) geben dem Skript allerdings an, diesen Kommentar und alles Nachfolgende nicht in das Bild zu schreiben. Ähnliches gibt's auch mit drei Pfeilen nach oben (^^^), was mir Code vor dem Skript aus Bildern ausblendet. So einfach ist ein SetUp und TearDown selbstgeschrieben.

Der Nachteil bei diesem Verfahren ist, dass die Teilnehmer keinen Code aus den Folien kopieren können, um ihn mal eben in der GroovyConsole auszuprobieren. Da die Codeschnipsel aber auch nicht groß sind, ist das nicht so schlimm. Schlimmer finde ich, dass die Teilnehmer nicht digital suchen können in den Folien: es sind eben Bilder, kein Text.

Trotzdem, diese Nachteile überwiegen bei Weitem nicht die Vorteile, die sich mit diesem Verfahren ergeben: automatische Synchronisation, automatischer Test (Übersetzen und Inline-Tests), Syntaxhighlighting und Volumenprüfung.

Ausbaufähig wäre das ganze allerdings noch: Ich muss immer noch nach dem entsprechenden Groovy-Skript für eine Folie suchen. Dabei behelfe ich mir zwar momentan mit einer Namenskonvention, aber das Wahre ist das auch noch nicht (es sei denn, man hätte ein automatisches Rename-Refactoring für Skripte und Folien - ich bin aber auch verwöhnt... ;-) ) Und eine neue Folie muss ich immer noch selbst anlegen mit einem Bild und einer Überschrift.

Ich hab mich in Groovys Scriptom immer noch nicht eingearbeitet (siehe auch GinA S. 546ff.), aber ich hoffe, das Folgende damit tun zu können:

  • Zu einem Verzeichnis mit png-Bildern wird pro Bild eine Folie mit einem bestimmten Layout angelegt. In diese Folie wird das Bild eingetragen als Verknüpfung und der Name des Bildes als Überschrift (CamelCase.png wird dann zur Überschrift CAMEL CASE).

  • Gibt es eine Überschrift, die nicht zu einer Bilddatei passt, dann wird die Folie gelöscht.

  • Gibt es eine Bilddatei, die nicht zu einer Überschrift gehört, dann wird eine neue Folie angelegt.

  • Gibt es genau eine Folie, zu der es keine Bilddatei gibt, und gibt es genau eine Bilddatei, zu der es keine Folie gibt, dann wird an der Stelle der bilddateilosen Folie eine neue Folie mit dem folienlosen Bild erzeugt. (Rename-Refactoring!!).



Bin mal gespannt, ob das mit Scriptom zu schaffen ist. Bin dankbar für jeden hilfreichen Hinweis, wie man mit Scriptom Kraftpunkt-Präsentationen manipuliert.

Schamlose Werbung: Die nächsten Schulungen mit Stefan und/oder mir in Hamburg für Groovy und für Grails stehen bereit. Termine und Inhalte gibt's hier für Groovy und hier für Grails.

Freitag, 21. September 2007

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

Groovy 1.1 beta 3 und MOP

Groovy 1.1 beta 3 ist seit heute draussen. Da gibt es so kleine Schmankerl wie die Aufbohrung des ternären Operators: Schrieb man bisher

a != null ? a : "default value"
, so kann man sich Redundanz und Tipparbeit sparen durch die Notation
a ?: "default value"

Und es wird immer interessanter, mit dem Meta-Object Protocol (MOP) zu arbeiten. Zwischen dem Umgang mit MOP in Groovy 1.0 und 1.1 beta 3 liegen mitlerweile Welten: wer mag noch eine Category schreiben, wenn er ExpandoMetaClasses zur verfügung hat?

Zu verdanken ist dies hauptsächlich dem Grails-Projekt und dessen Project Lead Graeme Rocher. In seinem aktuellen Blogeintrag beschreibt er prägnant und eindrucksvoll einen Teil dessen, zu was das neue MOP in der Lage ist.

Mittwoch, 27. Juni 2007

Dieser Blog ist tot. Ich blogge weiter auf dem «Agile Trail».

Groovy und Grails beim Java Forum Stuttgart


Am 05.07.2007, also schon nächste Woche, findet wieder das alljährliche Java Forum Stuttgart statt. Groovy und Grails sind mit Veranstaltungen fünf Mal am Start (siehe auch das Veranstaltungsprogramm):

Vielleicht sehen wir uns ja dort? Würde mich sehr drüber freuen!