Samstag, 6. Dezember 2008

z3c.recipe.tag

Nachdem Wolfgang diese Woche auf der Suche nach Symboldefinitionen durch sein Egg-Verzeichnis gekrochen ist, haben wir z3c.recipe.tag ausprobiert und waren auch sofort begeistert: Mit diesem Rezept werden Vim- und Emacs-kompatible ctags-Dateien erstellt, die alle Symbole des genannten Eggs und seiner Abhängigkeiten haben. Damit entfällt endlich die Pfad-Sucherei und die händische Prüfung der Versionsnummern.

Dienstag, 8. Juli 2008

Python descriptor tutorial

Raymond Hettinger hat ein Tutorial gegeben, in dem er erklärt wie man mit Hilfe von Deskriptoren den Attributzugriff (lesen, schreiben, löschen) in Python für seine eigenen Zwecke anpassen kann.

Die Folien zum Vortrag sind praktisch orientiert und sollten demächst online verfügbar sein. In der Zwischenzeit kann man sein bestehendes Deskriptor-Tutorial anschauen.

Nebenbei wird erklärt, wie super() funktioniert und wie aus Funktionen Methoden werden.

Update: Die eigentlichen Folien sind inzwischen im Europython-Wiki verfügbar.

How we develop Launchpad at Canonical (and Bazaar too)

Steve Alexander hat über die Entwicklungsmethoden berichtet, die für Launchpad und Bazaar benutzt werden. Steve und ich haben lustige handgeschrieben Folien gebaut, die wir abfotografiert haben.

Steve AlexanderEins der Hauptprobleme mit denen man sich in der Entwicklung bei Canonical, speziell bei den Launchpad- und Bazaar-Teams, beschäftigt ist die Frage wie man "Corporate-Style Development" mit einem völlig verteilten Team unter einen Hut bekommt.

Der von Canonical verfolgte Ansatz lautet dabei: aus Methoden von agilen Prozessen und der Community-getriebenen Open-Source-Entwicklung ein Emulgat zu erzeugen, das sie "Community Agile" nennen.

Um diese Prozessentwicklung intern fortlaufend zu gestalten, verwendet Canonical ebenfalls Elemente des "LEAN"-Prozesses. Dieser stammt ursprünglich aus der Autoproduktion von Toyota und und dem Kaizen: der kontinuierlichen Verbesserung von Produkten, der Organisation und der Prozesse.

Werte

Die konkrete Ausgestaltung der Prozesse berücksichtigt einige feste Elemente, die Canonical als "Werte" bezeichnet. Diese Werte werden mit den Werten "klassischer" agiler Entwicklung kontrastiert dargestellt und beruhen auf den eigenen Erfahrungen:

Wissen und Motivation über Co-Lokation

Canonical möchte die besten Leute zusammenbringen und hat die Erfahrung gemacht, dass es produktiver ist die besten Leute miteinander über große Entfernungen arbeiten zu lassen, statt darauf zu bestehen, dass alle vor Ort arbeiten und dabei weniger gute Entwickler im Team zu haben.

Patches integrieren über Sprintplanung

Canonical entwickelt die meisten Produkte gezielt als Open-Source. Dadurch kommt es zu Code-Spenden, die nicht unbedingt in die eigene Planung passen. Um das Gesamtprodukt für so viele Anwender wie möglich interessant zu machen ist man bestrebt Patches so schnell wie möglich in die Hauptlinie des Codes zu überführen.

Gemeinschaft über In-House-Entwicklung

Software profitiert in verschiedenen Aspekten davon, wenn sich um Sie eine Gemeinschaft bildet, die sie aktiv benutzt, erweitert und entwickelt. Dazu ist es nicht immer notwendig, dass die eigene Software Open-Source ist - extensive Schnittstellen und Plugin-Systeme helfen einer Community ebenfalls, sich zu etablieren und zur Entwicklung einer Software beizutragen.

Im Vergleich zur agilen Entwicklung ist dies eigentlich eine konsequente Fortführung des Kunde-vor-Ort-Prinzips.

Hochwertige Builds

Ebenfalls ein aus der agilen Entwicklung fortgeschriebener Ansatz: Hochwertige Releases.

Selbst bei zusammensitzenden Teams ist defekter Code problematisch. Wenn sich bei stark verteilten Teams ein Fehler einschleicht, kann dieser aufgrund der Zeitunterschiede schnell gesamte Arbeitstage vernichten, während man auf die Fehlerbehebung wartet. Daher müssen alle Tests nach jedem Checkin laufen. Und eigentlich ist man dann sowieso in der Lage nach jedem Checkin ein hochwertiges Release.

LEAN

Eine weite Frage bei LEAN ist auch, wie viel Arbeit verschwendet wird, um vom Beginn der Implementation eines Features zum Kunden zu kommen?

Mit LEAN versucht man hohe Entwicklungsgeschwindigkeit zu erreichen, um Funktionen so schnell wie möglich zum Kunden zu bringen, denn solange eine Funktion in Arbeit ist, verursacht sie nur Kosten: die Spezifikationen können sich ändern, es erfordert Aufmerksamkeit der Entwickler, es fehlt dem Kunden. Je länger dieser Zustand dauert, desto teurer wird die Funktion am Ende.

Ebenfalls ist es Verschwendung, wenn eine Funktion einmal bereitgestellt wurde, und wieder in die Entwicklung muss. Beispielsweise aufgrund fehlender Qualitätssicherung oder zu großer Arbeitspakete.

Canonical versucht Verschwendung durch einige Methoden zu reduzieren:

Feste Release-Zyklen

Launchpad hat einen Release-Zyklus von einem Monat, bei einem Planungshorizont von 4 Monaten. Ubuntu hat einen Release-Zyklus von 6 Monaten. Dadurch wird es einfacher für die verschiedenen Unternehmensbereiche (Marketing, Testing, Entwicklung) miteinander zu kommunizieren.

Gleichmäßige Arbeitsbelastung

Gegenbeispiel: Wenn man einfach nur einen 1-Monatszyklusansetzt, passiert in der dritten Woche folgendes: Qualitätssicherung muss passieren. Dadurch versucht jeder seinen Code noch irgendwie ins Release zu bekommen, was für erhöhten Stress in dieser Woche führt (eigenen Code schreiben, Tests schreiben, anderer Leute Code reviewen, ...).

Um dies zu umgehen, hat Canonical jeden Code-Reviewer einen Tag in der Woche auf Bereitschaft (jeweils an verschiedenen Tagen). Dadurch kann jeder Programmierer den bereitstehenden Reviewer sofort ansprechen und muss nicht auf die Qualitätssicherung in der dritten Woche warten. Durch synchrone Kommunikation (IRC, Voip) wird hier ebenfalls Verschwendung vermieden, da sowohl Reviewer als auch Entwickler Code und Konzepte gerade im Kopf haben und nicht "swappen" müssen.

Weiterhin werden die Arbeitspakete bewußt kleingehalten: jeder Patch darf maximal 500 Zeilen inklusive Diff-Kontext sein. Ist er größer muss er in mehrere kleinere Einheiten zerteilt werden.

Zum Schluss werden Änderungen so schnell wie möglich auf den Trunk gespielt um erneute Konflikte zu und damit Verschwendung zu vermeiden.

Weiterführendes

Steve hat außerdem auf ein Paper von Ian Clatworthy hingewiesen, in dem die Gedanken zur Community-getriebenen Entwicklung noch einmal vertieft dargestellt werden.

Montag, 7. Juli 2008

Discouraging the use of Python (or: How to keep the snakes off your plane)

Harald Armin Massa hat typische FUD-Argumente gegen Python in einem unterhaltsamen Vortrag erfasst und deren Gegenargumente aufgezeigt.

Sneaking in Python

Python schleicht sich ja wirklich überall ein: durch Mock-Anwendungen (die nie ersetzt werden), durch kleine Scripting-Tasks, durch Datenbanktransfers und andere Programmiertätigkeiten.

Der geneigte Pointy-Haired-Boss (PHB) weiß, dass er jetzt vorsichtig sein muss, um zu verhindern, dass Python in seiner Abteilung um sich greift ...

Python is dangerous

... weil weniger Code geschrieben werden muss.

Dadurch braucht man weniger Programmierer, die eigene Abteilung wird kleiner, man bekommt ein kleineres Budget, kleineres Büro und einen schlechteren Parkplatz. Man verliert Macht!

Aber ein anständiger PHB weiß: Python ist nur für kleine Anwendungen geeignet. Wir schreiben aber große Anwendungen. Python kann hier nicht benutzt werden!

... weil Python-Code lesbarer ist.

Dadurch können Nicht-Programmierer (oder Programmierer anderer Teams) verstehen was wir tun. Andere können Fehler in unserem Code finden! Die
Urheber der Spezifikationen können unseren Code auf die Spezifikation prüfen!

Für einen PHB ist das natürlich kein Problem: geistige Eigentumsrechte und Geschäftsgeheimnisse müssen gewahrt werden. Code kann nicht einfach weitergegeben werden!

... weil selbst große Unternehmen Python einsetzen.

Früher konnte man als PHB gegen Python argumentieren, indem man auf eine große Firma setzt: Wir sind eine Microsoft-Firma. Wir nehmen nur Software von großen Firmen (MS, Sun, Oracle, IBM, ...). Aber das geht heute leider nicht mehr. Selbst Sun und Microsoft setzen Python ein. Sogar in der Microsoft Knowledgebase wird Beispielcode in Python veröffentlicht.

Aber zum Glück ist Python keine Sprache erster Klasse. Jeder weiß, dass die richtigen Sprachen für .NET nicht IronIrgendwas heißen. Wenn Python eine Sprache erster Klasse wäre, müßte es ja Python# genannt werden!

... weil Python frei ist.

Und zwar nicht nur frei (wie in Freiheit) sondern sogar frei (wie in Freibier). Dadurch hat die eigene Abteilung weniger Ausgaben, ein kleineres Budget und (siehe oben) der eigene Parkplatz ist gefährdet!

Ein erfahrener PHB weiß jedoch, wie wichtig es ist im Team zu arbeiten. Um in einem Team zu arbeiten, braucht man gemeinsame Ziele. Unser Ziel ist: Profit. Das Ziel eines kommerziellen Softwaretool-Herstellers ist: Profit. Das Ziel der Python-Hersteller ist aber nicht Profit. Daher können wir nur mit Werkzeugen eines kommerziellen Herstellers arbeiten.

... weil Python's Entwicklungsprozess sich an der Leistung der Mitglieder orientiert.

Das ist natürlich Diskriminierung und verstößt gegen viele viele Gesetze, denn Personen, die keine Leistung erbringen haben nichts zu sagen!

Merke: Ein guter Pointy-Haired-Boss weiß, wie man Python vermeidet!

ZEORaid-Talk

Ich habe auf der EuroPython einen Talk über den aktuellen Entwicklungsstand von ZEORaid, unserer Replikationsslösung für die ZODB, gegeben.

Der Vortrag lief recht gut, mit etwa 50 anwesenden Zuhörern. Es gabe einige interessante Nachfragen, speziell zum Problem ZEORaid selbst hochverfügbar zu machen, ohne komplizierte Lösungen (heartbeat et al) hinzuzuziehen.

Die Folien sind ebenfalls verfügbar.

py.test: rapid testing with minimal effort

Holger Krekel hat ein 1-stündiges Tutorial gegeben um die Verwendung von py.test zu erläutern.

Übersicht
  • py.test ist projektübergreifend und hält den Test-Tool-Code in einer eigenen Bibliothek
  • sammelt Python-Tests automatisch auf und führt sie aus
  • versucht die Boiler-Plate innerhalb eines Projekts klein zu halten
  • kann projektspezifisch erweitert werden
  • läuft auf Linux, Windows, OSX und unter Python 2.3-2.5
Grundlagen
  • Installation als Egg, stellt "py.test" als Executable zur Verfügung
  • Der "py"-Namensraum hat einen automatischen Lazy-Importer, der alles unterhalb von "py.*" importiert, so dass man nur "py" importieren braucht, der Rest kommt automatisch mit.
  • Tests werden über Konventionen automatisch gefunden (Klasse mit Namen "Test*" und Methoden mit dem Namen test_*) automatisch gefunden.
  • Automatisches Auffinden kann über "--collectonly" nachverfolgt werden
    um zu sehen wie py.test vorgeht und was es tatsächlich sieht und findet.
  • Assertions werden über Python's "assert"-Statement formuliert. Exceptions können über eine Helferfunktion "py.test.raises" mit dem "assert"-Statement kombiniert werden.
  • Fehlerhafte Werte bei einem Fehler werden getraced um zu zeigen wie sie berechnet wurden.
  • Generative Tests: wenn eine Testmethode ein Generator ist, kann sie Callables und deren Parameter yielden, die dann als eigentlicher Test ausgeführt werden.
  • stdout/stderr werden umgeleitet und nur im Fehlerfall ausgegeben
  • --pdb lädt einen pdb nach einem Fehler
  • -x beendet den Testlauf nach dem ersten Fehler
  • --looponfailing: führt die fehlgeschlagenen Tests automatisch neu aus, wenn Dateien, die zu diesen Tests gehören verändert werden
  • setup/teardown: setup_module, setup_class, setup_method, teardown_*
  • setup_method bekommt das Methodenobjekt reingereicht, setup_module erhält das Modul-Objekt, setup_class erhält die Klasse
  • doctests werden anhand der Extension ".txt" automatisch gefunden
Erweiterbarkeit
  • py.test sucht nach "conftest.py"-Dateien, die die Konfiguration von py.test beeinflussen.
  • Mehrere conftest.py-Dateien können über Verzeichnisebenen miteinander kombiniert werden.
  • Diverse Elemente (Session, Collection, Module, ...) können beerbt werden, um eigene Funktionalität unterzubringen.
  • Dazu werden via "conftest.py" dynamisch die konkreten Klassen für Session, Collection, Module, ... nachgeschlagen, die unterhalb eines Verzeichnisses verwendet werden sollen.
  • Fehlerberichte können in HTMl generiert werden. Dies kann ältere Testläufe beinhalten, so dass man den historischen Verlauf einsehen kann.
  • Weitere Plugins für Prolog-Tests, JavaScript-Tests (via SpiderMonkey), verteilte Tests um Tests auf anderen Maschinen (mit ggfs. anderen Plattformen) auszuführen, Integration mit klassischen UnitTest
  • Reporting kann man momentan nicht (einfach) anpassen
Fragen
  • Ist die py-Import-Magic kompatibel mit py2exe? Antwort: Unbekannt.
  • Wie schwer wird es sein py.test auf Python 3k auszuführen? Antwort: Unbekannt
  • Parallele Ausführung: über verteilte Tests. Können sowohl lokal als auch remote verteilt werden inkl. Multi-CPU-Support.
  • Gruppierung von tests nach Setup ala Layer: Gibt es momentan nichts.

ReportLab Paragraphs Reloaded

Dinu Gherman gab einen Vortrag über ReportLab. Dabei ist er speziell auf die Implementation von Paragraphen, deren Probleme und einer Reimplementation eingegangen.

ReportLab-Übersicht
  1. Canvas, eine Zeichenfläche, die in etwa einer Seite entspricht. Kann auch als Bilddatei exportiert werden.
  2. Platypus, "Page LAyout TYPography Using Scripts", bietet verschiedene Objekte (Frame, PageTemplate, DocumentTemplate, Content, Flowables) um Typographie und Inhalt einer oder mehrer Seiten zu beschreiben um daraus ein PDF zu erzeugen.
  3. RML, "ReportLab Markup Language", ein Aufsatz für Platypus, der XML in Platypus-Anweisungen übersetzt (kommerziell, eine freie Drittanbieter-Implementation (z3c.rml) ist aber auch verfügbar)
Paragraphen sind Flowables aus der Platypus-Bibliothek, deren Hauptaufgabe die Berechnung von Zeilenumbrüchen ist. Außerdem wenden Paragraphen verschiedene Stile für Schriften, Einzüge und Anstriche an. Innerhalb eines Paragraphen können XML-Tags verwendet werden, um einige Stile auf Wortebene anzuwenden.

Paragraphen können momentan nicht:
  • eingebettete Bilder (im ReportLab SVN inzwischen doch)
  • Silbentrennung
  • Kerning
Außerdem ist der Code für Paragraphen nur sehr schwer verständlich und nicht erweiterbar. Leider ist das Hauptaugenmerk der Entwicklung bisher auf Geschwindigkeit gelegt worden.

"Paragraphs Reloaded"

Ein neues Flowable, genauer: eine Familie von Paragraphen-Klassen, die abgeleitet werden können (und sollen).

Der MinimalParagraph ist ausschließlich für die Berechnung von Zeilenumbrüchen und wenigen Paragraph-Stilen da.

Paragraphen bieten ein Event-Schema, an dem eigener Code in das Layouting eingreifen kann. Beispielsweise an Wort- oder Zeilengrenzen.

Beispiele für Erweiterbarkeit, die Dinu bereits implementiert hat: einzelne Wörter markieren, Silbentrennung, eingebettete Bitmap- und Vektorbilder, Zeilennummerierung.

Beim Vergleich der Code-Komplexität der Original-Implementation fällt auf, dass der bisherige Paraph etwa 1400 Codezeilen hat, während die neue Minimalimplementation mit etwa 200 Zeilen auskommt.

Im Geschwindigkeitsvergleich hat die bisherige Implementation die Nase vorn. Der neue Code braucht etwa 2-5mal länger um einen Vergleichbaren Paragraphen zu zeichnen. Nach Dinus Erfahrung ist das aber immer noch schnell genug für die meisten Aufgaben.

In Zukunft will Dinu weitere Paragraphen-Attribute implementieren, sowie Kerning, eingebettetes XML, generische Callbacks und eventuell RTL-Unterstützung.

Fragen
  • Frage nach der Verwendung des TeX-Zeilenumbruch-Algorithmus: nicht berücksichtigt. Andrew Kuchling hatte ihn mal teilweise implementiert, ist aber extrem langsam gewesen.

EuroPython 2008

Die EP 2008 beginnt heute. Eine gute Neuerung des Hotels ist die freie Verfügbarkeit von WLAN auf den Zimmern, nicht nur im Konferenzbereich. Die Registrierung lief bedeutend einfacher als letztes Jahr: zur Anmeldung gehen, eigenes Namensschild und Konferenztüte nehmen, fertig.

Freitag, 27. Juni 2008

Neue Blob-Verzeichnisstrukturen

Die ZODB unterstützt seit einiger Zeit große Dateien über den eigenen Datentyp "Blob". Bisher wurde für jeden Blob ein Verzeichnis angelegt, in dem sämtliche Revisionen des Blobs gespeichert wurden.

Eine Installation brachte dies an die Grenze, da als Dateisystem ext3 benutzt wurde, und dort die Anzahl der Einträge je Verzeichnis auf 32k begrenzt ist. Da dies auch in anderen Dateisystemen der Fall ist habe ich das Blob-Verzeichnis etwas stärker strukturiert: 8 Ebenen von Verzeichnissen, abgebildet über die Little-Endian-Repräsentation der OID. Das garantiert maximal 256 Einträge je Verzeichnis und balanciert den Baum relativ einfach aus. Die Implementation ist abwärtskompatibel für alle, die bereits Datenbanken im alten Schema haben.

Momentan lebt der Code noch auf einer Branch und ist für ZODB-trunk und ZODB 3.8 verfügbar.

Eine Einschränkung der Branches ist momentan, dass die Datenbankgröße nur ohne den Platz, den Blobs einnehmen berechnet werden kann, da getSize von ZEO in jeder Transaktion einmal aufgerufen wird, und bei der neuen Struktur sehr langsam wird.

Donnerstag, 22. Mai 2008

Pakete von Drittanbietern konfigurieren

Ich hatte gestern mit Sebastian das Problem aus einem Python-Paket für Zope 3 (gocept.country) eine ZCML-Konfiguration (konkret: i18n:registerTranslations) relativ zu einem anderen Python-Paket (pycountry) zu spezifizieren.

Leider erlaubt i18n:registerTranslations nur eine relative Pfadangabe zum aktuell konfigurierten Paket. Glücklicherweise gibt es einen generischen Mechanismus in ZCML um Konfigurationsangaben im Kontext beliebiger Python-Pakete auszuführen: das configure-Statement.

Configure-Statements können verschachtelt werden und erlauben die freie Angabe eines Pakets, das für alle darin eingebetteten Anweisungen als Kontext benutzt wird. Das ganze sieht dann folgendermaßen aus:

...
<configure package="pycountry">
<i18n:registertranslations directory="locales">
</i18n:registertranslations>
...

Freitag, 2. Mai 2008

ZEORaid in Beta

Seit Mittwoch gibt es ZEORaid 1.0b1, das wir inzwischen auf einem internen Produktionsserver testweise einsetzen. Die initiale Replikation der 1.1 GB grossen ZODB hat etwas weniger als 15 Minuten gedauert und resultiert normalerweise in Byte-genauen Kopien der originalen Datenbank.

Setzt man zwei identisch konfigurierte ZEORaid-Server auf, kann man auch ZEORaid selbst als einzelnen Ausfallpunkt ausschließen, wobei ein paar operative Einschränkungen zu beachten sind.

ZEORaid unterstützt Zope ab Version 2.8, Blobs und alle anderen ZODB-Funktionen ausser "Versions".

Freitag, 14. März 2008

PyCon 2008

PyCon 2008 (diesmal in Chicago) läuft seit einigen Stunden. Fotos gibt es ebenfalls.



Freitag, 15. Februar 2008

psycopg, segfaults, Valgrind

Diese Woche habe ich einen Segfault in psycopg behoben, der bei einem Zope-Server häufig für Abstürze sorgte. Das interessante: psycopg hat immer wenn ein Client-Encoding angegeben wurde, das keine Binde- oder Unterstriche enthalten hat, ein Byte zu wenig alloziiert. Genaue Fehlerbeschreibung und Patch gibts im Trac.

Schlussendlich hat mir Valgrind sehr geholfen das Problem zu analysieren. Die Aufrufzeile um einen Zope-Server, der im Vordergrund läuft zu überwachen ist:
valgrind --leak-check=yes --trace-children=yes --suppressions=valgrind-python.supp bin/zopectl fg
Die Suppressions-Datei wird im Python-Source-Code mitgeliefert und sorgt dafür, dass Valgrind sich nicht von Python's Memory-Manager für kleine Objekte verwirren lässt.

Mittwoch, 6. Februar 2008

zc.resourcelibrary und virtual hosting

zc.resourcelibrary ist ein exzellentes Werkzeug um automatisch Pakete von Ressourcen (CSS, JS, Bilder) gemeinsam zu registrieren und in eine HTML-Seite (via PageTemplate oder View-Klasse) einzubinden. Dabei werden sogar Abhängigkeiten (z.B. "Meine JS-Files benötigen MochiKit") berücksichtigt.

Da die URLs (CSS verweist auf Bilder) in einer Resource-Library statisch sind, muss man ein klein wenig aufpassen, wie man "Virtual-Hosting-kompatibel" bleibt.

Der kleine Trick besteht darin, alle URLs in CSS-Dateien relativ anzugeben. Dadurch wird die (automatisch berechnete) Basis-URL der Resource-Library ebenfalls auf die statisch enthaltenen Verweise angewandt.

Donnerstag, 24. Januar 2008

Zope ist nicht simpel - und das ist auch gut so

Dr. Dewar und Dr. Schonberg haben in zwei Artikeln dargestellt, warum Softwareentwicklung mehr ist als "einfach mal was zusammenzustöpseln":
Beide Artikel bestärken meinen Eindruck in Bezug auf die handwerklichen Fähigkeiten, die ich von Software-Entwicklern erwarte und wie diese von Hochschulen durchgängig enttäuscht werden.

Auch die typische Argumentation gegen Zope, dass es nicht "einfach sei", halte ich nicht für ein Problem, sondern für einen Vorteil. Nur weil es nicht simpel ist können wir komplexe und anspruchsvolle Probleme lösen und mehr tun als "zufällig die richtigen Komponenten raussuchen".

Ich möchte damit nicht für sinnnlos komplizierte Systeme argumentieren. Einfachheit darf aber nicht mit Simplizismus verwechselt werden.