Tag Archives: open source

politisches

Open Source: Python ZVT 700 cash register protocol

Vergangene Woche erreicht mich eine Mail, die mich über das Thema Softwarelizenz grübeln lässt:

Moin Mathias,

in Deinem Blog:

http://www.zieglergasse.at/blog/2012/hacks/terminal-update/

schreibst du, Ihr habt eine quelloffene python Bibliothek für ZVT 700 verwendet.

Ich habe ein wenig gegoogelt, jedoch keine gefunden…

Auch PIP hat nichts ausgespuckt.

Hast du einen Link für mich?

herzliche Grüße

[Name und Organisation bekannt]

Interessante Anfrage: Da gibt es scheinbar Interesse an Software, die im Rahmen meiner Tätigkeit an der WU entstanden ist. Obwohl mir mein Dienstvertrag – streng ausgelegt – die Verwertungsrechte an von mir geschriebener Software entzieht, wurde der angefragte Code gar nicht von mir selbst, sondern von Gabor, einem Externen in meinem Auftrag entwickelt. Und dieser wiederum hat den Code nicht explizit lizenziert, entwickelt aber im “Open Source”-Spirit.

Bevor dies hier eine juristische Abhandlung wird, will ich meinen Gedankengang darlegen:

  • Die WU als öffentlicher Auftraggeber finanziert sich zum Großteil über Steuergeld.
  • Steuergeld, welches etwa Softwareunternehmen mit hohen Lohnnebenkosten aufbringen müssen.
  • Während man hier intern enorm von Open Source Software profitiert, ist es de facto unmöglich, der Community etwas zurück zu geben. Freiwillige Spenden an Entwickler(teams) kann ich beispielsweise schlecht als notwendige Ausgabe meiner Kostenstelle deklarieren. (Ein womöglich überteuerter Wartungsvertrag an ein kommerzielles Unternehmen wäre natürlich “professionell” und außerdem gut planbar für die Finanzabteilung.)
  • Irgendwo sitzt also gerade ein Unternehmen und benötigt Code, der bereits mittels Steuergeld entstanden ist.
  • Wird dieser Code  außerhalb der WU eingesetzt, steigt die Wahrscheinlichkeit, dass er gewartet und bei künftigen Änderungen angepasst wird.
  • Damit sinken Kosten an der WU.
  • Die Sicherheit des Codes steigt durch Offenlegung ebenso. (Weil ja Lücken gefunden und aufgezeigt werden.)
  • Das Unternehmen wiederum profitiert mit verkürzter Entwicklungszeit. Doch hier ist kein Papierkrieg zum Abholen einer dubiosen Förderung notwendig, sondern es wird staatliche finanzierte Infrastruktur  verwendet.

Kurzum: Ich habe mich entschieden, das Paket unter der Gnu General Public Licence (GPL) zur Verfügung zu stellen, weil ich überzeugt bin, betriebswirtschaftlich und politisch das Richtige zu tun. Die GPL stellt sicher, dass selbst Derivate unserer ursprünglichen Arbeit quelloffen zur Verfügung gestellt werden müssen. Ungeachtet davon kann das Unternehmen natürlich Produkte bauen, vermarkten und damit Geld verdienen, was ja letztlich Ziel eines Unternehmens ist.

Code bei Github: https://github.com/mathiasfrey/ecrterm

python

Table syncing with Python

Recently, I had to move around a lot of data in an annoyingly error-prone process: I would receive awfully colorful spreadsheets in ever changing formats. Frightened by seemingly infinite creativity of Excel users I decided to move the data to a staging environment first. After some quality checking – aka: Excel exorcism – I subsequently would merge the source data with my production database, the target.

In the lingo of database people, I needed to implement INSERT, UPDATE and DELETE. Regarding my Python programme, this meant covering three cases:

  • new records in the source (INSERT),
  • changes between source and target (UPDATE) as well as
  • lost records, which only appear in target (DELETE).

In the context of a production system the latter case is the nasty one: You cannot simply delete records when you already have child records (i.e. foreign key relationships) in your system. So this meant shovelling data around manually. Thus my programme only handles the first two cases automatically and simply warns about the third case.

hxht
Moving around data and breaking some rules for the sake of backwards compatibility.

Object-relational mapping and a set()

The central piece of my Python code is an object-relational mapping between every database record and my custom class:

class Room(object):
    
    def __init__(self, pk, name, size):

        self.pk = pk
        self.name = name
        self.size = size

The “Syncer” does the work of fetching from target and source databases, comparing and taking proper action. I store all the records in a Python set() – a very powerful data structure for the task.
class RoomSyncer(object):
    
    def __init__(self):
        
        self.target_rooms = set()
    
    def get_target(self):
        """Fetch rooms from production db"""
        
        ...
        
        for room in target:
            ...
            self.target_rooms.add(
                Room(pk, name, size )
                )    

If you run into the problem that your target and source do not resemble each other (i.e. that their attributes are different) you cannot instantiate with the __init__() method in both cases. Use a factory method instead:
class Room(object):

    ...

    @classmethod
    def from_source(cls, pk, other_name, size):
        
        # do some magic to make objects simiar
        name = other_name
        
        return cls(pk, name, size)

class RoomSyncer(object):
    
    def __init__(self):
        
        ...
        
        self.source_rooms = set()
    
    def get_source(self):
        """Fetch rooms from staging db"""
        
        ...
        
        for room in source:
            ...
            self.source_rooms.add(
                Room.from_source(pk, other_name, size )
                )          

set() operations

So far we have two sets filled with our objects: target and source. If you subtract the target from the source you’ll get the newly arrived objects:

# rooms only in source
rooms_to_add = self.source_rooms - self.target_rooms

Oh no! The code won’t work since Python does not know whether your objects are equal or not. Hence the set operations won’t work out of the box. So you have to override the __hash__ and __eq__ methods – Python will then compare as you  would expect (more info on stackoverflow):
class Room(object):
    
    ...

    def __eq__(self, other):
        
        return self.pk == other.pk
    
    def __hash__(self):
        
        return hash(self.pk)

With this simple update you can now easily determine objects that only appear on one side. The last thing we need to do is to cover the UPDATE case. By overriding the methods above we implicitly confine the powers of Python’s set data structure. For a more sophisticated search for updates we’ll have to look at every attribute. Luckily for us, a Python object is just a simple dictionary under the hood. As a consequence we simply have to test the candidate dictionaries for equality:
class Room(object):
    
    ...

    def cmp(self, other):
        # is entire object equal?
        
        return self.__dict__ == other.__dict__

class RoomSyncer(object):
    ....

    def cmp_rooms(self, rooms):
        """objects appear on both sides"""

        rooms = self.target_rooms.intersection(self.source_rooms)

        for r in rooms:

            # simply get one object by key
            t = self._get_target(r.pk)
            s = self._get_source(r.pk)

            if t.cmp(s):
                # objects are identical
                ...
            
            else:
                # update
                ...

    def _get_target(self, pk):
        for r in self.target_rooms:
            if r.pk == pk:
                return r
    
    def _get_source(self, pk):  
        for r in self.source_rooms:
            if r.pk == pk:
                return r

IT project management

Kommerzielle Software, Open Source oder Eigenentwicklung?

Mit meiner Studierendengruppe an der FH-Wien habe ich Vor- und Nachteile unterschiedlicher Lösungswege bei der Softwareauswahl diskutiert. Wohl wissend, dass es Mischmodelle gibt, haben wir zunächst drei Extremfälle herausgearbeitet:

  • Kommerzielle und gleichzeitig proprietäre Software – also im Idealfall ein Standardprodukt, welches das betriebliche Problem abdeckt. Es wird lizenziert, dazu gibt es Wartungsverträge, der Anbieter kümmert sich um Installation, Roll-Out und Betrieb.
  • Nicht-kommerzielle, freie Software – also im Idealfall ein Open Source Projekt samt aktiver Community, welche ebenso an dem Problem arbeitet. Das Unternehmen kümmert sich selbst um Installation, Roll-Out und Betrieb.
  • Eine in-house oder externe (Eigen-)Entwicklung – also eine Software, die erst geschrieben werden muss. Noch lange vor der Installation gibt es also ein Softwareprojekt mit Anforderungsanalyse, Umsetzung, Tests, usw.

Sinn der Diskussion war zu zeigen, dass es keine universell beste Lösung gibt. Vielmehr konnten wir fünf Ziel-Kriterien definieren, die in Konkurrenz zueinand stehen:

  • Investitionskosten
  • Folgekosten
  • Geschwindigkeit (Projektdurchlaufzeit)
  • Risikominimierung (Wie “sehr” darf dieses Projekt nicht schief gehen?)
  • Flexibilität (Anpassungsfähigkeit, Weiterentwicklungen)

Lege ich meinen Fokus etwa auf maximale Flexibilität, so werde ich bei der Eigenentwicklung landen. Denn hier stehen mir sämtliche Freiheitsgrade offen, das Ganze allerdings zum Preis der Geschwindigkeit.

randbedingungen
Das Software-Fünfeck.

Im konkreten Einzelfall sind uU einige Kriterien gut miteinand zu vereinbaren, in anderen Situationen widersprechen sie sich total. Die fünf Punkte werden allerdings bei der Zielsetzung von Softwareprojekten hilfreich sein.

Parallel zu diesen Zielkriterien konnten wir drei Randbedingungen herausarbeiten, die den Entscheidungsprozess begleiten. Auch hier gilt, dass die Punkte an die konkrete Situation angepasst werden. IT-Sicherheit wiegt für eine Bank wohl deutlich höher, als für einen Sportverein. Die Randbedingungen sind:

  • Sicherheit
  • Zufriedenheit (Usability)
  • Bestehendes Ökosystem (Passt dieses neue Stück Software in meine IT-Landschaft?)
ddd
Die Randbedingungen.

Wer Interesse an einer Checklist für die Auswahl konkreter Software-Produkte hat, dazu gab’s bereits einen Blog-Beitrag.

kitchen-hacks

“Brotstrap” (bootstrap für Brot)

In den vergangenen zwei Jahren habe ich festgestellt, wie ähnlich sich Kochen und Programmieren ansich sind: Ohne algorithmischen Denken, trial & error und dem Prinzip Open Source geht es hier und da nicht. Ich backe seit inzwischen über einem Jahr mein eigenes Brot und ernte immer wieder Komplimente, vor allem aber auch Erstaunen, dass das Ganze so einfach ist. Hier also mein Rezept, wie man mit knapp 20 Minuten Arbeitszeit Weißbrot bäckt.

Requirements

-- 8< --
                                   exists
Zutaten: 435g Weizenmehl glatt       [ ]
         350g warmes Wasser          [ ]
          12g Kochsalz               [ ]
           1g Hefe/Germ (Sackerl)    [ ]
              Kürbiskerne            [ ]
              Haferflocken           [ ]
Tools:      1 Bräter (Beispiel)      [ ]
            1 Teigspatel (Beispiel)  [ ]
            1 Schüssel (Beispiel)    [ ]
              Backpapier             [ ]
              Frischhaltefolie       [ ]
            1 Gummiring              [ ]
            2 Geschirrtücher         [ ]
-- 8< --

Timeline

Der Teig benötigt ausreichend Zeit zum Gären unter Luftabschluss – einfach Frischhaltefolie über die Schüssel und mit Gummiring befestigen. So entstehen einerseits Luftlöcher im späteren Endprodukt, andererseits bekommt das Brot dadurch einen leicht säuerlichen Geschmack. Ist der Teig am nächsten Tag fertig, benötigt man eine weitere Stunde Durchlaufzeit.

    +----------------+
    | Teig fertigen  |  5min
    +--------+-------+
             |
             |
             |  16-24h Pause
             |  Teig ruht in der Schüssel
             |  unter der Folie
             v
    +------------------------------------+
    |+----------------+ +---------------+|
    ||Flocken u. Kerne| |Bräter und Ofen||
    ||ausbreiten      | |auf 270° heizen||
    |+-------+--------+ +---+-----------+|
    |        |              |            |
    |+-------v--------+     |            |
    ||Backen          |<----+  30+15mmin |
    ||25-30 mit Deckel|                  |
    ||10-15 ohne D.   |                  |
    |+----------------+                  |
    +------------------------------------+
             +
             |  15-30min Pause
             |
             v
    +----------------+
    |     Essen      |
    +----------------+

Teig fertigen: Pre-processing

ff
Mehl, Salz und Hefe durchmischen.
gjhk
Wasser hinzufügen und rühren, bis es nicht mehr staubt. Kneten verboten!

Flocken und Kerne: Compilation

ghgh
Am Backpapier Mehl und Haferflocken ausbreiten. Kürbiskerne in der Mitte anhäufen.
hh
Teig aus der Schüssel leeren.
rr
An den Rändern nach oben/innen umschlagen – ansonsten allerdings nicht viel bewegen. Dank des Mehls sollte das Ganze nicht kleben. wenn doch, Mehl oder Haferflocken hinzufügen.

Installation

Achtung: Topf ist brennheiß!

ff
Den heißen Bräter zügig raus aus dem Ofen und Teig hinein stülpen. Die Kürbiskerne sind nun oben.
g
Bräter mit Deckel schnell zurück in den Ofen und 25-30 Minuten bei 270° Ober-/Unterhitze backen.

Tests

kk
Unit test: Nach 16 bis 24 Stunden Gärung unter Frischhaltefolie sollten sich Bläschen gebildet haben.
jj
Function test: Nach 25-30 Minuten bei 270° (mit Deckel!) ist das Brot leicht gebräunt. Deckel runter und weitere 10-15 Minuten im Ofen lassen. (Energiesparer können bereits jetzt abschalten.)
hh
Acceptance Test: Kundenzufriedenheit erkennt man, wenn das Brot schnell weg ist.

User Interface

11 17
Output 17.Nov 2012.
3 17
Output 17. März 2012.
8 17
Output 17. August 2012.

… mir war bislang selbst nicht bewusst, dass der 17. eines Monats bei uns der Brottag zu sein scheint.

Customizing

Ist das Brotstrap Script ohne Fehlercodes ausgeführt, so sind der Kreativität keine Grenzen gesetzt. Kürbiskerne und Haferflocken können durch andere Produkte aus der Kategorie Cerealien getauscht werden, auch für Weizenmehl gibt es diverse Derivate. Meine Ideen gehen weiters in Richtung getrocknete Tomaten oder Oliven.

Licence

Die Brotidee geht auf ein wunderbares Abendessen mit Katharina Seiser zurück, deren Blog ich wärmstens empfehlen möchte. Wer an Spitzenleistungen interessiert ist, sollte sich daher ihr deutlich detailliertes Rezept durchlesen.