Docker healthchecks – things to consider

While working on a recent docker project I encountered an issue when it comes to health checks. You may define a health check for a container from within your Dockerfile, such as

HEALTHCHECK --interval=5s --timeout=5s --start-period=20s
         --retries=5 CMD wget --output-document=- 
         --quiet --tries=1 http://127.0.0.1

The syntax is quite simple to understand, you basically define how and when the health check should be executed and which command(s) to use. Breaking things down from the example

  • –interval=5s – run the check every 5 seconds
  • –timeout=5s – maximum time to wait for the health check to complete
  • –start-period=20s – allow some time for the process to be monitored to come to a functioning state, avoids false alarms during startup, in this case we allow 20 seconds
  • –retries=5 – only trigger an alarm after 5 unsuccessful tries (non zero exit code) – this helps avoiding false alarms in case the process is under heavy load
  • After the CMD follows the command to execute, this is done from inside the container, in the given example we check for the webserver to deliver something indicating the server is working properly

However every one should consider on how flexible the health check should be to match as many use cases as possible. This is especially true if you are dealing with web-based endpoints as pointed out in the example.

Continue reading

Why IPv4 is not better compared to IPv6 in terms of security of your home/office network

If you look at the internet at the moment, from a more technical point of view, you will often find users complaining about the „new“ Internet-protocol IPv6. Most of the time the complaints are about issues with the Internet-Service-Provider ISP used.

I will focus on the issue based on my experience in Germany (things might be different in your location, feel free to leave a note in the comments). In fact the technical introduction of IPv6 went unnoticed for most of the average users. This is partly due to the fact, that in the beginning there were not so much services that were accessible via IPv6 (a typical chicken-egg-problem) and most operating systems seamlessly degrade to IPv4 if a service is not available in IPv6.

Continue reading

PowerDNS mit Pi-Hole auf RasPi

Eines der etwas länger schon mal angedachten Projekte, welches ich dann aufgrund Zeitmangels und auch etwas Frustration in die Ecke gelegt hatte ist ein eigener, lokaler DNS-Server den man auch schnell aktualisieren kann – wer häufiger in verschiedenen Projekten arbeitet weiß es zu schätzen wenn man den Stall der Entwicklungs-Container nicht per IP-Adresse auswendig lernen muss, sondern ihn per sprechenden Namen ansprechen kann. In diesem Post geht es erst einmal darum die Grundlagen zu schaffen, auch das ist bereits etwas mehr Arbeit als ich gedacht hätte.Wichtige Eckpunkte / Material zum Nachbauen:

  • Raspberry Pi (inklusive Netzteil)
  • als DNS-Server kommt PowerDNS zum Einsatz
  • MySQL/MariaDB als Datenbank für die DNS-Einträge
  • DNS-Dist als Loadbalancer für DNS-Queries
  • PiHole als Resolver mit Blacklist
  • Docker als Virtualisierung für alle Services
  • IPv6 als primäres Netzwerkprotokoll, IPv4 nur als Fallback

Continue reading

Datenbankversionierung – Vor- und Nachteile bestimmter Praktiken

Gerade hatte ich mal wieder ein Schlüsselerlebnis in meiner Programmierung. In diesem Fall gab es ein Kollision mit YAML (YAML Ain’t Markup Language) – ich spreche explizit von Kollision, denn meine Erfahrung ist für den verwendeten Anwendungsfall einfach nur schlecht bzw. ich sehe leider aktuell einige Nachteile.

Datenbank-Schemata versionieren

Zur Versionierung von Datenbank-Änderungen bzw. um den Weg von einer „leeren“ Datenbank bis hin zum aktuellen Stand der Entwicklung zu beschreiben verwendet man in der Regel entsprechende Tools wie Liquibase oder Flyway. Das Prinzip ist im Prinzip immer das Gleiche – mit ein wenig „Rahmenwerk“ drum herum steuert man die Ausführung der Datenbank-Statements. Dabei kann man auf verschiedene Szenarien eingehen, einer der häufigst genannten ist, dass man ein Produkt mit verschiedenen Datenbank-Servern laufen lassen kann. Das ist beispielsweise wichtig wenn man Software an Firmen (seltener private Anwender) ausliefert, sich aber darauf einstellen muss, dass dort nicht unbedingt die aktuelle Version von MySQL läuft sondern eben im Zweifel auch ein PostgreSQL oder eine andere (kommerzielle) Datenbank wie Oracle. Continue reading

Frameworks in der Programmierung – wirklich so essentiell wie immer behauptet?

Wenn immer man sich aktuell umschaut auf dem Jobmarkt, dann sind im Softwarebereich immer Erfahrungen mit Frameworks gefordert oder zumindest gern gesehen. Nun habe ich ja auch einige Erfahrung und ich sehe das immer wieder etwas zwiegespalten.

Machen wir uns erst einmal ein Bild mit welchem Ziel Frameworks entstanden sind. Mehrheitlich ist ihr Ziel die Entwicklung von Software zu vereinfachen und zu beschleunigen. Der Entwickler soll sich weniger Gedanken machen müssen über einige technische Details und soll sich ganz und gar auf seine Applikation konzentrieren können. Das klingt ja erst einmal nicht schlecht. Wer möchte sich schon gerne mit den Details einer TCP/IP-Verbindung womöglich sogar noch Verschlüsselung beschäftigen müssen wenn er nur Daten von einem Server irgendwo im Netz abholen möchte. Das klingt doch schon insgesamt sehr verlockend, aber jede Medaille hat bekanntlich zwei Seiten. Jede Technologie bringt ihre Tücken und ggf. auch Einschränkungen mit. Eine dieser Einschränkungen ist es, dass ein Framework gewisse Regeln vorgibt an die man sich halten muss, wenn man es verwendet. Das muss noch nicht mal negativ sein, vermeidet es doch, dass man sich unfreiwillig irgendwo eine Bremse einbaut, die man ggf. später wieder ausbauen muss.

Da ich relativ viel im Bereich Webentwicklung mache, beschränke ich mich im Folgenden bei den Beispielen auf dort häufig anzutreffende Frameworks und meine Erfahrungen mit Ihnen.

Eines der für mich wichtigsten Frameworks ist und bleibt JQuery und es ist eines der wenigen Frameworks, das ich schätzen gelernt habe. Warum das so ist? JQuery schreibt mir als Entwickler nicht irgendein Gerüst vor, vielmehr gibt es eine Reihe von best-practices und jede Menge Beispiele. Brauche ich aber nur eine simples Ein- und Ausblenden eines Formularelements dann muss ich mich nicht erst mit dem Bauen und Administrieren von Formularen im Sinne des Frameworks beschäftigen. Stattdessen kann ich es einfach aus und einblenden wie es gerade nötig ist. Minimaler, schlanker Code mit dem ich das Element finden und damit etwas machen kann. Derartige Abstraktion (noch dazu über Browser-Grenzen hinweg) finde ich sehr hilfreich. Auch wenn sich JQuery selbst als Framework bezeichnet – für mich hat es eher den Charakter einer umfangreichen Library (aber Library klingt natürlich so altbacken, das kannten ja schon die Entwickler aus C … daher kann man das natürlich in einem modernen Umfeld nicht offiziell so nennen).

Das nächste Framwork, mit dem ich auch immer noch arbeiten darf, ist ZendFramework. Mittlerweile ist davon die Version 3 auf dem Markt, vor allem nachdem die Version 2 reichlich wenig Akzeptanz gefunden hat. Im Arbeitsumfeld sind wir noch größtenteils mit Zend1 unterwegs. Das wird mittlerweile definitiv nicht mehr weiter entwickelt, aber wenn es läuft und es keine sicherheitskritischen Probleme gibt gilt die alte Weisheit: „never touch a running system“. Leider muss ich sagen, dass mir das Framework häufig mehr Arbeit verursacht als es je einsparen könnte. Vieles ist einfach nur sehr umständlich, trotz oder gerade wegen der vorgegeben Struktur. Auf der einen Seite ist sie recht starr – es gibt nur eine Möglichkeit bestimmte Ergebnisse zu erreichen. Auf der anderen Seite sind die Funktionen dann doch recht häufig wachsweich – nahezu an jeder Stelle kann (oder muss) man Parameter als indiziertes Array übergeben.

Richtig enttäuscht hat mich das Framework dann bei der Umsetzung von Commandozeilen-Parametern. Im Quellcode des Framworks stehen noch jede Menge offene Todo-Punkte. Die Funktion an und für sich kann man „out of the box“ fast nicht gebrauchen, denn unbekannte Parametern führen zwangsweise zu einem Abbruch der Verarbeitung. Man kann natürlich dann kurzerhand die Framework-Klasse als Basis hernehmen und die notwendigen Routinen in einer eigenen Klasse überschreiben. Aber so wirklich prickelnd ist das nicht, noch dazu bindet man sich damit sehr stark an das Framework – will man die Funktionalität in einem anderen Projekt wieder verwenden, so muss man die dort mit hoher Wahrscheinlichkeit neu implementieren. Ich habe mich in diesem Falle dazu entschieden, es dann gleich selbst zu machen, PHP bietet von Haus aus bereits recht umfangreiche Funktionen, unter anderem sei hier Getopt genannt.

Natürlich wollte ich auch mal schauen was aktuelle Frameworks so können und vielleicht machen die es ja besser. Also habe ich mir Symphony angeschaut. Auf den ersten Blick ist wieder alles „nice and shiny“. Sobald man aber etwas damit arbeiten möchte, musste ich feststellen: Die Doku und die Beispiele sind einfach nur sehr akademisch gehalten. Ich habe das Framework nach einigen Versuchen ad acta gelegt, weil es ein verdammt hoher Aufwand ist, einen recht simplen Fall abzubilden: Man nehme eine einfache 1:n-Relation wie sie jede Datenbank ohne Probleme abbildet: Eine Art News-Artikel wird einer Kategorie zugeordnet. Ein priviligierter Nutzer ist in der Lage die Tabelle der Kategorien bei Bedarf zu erweitern. Ein klassischer Fall, den man im User-Interface gerne und effizient mit Drop-Down-Menu realisiert. In Symfony ist das ein echter Krampf, spätestens bei der Verwendung der Anzeigenamen als Array-Indizes und der eindeutigen Werte als Array-Werte habe ich mir nur noch an den Kopf gelangt. Das funktioniert zwar dank UTF-8-Unterstützung aber es widerspricht sämtlicher Intuition. Die Beispiele zu Formularen sind da auch keine wirkliche Hilfe – da wird einfach darauf gesetzt, dass man es ja doch per Text umsetzen könnte. Das mag für schnelle Projekte sinnvoll sein, aber im Businessumfeld sind die Regeln dann doch etwas strikter. Man kann es natürlich auf der Server-Seite dann wieder prüfen und eine Fehlermeldung ausspucken – aber warum muss der Anwender erst Tippfehler machen und ggf. raten wenn es nur wenige valide Auswahlen gibt?

Das ist jetzt sicherlich keine umfassende Evaluation, aber in vielen Punkten gleichen sich die Frameworks dann doch. Ich werde mir auch noch weitere anschauen. In einem der nächsten Posts werde ich einige generelle Kritikpunkte die mir bisher bei nahezu jedem „Backend-Framework“ aufgefallen sind näher ausführen.

 

Magento 2 – Rest-API oder Reste-API?

Beruflich darf ich mich gerade mit Magento als Shop-System auseinandersetzen. Auf den ersten Blick ein Shopsystem wie es viele auf PHP-Basis gibt. Jedes System hat eine andere Geschichte und damit seine Eigenheiten und besonderen Pluspunkte. Leider finde ich von den Pluspunkten bei Magento für meinen aktuellen Fall etwas zu wenig bis gar keine. Wir haben eine externe Datenquelle, welche verschiedene Verwaltungsabläufe abbildet, an deren Ende eine Reihe von Produkten für den Shop stehen.

Anfänglich war ich vielleicht etwas naiv und dachte: Ein paar Zeilen SQL und dann lässt sich das Datenmodell sicherlich so extrahieren, dass man recht schnell und zuverlässig die Daten vom Quellsystem in den Shop überführen kann. Leider ist das nicht der Fall, denn Magento hat sich als Datenmodellierung für EAV entschieden. Damit ist nicht die erste allgemeine Verunsicherung gemeint (auch wenn die dann nicht mehr weit her ist) sondern eine Modellierungstechnik namens Entity-Attribute-Value. Im ersten Moment klingt das Modell für einen Shop sogar sehr lohnenswert, denn eine Shopsoftware muss ja ggf. mit verschiedensten Waren zurecht kommen. Genau das ist mit EAV möglich: Man bildet die Modellierung von zusätzlichen Eigenschaften über weitere Tabellen ab. So vernünftig das anfänglich klingen mag, um so schwieriger wird die Umsetzung in der Praxis. Da man bestimmte Attribute ja auch in verschiedenen Fällen wieder brauchen kann hat man die noch eine Stufe weiter abstrahiert. Das Ergebnis ist ein sehr umfangreiches Modell, das Anna Völkl schön aufbereitet hat. Übersichtlich ist etwas anderes, auf diesem Datenmodell  manuell direkt auf Tabellenebene zuzugreifen kann man getrost vergessen.
Continue reading

Posted in Web |

Fiese Falle in MySQL bei Verwendung von Views in (Left)-Joins

Da habe ich doch kurz vor Weihnachten noch eine echte Knobelaufgabe erlebt, deren Ergebnis für den ein oder anderen sicherlich interessant sein dürfte. Ausgangspunkt war folgendes eigentlich simple SQL-Statement:

Select * from tableA left join viewC 
     on tableA.id=viewC.lookup

Soweit so unspektakulär, auch wenn das Original noch mit einigen weiteren Filtern gespickt war und die View nicht gerade ein einfaches Query kappselt.

Was allerdings gar nicht lustig war, waren die Ergebnisse dieser Abfrage, denn sie entsprachen nicht den Erwartungen. Aus der View erhielt ich nämlich keinen Join-Partner obwohl ich diesen als Test extra geprüft hatte mit:

 Select * from viewC where lookup='TestValue'

Folgende Punkte habe ich als „übliche Verdächtige“ abgeprüft:

  • Vergleich der Datentypen – auch nicht die Ursache
  • Collations (also Zeichensätze) – auch mit Casting, das Ergebnis bleibt das Gleiche

Spannender Nebeneffekt, der bei der weiteren Untersuchung heraus kam – nutze ich die view nicht sondern packe 1:1 den Code aus der Definition mit in mein Statement

 
Select * from tableA left join 
   (select * from tableB 
     left join tableF 
         on tableB.id=tableF.foo 
      where tableF.bar='baz' and deletedDate is null)
   as testview on testview.id=tableA.id

Dann funktioniert wieder alles wie erwartet. Es staunt der Laie und der Fachmann wundert sich. Höchste Zeit das Problem genauer unter die Lupe zu nehmen und die bekannten Bugs von MySQL bzw. den Deviraten wie MariaDB und Percona zu durchforsten. Ergebnisse sind leider recht dürftig und beschreiben nicht das was ich erlebe. Immerhin stoße ich auf weitere Probleme die erst einmal völlig losgelöst von der Thematik erscheinen, es geht dabei um möglich Einstellungen des Servers und den Standard-Verhalten. Das hat sich in den letzten Jahren immer mal wieder etwas verändert und spiegelt des „Erwachsen werden“ von MySQL wieder. Wir erinnern uns: Es hat eine geraume Zeit gedauert bis MySQL endlich als Standard auf INNODB als Engine gewechselt hat und somit referenzielle Integrität in Form von Transaktionen und Foreign Keys unterstützt wurden. Ebenso aus der grauen Urzeit von MySQL stammen Probleme mit NULL-Werten bei Datumsfeldern (DATE,DATETIME). Und genau da liegt der Hase am Ende auch begraben. Die Server-Konfiguration gibt vor, dass der Server sich strikt verhalten soll, unter anderem bei den Datumsfeldern.
Somit ist es nicht mehr zulässig den „uralten NULL-Ersatz 0000-00-00 00:00:00“ zu verwenden. Die Routinen für den Ersatz kann man aber per Session einschalten, und genau das ist bei der manuellen Abfrage der Werte jedes mal passiert, sei es per manuellem Join oder bei der Abfrage der einzelnen Tabellen. Dabei verhält sich das isnull je nach eingestelltem Modus. Mal liefert es Zeilen mit „0000-00-00 00:00:00“ als Ergebnis, mal nicht, je nachdem ob strict-mode gesetzt ist oder nicht.

Warum läuft es dann beim Verwenden der View aus dem Ruder? Das liegt an der Art und Weise wie MySQL mit Views umgeht: Sind diese übermäßig komplex werden sie als separater Thread gestartet, der eine temporäre Tabelle bereitstellt auf die dann wiederum gejoined werden kann. Dieser Thread wird allerdings vom Serverprozess angestoßen, und dort steht der Modus per default auf strict und dieser wird dann auch angewandt. Somit ist das Ergebnis nicht das was ich bei der singulären Abfrage erhalten habe, sondern leider eben ein leeres da in der Tabelle anstelle NULL eben noch „0000-00-00 00:00:00“ verwendet wird.

Die temporäre Lösung ist, den Join manuell auszuführen, mittelfristig werden wir den Server umstellen. Das sind aber eigentlich nur kosmetische Lösungen. Die eigentlich korrekte Maßnahme für dieses Problem ist die Verwendung von sauberen NULL-Werten anstelle obskurer Workarounds. Leider verlassen sich sehr viele Applikationen bei uns noch auf die Tabelle und diese kruden Werte, einfach Umstellen ist also erstmal leider nicht drin. Ich kann jedem Entwickler nur wärmstens empfehlen, sich auf derartige Altlasten nicht zu verlassen und schnellstmöglich dafür zu sorgen diese abzubauen.

Routing mit HTTP – Query-String oder Verzeichnis-Notation?

In loser Folge werde ich in den nächsten Monaten einige Vorgehensweisen im Netz technisch etwas näher beleuchten und hinterfragen.

Jedes aktuelle Framework, das etwas auf sich hält im Bereich Webentwicklung, bringt einen Routing-Mechanismus mit. Was macht das Ding? Es kümmert sich darum, dass aus einer URL heraus die passende Applikation bzw. Teilapplikation aufgerufen wird. Wenn man also http://example.com/cart/list aufruft, dann wird der passende Programmcode ausgeführt, der sich um die Anzeige des Warenkorbs kümmert. Soweit so einfach. Innerhalb der Frameworks wird dann häufig per Model-View-Controler gearbeitet. Die Url wird dann noch weiter „genutzt“ um den passenden Controller und die passende Action (sofern es verschiedene gibt) zu ermitteln. Mittlerweile auch gängige Praxis ist es alles was danach noch als scheinbare Verzeichnisstruktur kommt als Parameter zu betrachten, immer wechselweise Name/Wert.

Auf den ersten Blick sieht das ja schick aus, denn die URLs werden dadurch ggf. „sprechender“ bzw. man kann sie sich leichter merken. Aber nicht alles was schön / schick aussieht ist auch technisch sinnvoll. Ich selbst reibe mich regelmäßig an dieser Form der Applikationssteuerung.

Am ärgerlichsten finde ich den Missbrauch der Verzeichnisstruktur zur Parameterübergabe. Hierfür hat das HTTP-Protokoll bzw. das generische URL-Schema nämlich seit den Kindertagen des Netzes eine passende Lösung. Diese nennt sich Query-String und ist an vielen Stellen des Netzes erfolgreich im Einsatz. Es handelt sich dabei um das „Anhängsel“ an Internet-Adressen die nach einem Fragezeichen folgen: Also z.B. http://example.org/suche.html?was=einThema. Die Applikation kann den Querystring (im Code wird er häufig als „GET-Parameter“ genannt) dann direkt auswerten. Auch für den Fall mehrerer Parameter ist vorgesorgt: Diese werden per Kaufmanns-Und (Ampersand) getrennt. Das sieht dann so aus: http://example.org/suche.html?was=einThema&wo=wohnort

Technisch steht dabei das Konzept des Parametrisierens von Programmen (und letztlich Funktionen) dahinter. Das Äquivalent aus der Vor-Web-Zeit (das auch heute immer noch ständig im Einsatz ist) auf einer Kommandozeile (also Bash, SSH und Co) sind Parameter die man dem Programmaufruf mitgeben hat. In den meisten Programmiersprachen werden die Parameter in arg oder argv Array übergeben.

Ich finde es nicht weniger ansprechend als die Verzeichnisschreibweise. Ganz im Gegenteil – ich muss als Benutzer ggf. nicht raten was jetzt Parameter und was noch Verzeichnis ist.

 

Posted in Web |

IPv6 – das „neue“ Internet-Protokoll und der steinige Weg dorthin

Nun habe ich am 22. und 23.05.2014 die Möglichkeit bekommen am IPv6-Kongress in Frankfurt teilzunehmen. So langsam aber sicher wird es Zeit sich um das neue Internet-Protokoll zu kümmern und damit vertraut zu werden. In erster Linie ist es natürlich ein berufliches Interesse, hier am Ball zu bleiben. Aber auch für mich privat als „digital Native“ bis „Nerd“ – irgendwo dazwischen liege ich wohl – ist es natürlich interesant zu wissen was als nächstes kommt.

Nun ersteinmal: Warum das ganze? Nun, das Internet ist langsam aber sicher gewachsen, schneller als man es ursprünglich einmal gedacht hat und noch dazu in Ausdehnungen die sich früher kein Mensch so recht vorstellen konnte. Wichtigstes Prinzip war immer die sogenannte Ende-zu-Ende Kommunikation nach dem Best-Effort-Prinzip: Jeder leitet alle Daten zielführend und so gut es geht weiter, die kleinste Einheit dafür sind sogenannte Pakete. Egal was man an Daten im Internet verschicken möchte, alles wird in kleine Häppchen zerlegt und vom Sender zum Empfänger transportiert. Dabei ist es (fast) unerheblich was transportiert wird: Sprache, Text, Bilder, Videos, Dateien etc.: Alles wird auf die Pakete verteilt – man kann es wie das Versenden einer umfangreichen Lieferung sehen: Was auf einen LKW passt wird auf einen geladen und verschickt, wenn es mehr wird, teilt man es auf. Vorteil: Wenn mal tatsächlich etwas nicht ankommt, muss man nur den fehlenden Teil der Daten nachschicken (da wird es dann mit den LKWs ggf. etwas schwierig).
Was braucht man um Pakete zu verschicken? Richtig, eine Adresse damit der Postbote oder Paketdienst weiß wohin mit der Lieferung. Dazu wurde das Internet-Protokoll entwickelt, kurz IP. Derzeit werden Adressen mit 32 bit Länge verwendet, geschrieben in 4 Blöcken zu je 8 Bit. Das gibt dann Angaben wie 192.168.10.74. Diese Adressen werden gemäß ihrer Historie als IPv4 (vierte Revision des Protokolls in Verbindung mit TCP) bezeichnet.

Nun funktioniert das ja momentan schon, weshalb also ein neues Protokoll einführen? Never touch a running system bzw. never change a winning team…. Nun es gibt gute Gründe dafür, denn das Netz ist seit der letzten Protokollversion immens gewachsen. Niemand hätte anfänglich davon zu träumen gewagt, dass IP derartig populär und weltweit im Einsatz sein würde. Auch waren 32 Bit zu dem Zeitpunkt ein nahezu unvorstellbar großer Zahlenbereich.
Heute hat fast jeder mindestens einen PC, Laptop und ein Smartphone ggf. noch weitere Geräte wie Netzwerkdrucker, IP-Telephone, IP-Webcams, Internetfähige Fernseher etc. Für jedes Gerät wird eine eigene Adresse benötigt… Wenn jeder Mensch auf der Erde ein Gerät hat, dann reicht es schon nicht mehr…
Für den Gebrauch in abgeschlossenen Netzwerken gibt es Adressen, die nicht weltweit eindeutig sind – so lange die Netzwerke nicht miteiander kommunizieren müssen ist das auch legitim. Die bekannstesten Adressen für diesen Fall sind die der Class C: 192.168.x.y, für größere gibt es die Class b (172.16.0.0 bis 172.32.255.255), in großen Unternehmen gibt es meist Class A (10.x.y.z).
Schon früh hat man Methoden entwickelt um Internet-Anschlüsse für mehrere Rechner auf einmal nutzbar zu machen. Einige alte Hasen erinnern sich unter Linux noch an ipfwadm, später ipchains und heute iptables. Die Werkzeuge können noch viel mehr aber eben auch IP Masquerading bzw. Network-Address-Translation (NAT). Noch heute kommen genau die gleichen Mechanismen zum Einsatz, meist hübsch verpackt in einem Multifunktionsgerät das viele als Router bezeichnen (was technisch nur teilweise korrekt ist). Netter Nebeneffekt: ohne besondere Einstellungen (z.B. Portweiterleitungen) sind die Geräte im Netz auch erst mal vor Zugriffen von außen geschützt.
Im öffentlichen Internet dürfen die oben genannten Bereiche nicht verwendet werden, sie fallen (wie einige andrere Bereiche mit speziellen Funktionen) aus den zur Auswahl stehenden IP-Adressen heraus. Es wird also noch knapper.
Nun kann man ja sagen: was einmal klappt, geht auch zweimal… Also schachteln wir doch ein Netz mittels IP Masquerading in ein anderes. Das funktioniert (leider) recht gut. Zudem erhöht es die Sicherheit, sollte man meinen. Schwierig wird es dann aber Geräte in der zweiten Ebene anzusprechen: am eigenen Router kann man noch Portweiterleitungen einrichten, ein Provider mit mehreren tausend kunden kann das nicht. Insgesamt wird also das Ende zu Ende Prinzip ausgehebelt. Im kleinen ist das ja noch ok, aber weltweit wird es schwierig… Denn ein Fernzugriff aus die zentrale Dateiablage daheim ist sehr praktisch (dann muss man die Dateien nicht irgendwelchen Clouddiensten anvertrauen). Genau das klappt dann aber eben nicht mehr.
Es gibt noch einige gute Gründe mehr weshalb IPv4 ersetzungsreif ist, aber das würde den Rahmen hier sprengen.

Nun gut, ich bin technisch ja durchaus interessiert, also würde ich IPv6 dann auch gerne baldest möglich nutzen. Zumal ein Parallelbetrieb ja sogar explizit vorgesehen und möglich ist. Das brauche ich beispielsweise für meinen gut gedienten Netzwerkdrucker, für diesen wird es keine Softwareaktualisierung geben, die ihn  IPv6 fähig macht. Aber der Rest meines Geräteparks ist soweit eigentlich fit. Bis auf … wer hätte es gedacht? Den Router. Nun gut, der hat auch schon einige Jahre auf dem Buckel und es gab ihn bereits bei Vertragsabschluss als Endgerät.

Also frage ich erst mal bei meinem Provider nach, wie es denn aussieht mit IPv6 und vor allem ob es eine Möglichkeit wieder ein subventioniertes Gerät zu erhalten. Fragen kostet nichts und man kann nur Erkenntnis gewinnen. Prompt habe ich die Antwort, das er Ersatz des Routers wahrscheinlich möglich sei, aber ich möge doch bitte nochmal in der Technik anrufen. Gesagt getan. Dort verweißt man mich dann aber doch in die Vetragsbetreuung. Dort heißt es dann, dass ein Upgrade des Routers nur gegen Zuzahlung von 90 EUR möglich ist, was mir für das kleinste Gerät mit Branding dann doch etwas viel Geld ist. Ich lehne das Angebot also erst einmal ab und schaue mich derweil bei den Gerbauchtgeräten um.

Am nächsten Tag erfolgt ein weiterer Anruf, man signalisiert beim Router Entgegenkommen und senkt die Hürde auf 49 EUR – immer noch zu viel wie ich finde – die Geräte gehen bei ebay für um die 35 EUR über den virtuellen Tresen und Versandkosten hätte ich in beiden Fällen. Also ordere ich erst mal eine FritzBox mit IPv6-Fähigkeit – immer in dem Glauben, dass dies das Tor zur IPv6-Welt aufstoßen wird.

Einige Tage vergehen, ich bin auch sonst gut ausgelastet, aber einige Wochen danach komme ich dann endlich dazu die Box anzuschließen. Erste Ernüchterung bei den Fähigkeiten: Bisher gab es zwei normale analaoge Anschlüsse intern, jetzt nur noch einen, der andere ist für ein Fax reserviert (TAE-N-Anschluss) – die Software lässt sich auch nicht überreden den Anschluss zweckentfremdet zu nutzen. Das ist ärgerlich, denn mittlerweile haben wir ja zwei Telefone die wir auch beide parallel nutzen möchten und bisher konnten. Aber egal: Jetzt will ich erst einmal wissen wie es um IPv6 steht und für einen Test ist das Setup ja durchaus geeignet.

Doch was muss ich feststellen: Ich bekomme keine IPv6-Adresse bzw. ein entsprechendes Präfix zugeteilt. Das ist ein Problem des Providers, weshalb ich den wieder kontaktiere. Die Antwort ist diesmal ernüchternd: IPv6 gibt es nur für einige Kunden mit V-DSL und in einem Pilotprojekt. Ein allgemeiner Start ist noch nicht in Aussicht.

Also wird es erst mal nichts mit IPv6 bei mir. Auf eine Lösung mit Tunnel möchte ich eigentlich ungern setzen, die Option Dualstack-Lite wäre für mich ja auch noch OK gewesen. Was bleibt ist ein schaler Beigeschmack über das Verhalten meines Providers bezüglich des Routers – wollte man mir hier einfach nur ein Neugerät verkaufen oder ist das nur ein Kommunikationsproblem gewesen. Ersteres fände ich reichlich dreist, letzteres ist wohl aber in modernen Unternehmen immer wieder der Fall. Warten wir also ab, was kommen wird – vielleicht auch irgendwann IPv6.

 

Modularer Querbaukasten in PHP: Traits

Objektorientierte Entwicklung ist mittlerweile der Standard wenn es um Geschäftslogiken geht. Für verschiedene weitere Anwendungszwecke gibt es auch immer noch gute Funktionale Programmiersprachen. Jede Herangehensweise hat ihre Vor- und Nachteile.

Wie immer sind Programmierer komische Wesen und würden an einigen Stellen gerne das Beste aus beiden Welten haben, auch wenn diese sich eigentlich gegenseitig ausschließen.

Aktuell hatte ich mal wieder einen solchen Fall: Es gibt eine „fertige“ PHP-Bibliothek zum Erzeugen von PDF-Dokumenten (diese eigenen sich in der Regel besser zum Ausdrucken als HTML-Seiten) – etabliert hat sich hier FPDF bzw. dessen Fork TCPDF. TCPDF ist die aktuellere und modernere Fassung, sie unterstützt unter anderem die Verwendung von UTF-8-Zeichensätzen. Daher musste ich mich auch „mal wieder“ mit schon lange gepflegten und eigentlich abgeschlossenen PDF-Routinen beschäftigen: FPDF kann mit UTF8 nicht richtig umgehen, somit sehen die erzeugten PDFs aus wie Kraut und Rüben sobald Umlaute oder Sonderzeichen im Spiel sind.

Beim Umstellen gibt es ein paar Feinheiten, aber nichts was einen wirklich davon abhält die Umstellung halbwegs zügig durchzuführen. Die meisten Probleme erkennt man einmal und kann sie dann in den Folgedateien direkt korrigieren.

In diesem Zusammenhang habe ich mich mal wieder etwas geärgert: Viele unserer Dokumente enthalten Tabellen. Soweit so langweilig. Aus Mangel an Alternativen haben wir häufig den Code einfach von der einen eigenen Klasse in die nächste mit kopiert. Das Ergebnis ist altbekannt. Wenn man einen Fehler beseitigen will, muss man alle Kopien mit durcharbeiten. Effizient ist das nicht gerade.

Eine mögliche Option ist es eine eigene Klasse dazwischen zu setzen, die solche Funktionen realisiert. Aber was ist mit den Dokumenten wo man dann gar keine Tabelle braucht – da hat man Pech gehabt? Fazit das geht, aber richtig schön finde ich das auch nicht. Mehrfach-Vererbung kennt PHP nicht – aus gutem Grund (Diamond-Problem). Für meinen Fall hätte ich mir etwas gewünscht wie eine Art Plugin oder von mir aus auch eine Art „include“ das entsprechende Funktionen einbindet wenn sie benötigt werden. Vergleichbar mit dem was ein Präprozessort für C erreichen kann: Macro-mäßig das einfügen was gerade gebraucht wird – bei compilierten Sprachen eine sehr feine Sache, bei Skripten leider kein gangbarer Weg.

Was braucht man eigentlich genau? bzw. was wünsche ich mir? – Das waren meine Fragen. Damit man eine Tabelle einfach einbauen kann braucht man Zugriff auf einige Klassenvariablen – man könnte sich ggf. behelfen, eine Referenz an eine Tabellenklasse zu übergeben und dort den notwendigen Code zu schreiben. Aber eine Tabelle ist ja auch nur wieder eine Sammlung von einfacheren PDF-Elementen – würde also auch wieder aus der TCPPDF-Klasse erben müssen, davon den Code in die andere Klasse zu übergeben mal ganz abgesehen. Eine Art „Nachbau“ des Präprozessors wäre es wenn man hergehen könnte und an der benötigten Stelle in der Klasse einfach per include die Funktionen einbaut die man braucht. Das geht natürlich so nicht, auch weil es im Tabellencode ja durchaus sinnvoll ist, diesen strukturiert zu halten und keinen Spaghetti-Code zu erzeugen, den keiner mehr durchschaut. Auch die Nutzung von Klassenvariablen innerhalb der Tabelle wäre doch praktisch. Kurzum: ein simples Include kann das nicht leisten und sollte es auch nie.

Nun ist es ja aber bei weitem kein super exotisches Problem, mit dem wir hier konfrontiert sind: Modulbauweise mit Blackboxes die nur definierte Schnittstellen haben ist ja auch in anderen Bereichen üblich: Keiner entwickelt heute mehr für jedes Auto Standard-Komponenten vollständig neu – vielmehr werden Grundelemente mit einen neuen Aufsatz versehen oder neu miteinander kombiniert. PHP löst das Dilemma mit sogenannten Traits – ich vergleiche das gerne mit Matrix-Vererbung – um ein Gesamtpaket zu erhalten markiert man einfach die Zusatzfunktionen die das Ergebnis haben soll. Klingt kompliziert – ist es aber nicht.

Einen Trait programmiert man fast wie eine ganz normale Klasse – abgesehen, davon dass sie keinen eigenen Konstruktor enthält, gibt es alles was man sonst auch kennt: Funktionen, Zugriffsbeschränkungen (public,private,protected) und Klassenvariablen. Kurzum man kann alles was man immer wieder braucht damit sauber realisieren – in meinem Fall, habe ich alles was ich für eine Tabelle benötige im Trait verpackt. Man hat sogar Zugriff auf die Methoden und Variablen der Klasse in der man den Trait am Ende einsetzen will – hier ist die Unterstützung der Entwicklungsumgebung natürlich nicht so gut wie in einer vererbten Klasse, denn der Trait kann ja in jeder beliebigen Klasse verwendet werden – von daher etwas mehr Denkarbeit. Ich habe vieles direkt aus der bisherigen Realisierung übernehmen können, das macht es etwas leichter.

Was man noch beachten muss: Gleichnamige Funktionen in der übernehmenden Klasse „überdecken“ bzw. überschreiben die Funktionen des Traits (vergleichbar mit dem was man aus der Vererbung kennt: Es wird immer die „nächstliegende“ Funktion genommen, es sei denn man gibt den Namespace bzw. die Elternklasse mit an (parrent::) . Für mich hat es sich bewährt im Trait die Funktionen als solche entsprechend zu bennen – sie bekommen alle den Prefix „pdf_table_trait_“ – die Wahrscheinlichkeit, dass man somit ungeplant etwas überschreibt ist vergleichsweise gering. Die Programmiersprache nimmt einem eben nicht alles ab und etwas Coding-Disziplin hat noch keinem Entwickler geschadet.

Insgesamt habe ich nun mit dem Trait das was ich gesucht habe: Einen Code-Block, den ich separat warten kann – wenn ich einen Fehler in der Tabellenerzeugung beseitige, dann muss ich das nur noch an einer Stelle tun, nicht mehr in jedem Dokument. Zudem habe ich es so realisiert, dass ich den Code sogar innerhalb einer Klasse mehrfach aufrufen kann um verschiedene Tabellen zu zeichnen (das hatte ich vorher mit etwas Verrenkungen unsauber gelöst). Man sollte natürlich jetzt nicht alles und jedes zwingend in einen Trait auslagern, nur weil es geht – mit Maß und Ziel das richitige Werkzeug an der richtigen Stelle ansetzen. Traits gehören dabei eindeutig in die Kiste mit der Aufschrift „Spezialwerkzeuge“ – man braucht sie nicht all zu häufig, aber wenn man weiß dass es sie gibt und wie man sie richtig einsetzt, geht vieles sehr elegant zu lösen.