So bitte nicht – Schnittstellen

Es ist an der Zeit die lose Reihe mal wieder etwas weiter zu führen, mit einem Thema das mich die letzten Tage wiederholt beschäftigt hat: Schnittstellen.

In der IT-Welt beschreiben Schnittstellen verschiedenste Dinge – den meisten vertraut sind die Begrifflichkeiten aus der Hardware – hier erkennt man auch noch recht klar die Eigenschaft einer Schnittstelle, sie bildet die Grenze zwischen zwei Geräten, verallgemeinert von Systemen. Welches System an einer Schnittstelle andockt ist im ersten Moment unerheblich – die meisten Schnittstellen sind universell gehalten: Ob man eine Tastatur oder eine Maus in eine USB-Buchse einstöpselt ist im ersten Moment unerheblich. Die Schnittstelle ist so ausgelegt, dass über verschiedene Ebene hinweg eine Kommunikation nach einem bestimmten Muster stattfinden kann. USB beispielsweise gibt verschiedene Operations-Modi für unterschiedliche Anwendungszwecke – von der Maus als Eingabegerät über den GPS-Sensor bis hin zum Speichermedium. Die häufig verwendeten Hadware-Schnittstellen sind durch verschiedene Normen und Vorschriften festgelegt. In der Industrie gibt es zudem verschiedene Eigenentwicklungen für spezielle Zwecke, diese sind nicht zwingend so universell wie USB, aber sie erlauben auch weiterhin den Austausch von Informationen von einem System zu einem anderen hin. Im Fahrzeug z.B. per CAN-Bus: Dort meldet die Klima-Regelung an die Klima-Anlage die gewünschte Temperatur und die aktuelle Temperatur, der Klima-Kompressor wird daraufhin entsprechend in der Leistung geregelt.

Soweit einmal der Sinn und Zweck von Schnittstellen an anschaulichen Beispielen, aber mit der Hardware ist ja noch lange nicht Schluss. Vielmehr ist das ja noch alles nachvollziehbar und man kann sich unter der Definition einer Schnittstelle sehr leicht etwas vorstellen. Aber auf etwas höherer Abstraktionsebene existieren weiter Schnittstellen. Diese sind nicht so leicht erkennbar, aber dennoch vorhanden.

Jeder Programmierer der nicht absolut blutiger Anfänger ist, kennt die Erzeugung von wieder verwendbarem Code – nahezu jede Programmiersprache (von einigen Exoten einmal abgesehen) kennt den Begriff einer Funktion oder Methode. Das Prinzip dieser Konstrukte lehnt sich an der Mathematik an: Meist gibt man eine bestimmte, wohldefinierte Menge von Werten in eine Funktion hinein, die daraus etwas errechnet, etwas auslöst etc. in aller Regel gibt es auch noch einen Rückgabe-Wert (je nach Programmiersprache gibt es auch Möglichkeiten mehrere Werte zurück zu geben, entweder über den Stack oder einen reservierten, gemeinsam genutzten Speicherbereich, oft als Heap bezeichnet – das hier zu erläutern würde allerdings zu weit führen …). Wenn man das Prinzip der Funktionen einmal verstanden hat, sind diese einfach praktisch zu verwenden. Wichtig ist hierbei immer die Parameter-Reihenfolge (wie in der Mathematik auch) und je nach Programmiersprache auch noch der Werte-Typ der Parameter (starke oder schwache Typisierung: In Skriptsprachen wie PHP und Perl ist der Typ egal, in Java oder C müssen auch die Typen übereinstimmen – für beide Standpunkte gibt es gute Argumente, ich tendiere mittlerweile eher zu starker Typisierung und würde sie mir auch in PHP wünschen … aber auch das würde diesen Artikel leider sprengen). In ganz ähnlicher Weise lässt sich das auf objektorientierte Programmierung ausweiten. Auch dort gelten die gleichen Grundsätze, zusätzlich gibt es noch ein paar nette Gimmiks on top.

Gehen wir noch eine Abstraktionsstufe höher, dann sind wir bei Abläufen und Prozessen und eigentlich nicht mehr zwingend in der Softwarewelt verhaftet. Jeder Austausch von Daten über Systemgrenzen hinweg benötigt eine Schnittstelle. Egal ob die beiden Systeme nun Rechner sind, Menschen, Unternehmen oder sogar jede beliebige Kombination aus den vorgenannten. Überlegen Sie einmal inwiefern ein Rechner ihnen bestimmte Schnittstellen eröffnet und wann sie diese nutzen. Etwas Hirnakrobatik, aber wenn man es mal gemacht hat, sind viele Dinge am Rechner mit einmal logisch verständlich.

Was leider immer wieder schief geht ist die Spezifikation entsprechender Schnittstellen in dieser Abstraktionsebene. Oftmals sind sich die beiden Kommunikationspartner nicht bewusst, dass eine klar definierte Sprache/Syntax/Form der Kommunikation notwendig ist um Missverständnisse und Fehler zu vermeiden. Das beginnt meist mit solchen Sprüchen “wir bekommen dann eine Datei, da steht alles drin was uns unser Partner mitteilen möchte und was wir wissen wollen…”. Wie diese Datei am Ende aussieht ist bei solchen Sachen meisten leider erst einmal egal – dank der Intelligenz vor dem Monitor ist es dem Betrachter auch egal ob ein Textdokument als reiner Text, Word-Datei, Vektorgrafik oder als pixelbasierte Bilddatei vorliegt. Lesen und verstehen kann der Mensch das alles. Problematisch wird es wenn es dann an die Automatisierung geht. Da sind nicht alle Formate wirklich gut geeignet – jeder der einmal versucht hat aus einem abfotografierten Text wieder einen editierbaren Text zu machen weiß wovon ich spreche: Ohne Optial Character Recognition (OCR – Texterkennung) geht da gar nichts und selbst die ist meist nicht sonderlich fehlerfrei, von der Semantik der einzelnen Texteile und dem Layout mal ganz zu schweigen. Besser sind dann schon Excel oder Word-Dateien wobei die auch nicht immer kompatibel untereinander sind. Es gilt auch hier das alte Mantra: Je einfacher, je simpler um so besser. In der IT hat man für diverse Datentypen gut erprobte Ablage-Möglichkeiten entwickelt. Tabellen kann man recht gut in SQL oder CSV ausdrücken, wenn es etwas weniger stark strukturiert ist, kommen XML-Varianten in Frage.

Was lernen wir aus diesen Sachen?

Erstens: Es geht nicht ohne Schnittstellen, selbst innerhalb eines Programms gibt es in der Regel verschiedene Module oder Funktionen die Daten untereinander austauschen und so zum Gesamtsystem beitragen. Diese Schnittstellen sind in der Regel durch die verwendete Programmiersprache und die Programmierweise vorgeben (funktionale, prozedural oder objektorientiert).

Zweitens: Schnittstellen nach außen hin (egal ob Mensch oder Maschine) müssen klar erkennbar und definiert sein. Man denke hierbei immer an die Zukunft und überlege ob es vielleicht sinnvoll ist, an einigen Stellen bereits die Option für eine externe Schnittstelle zu schaffen, später nachrüsten ist immer schwierig und bestehende Schnittstellen verändern ist wie beim Auto plötzlich Kupplungs- und Gas-Pedal zu vertauschen: Die Konsequenzen sind bestenfalls amüsant, schlimmstenfalls gefährlich und es kostet sehr viel Nerven…

Drittens: Bereits bei der Planung von Systemen berücksichtigen welche Daten mit externen Systemen automatisiert ausgetauscht werden sollen und wie. Einerseits muss klar definiert sein, welche Daten an externe Systeme bereit gestellt werden sollen. Evtl. ändert sich durch solche Anforderungen der Erfassungsbedarf in der eigenen Anwendung/dem eigenen System oder lässt einigen Sachverhalten eine neue Priorität zukommen. Auch wichtig ist das Format – dieses muss für den Anwendungsfall geeignet sein, Bilder in Word einzufügen um sie daraus wieder zu extrahieren ist ungeschickt – einfacher geht es wenn man Bilddateien direkt verschickt. Ist die Information tabellenförmig, so kommen Excel oder die simple Variante CSV (comma separated values) in Betracht. Für komplexere und ggf. nicht immer einheitliche Datenaustausche kann man sich mit XML behelfen. Wobei immer zu beachten ist: In aller Regel steht hinter jeder XML-Datei und jedem System auch wieder ein relationales Backend (aus Performance-Gründen) – es lohnt also, ggf. einmal auch die Betreuer und Entwickler des Partner-Systems über deren Struktur zu fragen.

 

 

Programmier-Ärger mit VBA

Da hab ich doch heute mal wieder ein tolles Projekt “geerbt” – für eine Tauschaktion sind in größerer Menge Serienummern-Etiketten zu erstellen. An und für sich ja eine recht einfache Aufgabe.

Trickreich wird sie dadurch, dass ein bestimmtes Muster eingehalten werden muss und auch die Nummern noch in verschiedenen Farben gedruckt werden sollen. Hintergrund der Geschichte ist: Damit es weniger Probleme mit dem Einlesen/Abschreiben von Seriennummern gibt, erhält der Mitarbeiter einen vorgedruckten Bogen mit Seriennummern, jede Nummer ist in leicht anderer farblicher Schattierung doppelt vorhanden: Eine für auf das Gerät, eine für ins Protokoll. Pro getauschten Teil sind es also insgesamt 4 Nummern – damit man sich nicht so leicht vertut sind die alten und neue Geräte-Kleber auch noch jeweils in stark unterschiedlichen Farben gehalten.

Auch die Größe der Etiketten steht bereits fest: Avery Zweckform 3666 – 65 kleine Klebeschildchen auf einem Bogen A4, je 21,2mm hoch und 38mm breit. Weitere Anforderung an das Hilfsmittel: Farben bitte einstellbar falls noch etwas anderes benötigt wird – und die Startnummer sollte man auch noch festlegen können, damit es keine doppelten Seriennummern gibt.

Immerhin man hat schon mal etwas vorbereitet: Eine Excel-Datei mit   einem Bogen und einer Startnummer zum eingeben – quick&dirty aber es tut. Problematisch: Man kann immer nur 32 Nummern damit erzeugen, dann ausdrucken und die nächste. Bei mehr als 1000 Seriennummern die benötigt werden sicherlich nicht das optimale Tool.

Die ersten Hürden sind schnell genommen: Die notwendige Schriftart auf dem Rechner installiert damit man Barcodes erzeugen kann ist doch schon mal die halbe Miete, dann gibt es nämlich keine problemtischen Schriftzeichen mehr sondenrn tatsächlich passende Barcodes.

Die eigentliche Freude beginnt danach – da es ja schon etwas gibt versucht man natürlich die bestehende Datei weiter zu nutzen – leider ein Schuss in den Ofen – denn die Felder sind alle “hardcoded” als Referenz in den einzelnen Excel-Feldern hinterlegt.

Gehen wir das ganze also doch programmatisch an – erst mal trenne ich die Eingabe von der Ausgabe ab, damit nicht irgendwelche unnötigen Zeilen und Spalten herumschwirren die hinterher den Ausdruck schwierig machen.

Danach beginnt die eigentliche Kür – VBA-Programmierung, lange ist es her, dass ich damit gearbeitet habe – und um so kruder wird der Einstieg. Immerhin es gibt recht viele nette Beispiele im Netz, anhand derer kann ich mich langsam vortasten.

In einem ersten Schritt erzeuge ich mir das “Raster” für die Etiketten  automatisiert – leichter gesagt als getan – was man in Excel sonst mit der Maus einfach mal “hinlupft” funktioniert natürlich nicht mehr, wenn man es sauber programmiert haben will – unter anderem muss man daran denken, dass ein Etikett rechts und links einen Rand bekommt und nicht nur einfach einen Abstand zwischen zwei Barcodes hingemurkst wird. Schon bei der Aktion fallen mir die kruden Werte auf mit denen Excel hantiert – eine vernünftige “Maß-Einheit” ist leider nicht zu erkennen. Aber egal – die ungefähren Werte wurden ja schon empirisch ermittelt.

Insgesamt finde ich die Programmierung sehr holprig – vor allem der eingebaute Editor in Excel nervt mit seiner permanenten Kontrolle und Fehlermeldungen – ein Stück Code von woanders her kopieren – nicht möglich wenn in der aktuellen Zeile noch ein Fehler ist. Ich bin ja für Fehlerhinweise dankbar, aber so aufdringlich muss es doch nun wirklich nicht sein – selbst PHP-Skripte und Eclipse beschweren sich nicht derart – spätestens wenns ans Laufenlassen geht, aber dann ist der Fehler ja auch gerechtfertigt wenn einer drin ist.

In die selbe Richtung gehen die Fehlermeldungen zur Laufzeit: “Objektinterner Fehler” ist eine sehr aussagekräftige Fehlermeldung – mit ein wenig Recherche im Code kommt man dann darauf, dass ein negativer Index das Problem sein könnte…

Die eigentliche algorithmische Aufgabe liegt dann darin, die Verteilung der Nummern auf die Seite zu berechnen – in gewisser Weise hat das etwas von Speicherzugriffsberechnungen aus der  technischen Informatik. Lästig sind dabei zwei Dinge: Excel bzw. VBA indiziert nicht wie gewöhnliche Programmiersprachen das tun ab 0, sondern weil es ja so viel besser ist beginnen alle Indizes mit 1 … und genauso intelligent verhält es sich bei Ganzzahlen: Wenn man dividiert wird automatisch korrekt gerundet – das gibt natürlich bei der Reihen und Spaltenberechnung ziemliches Chaos wenn man über die Hälfte eines Blattes hinaus ist.

Zusätzliche Nettigkeit der Sache an sich: 32 Nummern, also insgesamt 64 Etiketten passen ja nicht ohne weiteres auf 65 Felder – eines muss frei bleiben. Das wäre noch halb so wild – aber die Aufteilung 13×5 passt natürlich wie faust auf Auge zu einer geraden Anzahl Nummern. Also wird in der untersten Reihe nicht untereinander sondern nebeneinander gedruckt.

Auch total ungewohnt für mich: Das zusammenführen von Strings oder Zahlen – in PHP ist es der Punkt zum Konkatenieren, in vielen anderen Sprachen ist es das “+” (vor allem wenn es stark typisierende Sprachen mit überladenen Operatoren sind) in VBA ist man den Sonderweg des “&” gegangen – wer auch immer sich das hat einfallen lassen.

Das Einfärben der entsprechenden Bereich anhand eines vorgegeben beschäftigt mich auch noch mal etwas – die Angaben finden sich natürlich wieder da wo man sie nicht vermutet – wer sucht denn bitte die Hintergrundfarbe einer Zelle in Cell.Interior.Color und die Farbe in Cell.Font.Color? Ganz zu schweigen von etwas wie Fett oder kursiv – das wird nicht per Style festgelegt sondern per true oder false … ganz merkwürdige Sache, wenn man gewohnt ist mit HTML und CSS zu arbeiten.

Am Ende habe ich dann immerhin eine Lösung die funktioniert – die Performance empfinde ich persönlich als “lausig”, man muss Ewigkeiten warten bis die Seite endlich fertig aufgebaut ist, und das selbst wenn man nur “200” Seriennummern benötigt. Zusätzliche Schwierigkeiten bereiten mir dann noch die Maßeinheiten – damit es auf dem Drucker aus passt ohne dass die Schilder aus dem Passer laufen … Interessant wo die krummen Werte für die Umrechnung herkommen – die sind weder metrisch noch Zoll – wahrscheinlich eine interne Microsoft-Spezial-Längeneineheit, das würde dann auch erklären warum sie in der Breite anders umgerechnet wird als in der Höhe …

Ich denke ich werde mir den Spaß nochmal erlauben, es doch in PHP zu schreiben und daraus direkt ein PDF zu erzeugen – die Hauptarbeit mit der Zeilen und Spaltenberechnung ist ja schon gemacht….

Aber ich weiß mal wieder warum ich doch “echte” Programmiersprachen einer Markosprache einer Office-Suite vorziehe – eine Entwicklungsumgebung kann Office einfach nicht ersetzen.