Notizen aus dem Norden

Unsere Herberge auf Rügen 2012
Unsere Herberge auf Rügen 2012

Heute neigt sich unser diesjähriger Sprint dem Ende. Am Dienstag sind wir gen Norden auf die Insel Rügen gefahren, um uns für 3 Tage intensiv darüber zu unterhalten, wie wir in Zukunft Software entwickeln wollen. Der Fokus lag dabei auf der Client-Seite, also dem Teil der Anwendung, der im Browser ausgeführt wird. Hier wollen wir weitere Erfahrung sammeln und Konzepte suchen, wie man wart- und testbaren, strukturierten Code schreibt.

Im Vorfeld haben wir uns auf drei JavaScript Frameworks/Bibliotheken geeinigt, die wir uns dann am Mittwoch in drei Gruppen à zwei Personen intensiv angeschaut haben: Ember, Obviel und Backbone. Neben Dokumentation lesen und Tutorials ausprobieren haben wir auch gegen einen selbst-gestrickten “Spielserver” programmiert, um durch die praktische Erfahrung ein Gefühl für die Konzepte hinter dem Framework zu bekommen und einschätzen zu können, inwieweit sich das Framework in unserem Alltag einsetzen lässt.

Ember hat uns für den Einsatz bei “Grüne Wiese”-Projekten begeistert. Durch die strikte Trennung von Model, View und Controller (MVC) schreibt man nicht nur automatisch saubereren, sondern auch testbaren Code. Das Objekt-Modell bringt automatisierte, bidirektionale Aktualisierung zwischen Model und View mit, und für die Speicherung auf dem Server gibt es ein kleines, gut integriertes REST-Plugin. Der Aufwand, eine funktionierende CRUD-Anwendung, die Änderungen automatisch an den Server propagiert, zu entwickeln, ist mit Ember erstaunlich gering. Auch wie Ember es erlaubt, seine Klassen zu beerben, ist uns positiv aufgefallen. Leider haben wir es nicht geschafft, zwei Ember-Anwendungen auf einer Seite zu laden. Auch ist die Dokumentation noch recht dünn, was daran liegen dürfte, dass Ember noch ein junges Produkt ist.

Hilfreiche Links zu Ember:

Obviel ist streng genommen unser eigenes “Kind”, denn erste Ideen dazu entstanden im Jahre 2008 bei gocept. Obviel ist ein Client-seitiges Web-Framework für jQuery mit einem einfachen, aber genialen Prinzip: für ein JavaScript-Objekt rendert man einen View in einem Element. Dreh- und Angelpunkt bei Obviel sind die Interfaces, die definieren, wie ein View Objekte, die das Interface implementieren, rendert. Entwickler, die mit der Komponenten-Architektur von Zope vertraut sind, werden keine Probleme haben, Obviel zu verstehen. Weiterhin lässt sich Obviel problemlos in bestehende Projekte integrieren, es enthält Unterstützung für Internationalisierung (i18n), Forms mit Validierung, verschiedene Template-Engines, Subviews, …

Hilfreiche Links:

Backbone unterstützt den Entwickler bei der Strukturierung seiner Webanwendungen durch in Code gegossene Konventionen. Es wirkt sehr fokussiert, denn es tut nicht wirklich viel, aber das Wenige tut es sehr sinnvoll. Backbone ist, im Gegensatz zu Ember, sehr gut dokumentiert, löst aber im Moment keines unserer Probleme. Da Backbone insbesondere keine Unterstützung für data binding bietet, haben wir noch Knockout und Rivets ins Spiel gebracht. Für ersteres steht mit Knockback der „Glue-Code“, um die Frameworks miteinander zu verheiraten, schon zur Verfügung, für letzteres mussten wir ihn uns aus der Dokumentation und dem Issue-Tracker des Projekts zusammensuchen.

Weiterführende Links:

Ein Fazit zu ziehen fällt uns nicht leicht: Ember behalten wir für das nächste “Grüne Wiese”-Projekt auf jeden Fall im Auge. Da uns Backbone und Knockout/Rivets nicht überzeugen konnten, haben wir uns noch spontan AngularJS angeschaut – aber auch hier ist im Moment die Ernüchterung groß: Persistieren von Daten ist ein ungelöstes Problem, die Watcher auf dem Model (data binding) feuern nur unregelmäßig oder viel zu oft. Nach längerem Probieren haben wir herausgefunden, dass wir eine eigene Direktive schreiben müssen, die sich um die Persistierung kümmert.

Bleibt also Obviel, das wir an der einen oder anderen Stelle in unseren Projekten schon verwenden. Es wird wohl auch in Zukunft unser Werkzeug, um bestehenden JavaScript-Code zu verbessern oder neue Frontend-Einheiten zu bauen.

Das gocept-Team

Python 2 and 3 compatible builds with zc.buildout

Creating a single-source build environment with zc.buildout that works for both Python 2 and 3 is a bit of a hassle. This blog post shows how to do it for a minimal demo project.

During the sprints at PyCon DE 2012, we tried to make the upcoming 1.0 release of the nagiosplugin library compatible with both Python 2.7 and Python 3.2. Going for a single code base (without preprocessing steps like 3to2) was no too hard. The only thing left was a single-source zc.buildout setup suited for both Python 2.7 and 3.2. It worked out at last, but currently it needs two buildout configurations. This is a little bit kludgy. I hope that things will improve in the near future so that a single-source build environment with zc.buildout will be possible.

In the following, I will demonstrate the steps with a simple demo project called MultiVersion. It contains nothing more than a single class that is supposed to run under both Python 2 and 3. There is also a unit test to verify that the code works. We use zope.testrunner to run the unit tests. The code’s functionality is irrelevant for the examples, so I left it out. You can download the full source if you are interested.

1. Use a recent enough virtualenv

Older versions of virtualenv are generally not suited since they ship with obsolete releases of distribute and pip. Check if the virtualenv included in your GNU/Linux distribution is too old. Anything below 1.8 reduces the chance of success, so better install a current virtualenv locally then. Likewise, our bootstrap.py must be recent enough to support both Python 2 and 3. The standard bootstrap.py from python-distribute.org does currently not work with Python 3.

Now we are ready to create a virtualenv in a fresh source checkout.

Python 3.2:

$ virtualenv -p python3.2 .
Running virtualenv with interpreter /usr/bin/python3.2
New python executable in ./bin/python3.2
Installing distribute.....done.
Installing pip.....done.

Python 2.7:

$ virtualenv -p python2.7 .
Running virtualenv with interpreter /usr/bin/python2.7
New python executable in ./bin/python2.7
Not overwriting existing python script ./bin/python (you must use ./bin/python2.7)
Installing setuptools.....done.
Installing pip.....done.

2. Running buildout with Python 3.2

I will discuss the steps for Python 3.2 first, since main development will concentrate on newer Python versions. After that, I will describe the necessary steps to make the build environment backward compatible.

To run zc.buildout, we need a buildout.cfg file. I prefer to pin package versions in all projects to ensure reliable builds. As of writing this blog post, there is just an alpha release of zc.buildout that supports Python 3.2. Unfortunately, this version of zc.buildout supports Python 3.2 only, so don’t try this with Python 3.3.

My basic buildout.cfg looks like this:

[buildout]
allow-picked-versions = false
develop = .
newest = false
package = multiversion
parts = multiversion test
versions = versions

[versions]
distribute = 0.6.28
z3c.recipe.scripts = 1.0.1
zc.buildout = 2.0.0a2
zc.recipe.egg = 2.0.0a2
zc.recipe.testrunner = 1.4.0
zope.exceptions = 4.0.1
zope.interface = 4.0.1
zope.testrunner = 4.0.4

[multiversion]
recipe = zc.recipe.egg
eggs = ${buildout:package}
interpreter = py

[test]
recipe = zc.recipe.testrunner
eggs = ${buildout:package}
defaults = ['--auto-color']

In my experience, it is best to pin distutils to exactly the same version that is included in virtualenv’s support files. While differing versions are possible, they may trigger hard to find bugs since it is not always clear which version is used is which step.

I use the Python interpreter from my virtualenv’s bin directory while creating the buildout executable. This saves me from using activate/deactivate scripts which are slightly cumbersome in my opinion.

$ bin/python3.2 bootstrap.py
Creating directory 'blog-python-2-3/parts'.
Creating directory 'blog-python-2-3/develop-eggs'.
Generated script 'blog-python-2-3/bin/buildout'.

$ bin/buildout
Develop: 'blog-python-2-3/.'
Installing multiversion.
Generated interpreter 'blog-python-2-3/bin/py'.
Installing test.
Generated script 'blog-python-2-3/bin/test'.

Now we have a working build for Python 3.2:

$ bin/test
Running zope.testrunner.layer.UnitTests tests:
  Set up zope.testrunner.layer.UnitTests in 0.000 seconds.
  Ran 1 tests with 0 failures and 0 errors in 0.002 seconds.
Tearing down left over layers:
  Tear down zope.testrunner.layer.UnitTests in 0.000 seconds.

3. Running buildout with Python 2.7

Unfortunately, the current zc.buildout alpha release does not work with anything except Python 3.2. Running bootstrap.py fails:

$ bin/python2.7 bootstrap.py
Getting distribution for 'zc.buildout==2.0.0a2'.
While:
  Bootstrapping.
  Getting distribution for 'zc.buildout==2.0.0a2'.
Error: Couldn't find a distribution for 'zc.buildout==2.0.0a2'.

There is no single zc.buildout distribution that fits both Python 2.7 and 3.2. To get around this, I need to create a special-case buildout.cfg that changes version pinnings for incompatible packages. Besides zc.buildout, zc.recipe.egg needs different versions for Python 2.7 and 3.2 as well.

I create buildout-2.x.cfg (slightly grumbling):

[buildout]
extends = buildout.cfg

[versions]
zc.buildout = 1.6.3
zc.recipe.egg = 1.3.2

This one does the job when used with both bootstrap and buildout:

$ bin/python2.7 bootstrap.py -c buildout-2.x.cfg
Generated script 'blog-python-2-3/bin/buildout'.

$ bin/buildout -c buildout-2.x.cfg
Develop: 'blog-python-2-3/.'
Installing multiversion.
Generated interpreter 'blog-python-2-3/bin/py'.
Installing test.
Generated script 'blog-python-2-3/bin/test'.

We now have a build environment that builds single-source code for both Python 2.7 and 3.2 using zc.buildout. Of course, this technique could be extended to support even more versions. But I hope that the incompatible packages will be updated in the near future so that the need for special-case buildout.cfg files will go away. What seems to be most missing: a release of zc.buildout that supports all major Python versions.

TL;DR

  • Use a current virtualenv version.
  • Use a compatible bootstrap.py.
  • Pin your package versions.
  • Versions for some packages (including zc.buildout) must be special-cased.

Acknowledgements

I would like to thank Andrei Chirila and Michael Howitz for a great sprint session.

gocept Developer Punsch 3

Nachdem wir dieses Jahr bereits zwei “Developer-BBQs” veranstaltet haben, laden wir am Freitag, 7.12.2012 ab 14:00 Uhr ein weiteres Mal in unser Büro ein. Jahreszeitenbedingt unter dem Titel “Developer-Punsch”!

Die Veranstaltung richtet sich wie immer an alle (Web-)Entwickler und Sysadmins, die wie wir gerne mal über den Tellerrand schauen. In einem an Open Space angelehnten Format möchten wir uns vorher gesammelten Themen widmen, die auch gerne mitgebracht werden können [1].

Wir würden uns freuen, zahlreiche Interessierte aus der Region und auch darüber hinaus  empfangen zu dürfen.

Ab ca. 19 Uhr wird es etwas zu Essen geben und der Punsch wird serviert.

Um Anmeldung per Mail (mail@gocept.com) oder auf dem Etherpad [1] wird gebeten.

P.S.: Since we are addressing local audience we are keeping this post in German. Basically we want developers and admins in our area to meet up, exchange ideas, and enjoy hot punch.

[1] Etherpad zur Anmeldung und Themensammlung