Warum wir Unit-Tests für Ruby-Programmme schreiben sollten

29 12 2007

Ein schönes Beispiel, wie nützlich Tests für Ruby (und auch für andere Sprachen) Programme sein können, habe ich vorgestern erlebt.

Ich habe ein Gem erstellt, welche Spreadsheet-Dateien verarbeiten kann (http://roo.rubyforge.org).

In einer Newsgroup fragte nun jemand, mit welchem Tool man am besten Excel-Dateien in CSV-Dateien umwandeln kann. Ich habe darauf geanwortet, daß das mit ‚roo‘ gehen würde. Kurz darauf kam die Antwort, daß das nicht funktionieren würde, und daß die Methode ‚to_csv‘ welche in meinem Programm eine CSV-Ausgabe entweder nach stdout oder in eine Datei schreibt, nur für Openoffice- und Google-Spreadsheets, nicht jedoch für Excel-Spreadsheets funktionieren würde.

Ich war ziemlich verblüfft, weil ich sicher war, daß ich dies auf für Excel-Dateien schon implementiert hatte und daß dies auch schon funktioniert hätte.

Ich habe das dann bei mir überprüft – und tatsächlich, bei Excel-Dateien funktionierte es nicht.

Was war passiert? Wie konnte das passieren, wo ich doch speziell für dieses Gem eigentlich alle Funktionen mit Testfällen abgedeckt hatte?

Ich muß einschieben, daß ich generell ein großer Freund von Test Driven Development bin und ich auch für dieses Programm danach vorgegangen bin, was eine große Hilfe bei allen Erweiterungen ist, weil man einfach die vorhandenen Testfälle immer wieder ablaufen lassen kann, um zu testen, ob alles noch wie gewünscht funktioniert.

Die Lösung des Problems war dann relativ simpel: Ich hatte beim ersten Entwurf meines Programms als erstes die Klasse ‚Openoffice‘ (Spreadsheets) geschrieben und später die Klasse ‚Excel‘ welche eine Kind-Klasse von Openoffice war, und deshalb auch deren Methode ‚to_csv‘ für die Ausgabe als CSV-Datei geerbt hatte. So weit, so gut.

Im Lauf der späteren Entwicklung des Programms habe ich entschieden, daß dieses Design für den Benutzer zwar funktioniert hat, im Sinn der reinen OO-Lehre aber nicht ganz korrekt war, weil ein Excel-Objekt natürlich kein Kind-Objekt einer Openoffice-Klasse ist.

Ich habe dann eine generische Klasse ‚GenericSpreadsheet‘ eingeführt, von der sowohl die Openoffice- als auch die Excel-Klasse (und später auch noch die Google-Klasse) erben.

Im OO-Sinn war dieses Design nun wesentlich besser, aber die Methode ‚to_csv‘ war nun nur in der Openoffice-Klasse und nicht in der Excel-Klasse vorhanden. Ich hatte es in Kommentaren zwar schon zum Auslagern in die allgemeine Spreadsheet-Klasse markiert, dies aber noch nicht wirklich getan.

So – die Excel-Klasse war nun ihrer ‚to_csv‘ Methode beraubt, da sie nicht mehr von Openoffice erbt.

Warum haben das die Tests nicht aufgedeckt?

Es gab zwar auch für Excel-Objekt Tests, die die CSV-Ausgabe abgedeckt haben, allerdings habe ich dieses Test nur im Rahmen von Tests für ziemlich große Spreadsheet-Dateien mit mehreren tausend Zeilen verwendet. Da diese Tests aber im Vergleich zu kleineren Spreadsheet-Testdateien relativ lange dauerten, habe ich die lange laufenden Test mit einem speziellen Schalter wahlweise abschaltbar gemacht. Dies führte dazu, daß mir dieser spezielle Fehler durch die Lappen gegangen ist, weil ich diese lang laufenden Test nicht mehr ausgeführt hatte.

Die Lösung wäre natürlich gewesen (und habe ich jetzt auch als Testfälle eingebaut), die CSV-Ausgabe nicht nur im Rahmen von großen Spreadsheets zu testen, sondern generell und auch mit kleineren Test-Spreadsheets.





Dragongoserver Gem bei Rubyforge

25 12 2007

Wenn es genehmigt wird, werde ich in Kürze mein fünftes Gem bei Rubyforge veröffentlichen: Ein Kommandozeileninterface fürs Go-Spielen bei Dragongoserver.net.

Das existiert jetzt schon als funktionierendes Ruby-Programm  – ich muß es nur noch schön als Gem verpacken.

Was es bis jetzt kann:

  • in regelmäßigen Abständen den eigenen Account bei Dragongoserver.net abfragen, ob eigene Züge in laufenden Partien anstehen. Die Abfragezeit wird dynamisch angepaßt, so daß, wenn bei den eigenen Partien längere Zeit keine Züge zu tätigen sind, die Abfragezeit laufend erhöht wird (bzw. wieder veringert, wenn in kürzeren Abständen Züge der Gegner erkannt werden).

Was es in Zukunft können soll:

  • Einstellen von neuen Partien in den Waitingroom mit vorgebbaren Parameteren (z. B. Spielfeldgröße, Gesamtspielzeit, etc.) Dies ist teilweise schon programmiert.




Go playing program with Ada95

25 12 2007

Ich kann’s nicht lassen und will mich nun auch an ein Go-Programm versuchen.

Nach langem Überlegen, ob sich das überhaupt lohnt und angesicht der Tatsache, daß andere Leute damit schon viel weiter sind (siehe auch die Mailinglist computer-go), finde ich es trotzdem interessant, sich damit zu beschäftigen und ein vielleicht einigermaßen passabel spielendes Programm zu erstellen.

Als Implementierungssprache will ich Ada95 verwenden:

  • Sehr gute Geschwindigkeit des compilierten Codes gegenüber anderen Programmiersprachen.
  • Leichter lesbar und wartbar als beispielsweise C oder C++
  • Bereits vorhandene Sprach-Features wie beispielsweise parallele Tasks, die es erlauben, Aufgaben parallel abzuarbeiten.




Stolpersteine im Rails-Umfeld

24 12 2007

… genauer gesagt, bei der Verwendung von ActiveRecord.

Nenne nie eine Spalte in einer Datenbanktabelle ‚class‘!

Ich hatte ein Skript, in dem ich dieses so gemacht hatte. Es funktionierte auch, solange bis das Gem ActiveRecord in der Version 2.0.0 herauskam.  Dann kam eine für mich erstmal seltsame Fehlermeldung.

Ich habe dann eine Weile herumprobiert, bis ich schließlich herausgefunden hatte, daß es daran lag, daß die Spalte in der Datenbank ‚class‘ hieß – auf ‚class_name‘ geändert und alles funktionierte wieder zur Zufriedenheit.

Klar, ist es immer gefährlich, Variablen so wie Sprachelement in Ruby zu benennen, aber da es vorher funktioniert hatte, habe ich mir nichts böses dabei gedacht …





roo – Version 0.8.0 fertig

16 12 2007

Es ist vollbracht. Heute habe ich die Version 0.8.0 von Roo veröffentlicht. Die größte Neuerung daran ist, daß man mit roo nun auch auf Google Online Spreadsheets lesend und sogar schreibend zugreifen kann.

Desweiteren wurde die innere Strukur der Klassen etwas bereinigt, was für den Anwender jedoch keine Auswirkungen hat – mir hingegen war es wichtig, eine etwas bessere Struktur reinzubringen, was sich auch für die Zukunft bezahlt macht, wenn noch weitere Spreadsheet-Typen aufgenommen werden sollten.

Hiermit kann man jetzt von Ruby Programmen aus die eigenen Spreadsheets bei Google abrufen oder ändern. Außerdem kann man sogar fremde Spreadsheets von anderen Personen bearbeiten – soweit man dafür vom jeweiligen Eigentümer entsprechend authorisiert wurde.





roo – Version 0.8.0 (bald fertig)

9 12 2007

An diesem Wochenende, wenn im Büro sonst niemand anwesend war, habe ich mich hingesetzt und den größten Teil der Version 0.8.0 von roo geschrieben, mit der nun auch Google-Spreadsheets möglich sind.

Im großen und ganzen sieht es gut aus – kleinere Ungereimtheiten müssen noch getestet und korrigiert werden.

Aber es ist schon cool, wenn man von der irb aus auf seine entfernten Spreadsheets auf dem Google-Server zugreifen kann.





roo – Google Spreadsheets in Kürze auch möglich

8 12 2007

Lange aufgeschoben – habe ich mich in den letzten Tagen aufgemacht, jetzt auch den Zugriff auf Google-Spreadsheets von meinem gem „roo“ zu ermöglichen.

Google-Spreadsheets sind wirklich eine coole Sache, zum einen, daß Spreadsheets von jedem Rechner aus aufzurufen sind und zum anderen kann man sich tolle Anwendungen ausdenken, bei denen Daten aus eigenen oder fremden Spreadsheets im Netz gelesen und sogar geschrieben werden können.

Habt noch etwas Geduld – in den nächsten Tagen wird roo auch Google-Spreadsheets bearbeiten können.