Portierung eines Delphi-7-Projekts nach FreePascal und Lazarus

Hach, alte Software. Alte, gewachsene Software. Alte, gewachsene, ungepflegte Software. Ja. Wer kennt es nicht? Da gibt es ein Projekt, das hat bestimmt gut fünfundzwanzig Jahre auf dem Buckel und wurde, bis zuletzt, noch mit Delphi 7 “gepflegt”. Von gepflegt kann eigentlich nicht die Rede sein, doch wurden noch minimale Erweiterungen und, allem voran, Verschlimmbesserungen gemacht. Jeglicher Unsinn. Was aber versäumt wurde war, das Projekt, was bei hunderten von Kunden eingesetzt wird, auf eine aktuelle Plattform zu migrieren, damit eine vernünftige und saubere Weiterentwicklung überhaupt noch möglich ist.

Lazarus-IDE

Da komme ich ins Spiel. Problemlöser, Beruhiger … ja, einfach der, der das schlimme Los zog. Ich war zur falschen Zeit am falschen Ort.

Es war so, dass die Weiterentwicklung mit Delphi 7 in der Form nicht mehr möglich war. Die letzte Windowsbetriebssystemversion, auf der Delphi 7 wohl annehmbar lief, war Windows 7, welches ja bereits 2020 abgekündigt war. Ich habe Delphi 7 auf Windows 7 ausprobiert. Es war die Hölle. Stabilität war faktisch nicht vorhanden. Abgesehen von der unsinnigen Weiterentwicklung auf einer uralten, veralteten Plattform mit einem nicht unterstützten Betriebssystem war das Problem, dass Delphi 7 andauernd Fehler warf, stehen blieb, abstürzte. Abgesehen davon gab es in dem Projekt – teils absolut unnötige – Abhängigkeiten, die mitunter zwanzig (20!) Jahre alt waren.

Ich sah drei Möglichkeiten: 1. Ich kündige. Tja, Frau, Kinder und Haus …, also 2. Migration zu Delphi in einer aktuellen Version oder 3., und da war ich mir absolut nicht sicher, wie klug das war, Migration auf eine freie Plattform mittels FreePascal und Lazarus. Der Titel verrät, wofür wir uns entschieden.

Delphi in einer aktuellen Version war meinem Chef nicht nur zu teuer (?!), der Migrationsaufwand aufgrund des alten Codes und der noch schlimmeren Abhängigkeiten, wäre, so dachte ich, mindestens genau so groß gewesen, wie die Migration auf eine andere Plattform. Natürlich bin ich recht naiv an die Sache herangegangen, hatte ich doch wenig Erfahrung mit FreePascal und Lazarus, abgesehen von meinem Spieltrieb, den ich daran ab und zu mal auslebte. Aber was wusste ich? Ich fand, aufgrund meiner Tests, dass die Plattform stabil genug war und ist. Ich spiele gerne mit Technologien und ich habe mir Lazarus und FreePascal über Jahre hinweg angesehen. Die anfänglichen Probleme von vor einer Dekade waren behoben, FreePascal lief eigentlich schon immer ganz gut und Lazarus mauserte sich zu einer stabilen IDE. Ich schlug meinem Chef diese Lösung vor und ich denke, das Hauptargument war “kostenlos”. Ob er den Rest hörte, weiß ich nicht.

Also machte ich mich daran, mich tiefergehend mit FreePascal und Lazarus zu beschäftigen, Blog- und Forenartikel dazu zu lesen und ein oder zwei kleine Testprojekte damit zu schreiben, um das System und die Probleme kennenzulernen. Pascal lag bei mir bereits gut zwanzig Jahre weit weg und ich hatte das nur in zwei kleinen Projekten in meiner alten Firma eingesetzt. Ich kam immer mehr rein.

Dann schnappte ich mir eine virtuelle Maschine, warf ein Windows 7 an, schauderte mich als alter FreeBSD– und Mac-User, installierte Delphi 7 und TortoiseSVN, checkte das alte Projekt aus und installierte alle Abhängigkeiten, die mir die gut zwanzig Jahre alte Doku des Projekts preisgab. Diese elende Abhängigkeitenhölle. Abhängigkeiten, um eine “hübschere” Toolbar hinzukriegen, oder Abhängigkeiten, um eine Pfadauswahl zu implementieren. Die alten Programmierer lebten faktisch die Abhängigkeitshölle und genossen sicher, dass eines Tages ein kleiner Programmierer den Quatsch ausbaden müsse.

Nachdem ich guten Gewissens alle mir bekannten Abhängigkeiten mit teils Windows 3.11-Installationsprogrammen installiert hatte (und hey, dass das Zeug noch lief … man kann von Microsoft ja halten, was man will, aber ich war schon beeindruckt), lud ich das Projekt. Das bedeutet, ich versuchte, es zu laden. Ich weiß nicht, wie die alten Programmierer das zusammengebastelt hatten, aber man musste tatsächlich noch Projekteinstellungen an seine individuelle Entwicklungsumgebung anpassen. Normal? Nein. Stell dir mal vor: du checkst ein Projekt aus, auf irgendeinem Computer, und du musst dann noch die Projektdatei an deine Pfade usw. anpassen, weil dort der Benutzername drin steht. Das geht doch nicht! Und es war einiges und es dauerte noch viel länger, bis ich aufgrund der kargen Doku das Ding mal soweit hatte, dass nicht mehr gemeckert wurde. Ich sage das jetzt mal so: bitte, bitte, bitte, dokumentiert nicht das Offensichtliche (function SchreibeVornamen() // Diese Funktion schreibt den Vornamen…), sondern das, was eben nicht offensichtlich ist. In diesem Projekt wurde, und das mit einer solchen Begeisterung und einem solchen Arbeitsaufwand, nur das Offensichtliche dokumentiert.

Gut, es lud jetzt, es kompilierte. Naja, ab und an. Mal klickte ich auf “Play”, dann kompilierte es, mal auch nicht (ohne Code-Änderung), mal startete es, mal nicht, mal hing es sich auf und dann hing sich ganz Delphi auf. Es war nicht tragbar und wieder einmal wunderte es mich, wie man früher so arbeiten konnte (ich konnte das noch nie).

Nach dem Spruch “Man kann nicht alles haben.” durchwühlte ich den Code. Ich durchwühlte ihn nach den ganzen Abhängigkeiten, die ich ja unter FreePascal und Lazarus nicht mehr zur Verfügung haben sollte. Ich fand viele Stellen, die man einfach nicht brauchte oder für die Lazarus eigene Komponenten mitbrachte. Ich begann, auszuklammern und zu schauen, was noch lief oder was einfach nur sinnlos darin war. Ich fand so einiges. Als ich nach einigen Tagen der Pein dachte, fertig zu sein, dachte ich mir: Jetzt ist der Zeitpunkt da, an dem ich versuche, die Spaghetti … erm, den Code in Lazarus zu importieren.

Lazarus bietet einen Import von Delphi-Projekten an. Danke, liebe Lazarusentwickler. Der Dank ist ernstgemeint, denn der Import funktioniert gut. Nicht sehr gut, aber gut. Während des Imports zeigt das System bereits mögliche Probleme an, fehlende Units und so kann man sich, Notizen machend, schon einmal darauf einstellen, dass ein einfacher Import wohl sicher nicht den Segen bringt, den man so dringend bräuchte. Ich importierte, notierte, importierte erneut, notierte wieder. Sprang mit meinen Notizen wieder zurück zu Delphi und versuchte, weitere Probleme zu beheben oder zumindest zu minimieren. Commit, Checkout, Import, Notizen.

Irgendwann war ich dann soweit, dass der Import gut durchlief. Das hatte aber auch Tage gedauert. Ich war aber sehr stolz auf mich. Dann klickte ich auf “Kompilieren”. Ich musste noch einige Units entfernen, einige Funktionen und Prozeduren ausklammern, einigen Code umschreiben, aber irgendwann, recht schnell, wenn ich mich recht erinnere, kompilierte das Projekt dann durch. Nachdem ich auch Firebird inklusive Abhängigkeiten am Rennen hatte, haute es mich aus den Socken: Das Ding startete. Es startete. Es kam … tatatataaaa … die Login-Maske. Zumindeste schätzte ich, dass sie es wäre, denn sie war noch leer. Ich schloss den Tag trotzdem als erfolgreich ab. Ich fand dann recht schnell heraus, dass ich teilweise Ressourcen-Dateien ausgeklammert hatte und als ich sie wieder einklammerte und die Endung .dfm in .lfm umschrieb, die Masken (fast) 1:1 so aussahen, wie in Delphi. Ich arbeitete mich langsam vor, Maske für Maske für Maske. Ich wusste, es würde ein langer Weg werden, der noch weitere Stolpersteine haben sollte.

Einer dieser Stolpersteine war tatsächlich, dass einige Masken/Dialoge in Delphi binär und nicht in Textform abgespeichert waren. Komischerweise waren das von gut fünfzig Dialogen fünf oder sechs. Das Problem ist einfach zu lösen. In Delphi 7 öffnet man den Dialog und speichert ihn als Text, so dass man ihn in Lazarus benutzen kann. Dialoge, die per Text beschrieben werden, haben gegenüber den binären Dialogen den entscheidenden Vorteil, dass man sie mit jedem beliebigen Editor öffnen und bearbeiten kann, während sie auch mal aus Inkompatibilität eben nicht mit Lazarus GUI-Editor laden.

Es war eine Menge Tipperei, Ausklammerei, Umschreiben von Code, Entfernen von altem Code und Schreiben von neuem Code. Vor allem einiges an der Datenbankschnittstelle musste geändert werden, da wohl IB nicht hunderprozentig wie IBX funktioniert, vor allem im Transaktionsbereich.

Ich war dann aber sehr stolz, als die gesamte Basis der Software lief und fast so aussah und sich verhielt, wie sie es davor bei Delphi auch tat. Dann kam aber der Teil, der mir am meisten Bauchschmerzen bereitete. Im alten Projekt wurde QuickReport benutzt, um Reports zu generieren, das Drucken zu übernehmen und PDFs zu erzeugen. Gibt es QuickReport nicht mal mehr für ein aktuelles Delphi und ist die alte Version anscheinend nur mit Gefrickel und neueren Delphi-Versionen zum Laufen zu überreden, gibt es das Projekt gar nicht für Lazarus. Das bedeutet: Keine Reports, kein Drucken, kein PDF-Export.

Ich sah mir dann drei oder vier verschiedene kostenlose Report-Generatoren an, die sich über den Lazarus-Online-Packager installieren liessen. Alles unfertig. Der einzige Report-Generator, den ich halbwegs brauchbar fand und finde, heißt FortesReport. Dieser ist sehr nah an QuickReport und lässt sich ähnlich bedienen. Man baut die Reports mit dem Lazarus-GUI-Builder zusammen und kann sie dann aufrufen und mit Daten füllen. Ein Problem gibt es aber an FortesReport, welches nicht zu unterschätzen ist: Die Dokumentation. Diese gibt es nämlich nicht.

Wer mich kennt weiß, ich bin faul. Jemand meinte mal zu mir, alle Programmierer sind faul. Also überlegte ich nach einem Weg, wie ich das QuickReport-Zeugs zum FortesReport-Zeugs konvertiert bekomme. Und während ich so nachdachte, googlte ich und fand jemanden, der das selbe Problem hatte. Ich war nicht alleine auf dieser Welt. DACConv heißt das Programm. Die Software macht nicht viel mehr, als in den Pascal-Dateien und in den LFM-Dateien Klassennamen und Variablennamen anhand bestimmter mitgelieferter Schemata auszutauschen. Abgesehen von der echt schlechten Bedienung der Software macht sie ihren Job aber fein. Nur leider bleibt Handarbeit nicht erspart, denn teils müssen Bänder umgebaut werden, teils müssen Objekte entfernt werden, die einfach von FortesReport nicht unterstützt werden. Aber es geht allemal schneller, sehr viel schneller, als die Reports vollständig von Hand neuzubauen.

Ist das alles geschafft, kann man stolz auf sich sein. Das Projekt lässt sich reproduzierbar kompilieren und läuft und auch die Reports sehen aus, wie im Original.

Ist das alles also einfach gewesen? Nein. Man benötigt bereits einiges an Erfahrung, viel Sitzfleisch und, am Wichtigsten: Nerven wie Drahtseile.

Was ich allerdings sagen muss: Lazarus und FreePascal sind sehr stabil und sehr brauchbar, das hätte ich so nicht gedacht. In all der Zeit ist mir Lazarus vielleicht vier oder fünf Mal abgestürzt, und es war nicht einmal schlimm, da keine Daten dadurch beeinträchtigt wurden. Sie sollten noch ein wenig an der Stabilität feilen, aber ich könnte mir vorstellen, damit noch einmal zu arbeiten. Vielleicht nicht an einem großen Projekt, aber an kleinen Tools.