Als Angestellter in einer insolventen Firma

Im Jahr 2021 erfuhr ich, dass die Firma, für die ich seit mehr als dreineinhalb Jahren tätig bin, Insolvenz anmelden muss. Ein kurzer Erfahrungsbericht.

2018 suchte ich mir eine neue Arbeit, die ich im März des selben Jahres auch direkt begann, und zwar, wie so gerne, als Softwareentwickler und Administrator. Nach kurzen Startschwierigkeiten und Neuorientierung lief es dann doch ganz gut und ich hatte (zumeist) Freude an meiner Arbeit.

Im Oktober, nach einem Arbeitstag, dann das kurze Gespräch zwischen meinem Chef und mir. Er müsse wohl Insolvenz anmelden (warum und wieso, ist hier nicht Thema). Ich war schon gut geschockt, im Nachhinein hätte ich aber auch selbst drauf kommen können. Wie das so immer ist: Später ist man immer schlauer.

Im November 2021 wurde es dann offiziell. Ich bekam die schlechte Nachricht per E-Mail, dass ein Insolvenzantrag eingereicht wurde und es einen Insolvenzverwalter gibt. Dann wurde aus der „grauen“ Nachricht im Oktober plötzlich harte Gewissheit.

Abgesehen vom Verlust des Arbeitsplatzes gab es ein weiteres Problem: Es gibt kein Geld. Ab Oktober. Nochmal: kein Geld. Nicht weniger Geld oder jemand anderes übernimmt das, nein, es gibt kein Geld. Die Banken und die Supermärkte, die Strom- und Gaslieferanten, die Kindergärten, und viele mehr, wollen aber weiterhin Geld haben. Also stehst du mit einer Frau, die glücklicherweise beschäftigt ist, und drei Kindern da und weißt nicht weiter. Hast du dann keine Ersparnisse, sieht es schlecht für dich aus.

Vom Insolvenzverwalter wird dir dann gesagt: Stell doch einen Antrag auf Insolvenzgeld. Das bedeutet, dass du für drei Monate dein volles Gehalt bekommst, und zwar von der Arbeitsagentur und das ohne Anrechnung auf das Arbeitslosengeld, du arbeitest ja schließlich. Wissen muss man aber, dass einem das Insolvenzgeld erst zusteht, wenn auch eine Insolvenz besteht. Man hat allerdings auf dem Antragsformular die Möglichkeit, ein Kreuzchen zu setzen, um einen angemessenen Vorschuss zu bekommen, was ich machte.

Den Antrag habe ich noch im November eingereicht, um zum Einen Geld zu bekommen und zum Anderen die Fristen nicht zu verpassen (innerhalb von zwei Monaten nach Bekanntgabe der Einleitung der Insolvenz). Ich bekam aber kein Geld. Auf zweimaliges Nachfragen bei der Arbeitsagentur bekam ich die E-Mail, dass die den Antrag erst prüfen können, wenn mein Arbeitsverhältnis endet. Da war die Problematik, dass mein Chef versäumt hatte, mir fristgerecht zu kündigen und ich noch bis Ende Januar angestellt war. Wer bis hierhin aufmerksam mitgelesen hat weiß, dass es das Insolvenzgeld nur für drei Monate gibt, wenn es das denn überhaupt gibt, in meinem Fall also für Oktober, November und Dezember. Januar? Pustekuchen.

Laut meines Anwalts stand mir das Januargehalt aber von meinem Arbeitgeber zu. Damit ich nicht voraussichtlich kostenlos einen vierten Monat arbeite (denn ob man Insolvenzgeld bekommt, steht auch noch in den Sternen und ist von verschiedenen Faktoren abhängig), riet mein Anwalt und ein Rechtsforum mir, von meinem Zurückbehaltungsrecht gebrauch zu machen, was ich dann auch tat. Der Brief an meinen Chef stieß natürlich nicht auf Freude, hat er mich ja eingeplant, noch für Projekte für seiner anderen Firma weiter zu arbeiten.

Die Zeit, die man das Zurückbehaltungsrecht ausübt, kann man natürlich sinnvoll dazu nutzen, sich zu bewerben und an seinen Bewerbungsunterlagen zu arbeiten (wenn man nicht eh schon auf der Straße sitzt, weil man keine Rücklagen hatte), was ich auch fleißig tat.

Ich hatte natürlich durchaus Verständnis für meinen Chef. Neben ganz kuriosen Bitten, die ich hier nicht weiter ausführen möchte, wurde mir (wohl) vom Insolvenzverwalter meines Chefs geraten, selbst direkt zu kündigen, damit ich schleunigst Insolvenzgeld bekomme. Ganz großer Fehler. Laut zwei Anwälten, einem Rechtsforum und einem Gespräch mit der Arbeitsagentur selbst, erhält man dann eine dreimonatige Arbeitslosengeldsperre. Auf keinen Fall selbst kündigen, egal, welcher Druck ausgeübt wird.

Schlussendlich bekam ich Insolvenzgeld für drei Monate. Einen Monat, den ich gearbeitet hatte, bekam ich kein Geld. Auch, als alles durch war, ging ich leer aus.

Testaufgaben nach einem Bewerbungsgespräch

Ich habe jetzt länger überlegt, ob ich darüber überhaupt bloggen möchte. Ich mache es doch einmal, denn es gab für mich etwas sehr interessantes und es ist schon eine ganze Weile her.

Ich war auf Jobsuche, schrieb hier und da eine Bewerbung. Dann hatte ich ein Vorstellungsgespräch und der Herr am anderen Ende der Telefonleitung meinte, es könnte passen. Nachdem er über meine Konditionen nachdachte und das mit der Geschäftsleitung durchsprach, bekam ich einen Anruf, dass diese passen würden, die Firma aber eine Testaufgabe für mich hätte. Darum soll es hier gehen, nämlich um diese eine Testaufgabe und um Testaufgaben im Allgemeinen.

Nachdem wir den Techstack abgeklärt hatten und es darum um PHP und Symfony ging und ich auch sagte, dass ich von beidem keine Ahnung habe (PHP habe ich das letzte Mal vor 20 Jahren gemacht), wurde mir versichert, dass vor dem persönlichen Kennenlernen nur noch eine einfache Testaufgabe zu meistern wäre, nämlich die Umsetzung eines Kontonummer-Bankleitzahlen-IBAN-Konverters. Ich sagte: kein Problem, das musste ich auch schon in einem echten Projekt vor einigen Jahren machen, er soll mir die Aufgabe zukommen lassen. Kurze Zeit später war dann das Dokument mit der Testaufgabe da. Fünf vollgeschriebene DinA4-Seiten. Dabei ging es nicht um die Entwicklung eines Konverters, sondern um ein gesamtes Projekt mit etlichen Zwischenstationen.

Ich sollte mich erst einmal in PHP 8.1 einarbeiten. Danach in Symfony 6.1. Um beides richtig zu machen, würde ich schon keine Stunden mehr veranschlagen, sondern eher einige Tage bishin zu wenigen Wochen. Eine Programmiersprache lerne ich zwar schnell, vor allem PHP, bei der ich nicht einmal von ganz vorne einsteigen müsste, dann aber noch ein komplexes Framework, das ist Aufwand.

Zusätzlich dazu sollte ein Login-Verfahren entwickelt werden und eine dazugehörige Website mit Datenbankanbindung (MySQL oder MariaDB). In der Datenbank sollten die bereits zuvor konvertierten Daten tabellarisch dargestellt werden. Jeder Aufruf sollte einen Zähler inkrementieren.

Weiterhin sollten die Daten dann als JSON exportiert werden können.

Dazu gehörte dann die Installation und Konfiguration von Debian 11, die Installation der benötigten Software (spezielle PHP-Version, nicht in APT drin, MySQL oder MariaDB, Symfony und Apache oder NGINX).

Das war der technische Part. Dazu kam dann ein Benutzerhandbuch für den Konverter über Funktionalität und Bedienung. Dann noch eine Dokumentation für das gesamte Deployment durch einen Laien (Installation und Konfiguration Betriebssystem, Installation und Konfiguration Webserver, Installation und Konfiguration Datenbankserver, Installation und Konfiguration PHP, Installation und Konfiguration von Symfony – durch einen Laien!).

Weiterhin sollte das Projekt vorher komplett durchgeplant werden, vermute mit Pflichenheft, war nicht genauer beschrieben und es sollten auch Tests (Unit-Tests, händische Tests) durchgeführt und dokumentiert werden.

Versteht mich bitte nicht falsch: Das alles kann ich, aber rein realistisch, wenn man es vernünftig macht, ist das ein Projekt, das man nicht in einigen Stunden hinbringt, selbst, wenn man PHP und Symfony auf hohem Level beherrscht. Schon alleine am Pflichtenheft schreibt man eine Weile, das Benutzerhandbuch rotzt man auch nicht einfach runter…

Ich lehnte den Job dann mit Begründung ab. Eine Antwort darauf erhielt ich nie.

Softwareentwicklung Teil 2: Weitere Erfahrungen

Mir fallen noch einige weitere Dinge ein, die ich hier zu teilen versuche. Meist geht es um technische Schulden und, für mich, komische Ansätze in der Verwaltung von Firmen.

Ich war vierzehn Jahre lang in einem Unternehmen beschäftigt und das hat, zumindest in Bezug auf die IT, auf die IT-Abteilung gehört. Haben wir immer die richtigen Entscheidungen getroffen? Nein. Aber zumeist und aus den fehlgeschlagenen Entscheidungen haben wir immer gelernt. Ich möchte das hier einmal als Positivbeispiel anbringen. Ich schätze, es muss 2012 gewesen sein, als wir neue Server anschafften. Zwei baugleiche Geräte für Redundanz. Wir kamen auf die Idee, dort Festplatten mit 4TB Speicherkapazität einzubauen und entschieden uns für Western Digital SAS. Leider wusste keiner von uns, und da hätten wir uns vorher definitiv noch einmal genauer informieren müssen, dass es SAS-Festplatten und Nearline-SAS-Festplatten gab. Wir waren zwar verwundert über die Preise, denn eine solche Platte mit 4TB in etwa so viel wie welche mit 960GB, aber wir forschten nicht weiter nach, sondern freuten uns.

Wir klatschten die Server also mit einer Menge dieser Platten voll, richteten darauf zraid-2 ein (RAID 6) und banden die Geräte ins Netzwerk ein. Wie zuvor auch, exportieren wir die Home-Laufwerke gut 50 Clients per NFS. In Tests funktionierte alles tadellos und wir schlossen glücklich und schnell die Umstellung ab. Dann kamen die Leute und wollten arbeiten. Es kam zu großen Wartezeiten und ein gewisser Unmut machte sich breit, denn das System performte nicht. In einzelnen Tests lief es hervorragend, sequentielles Schreiben und Lesen funktionierte tadellos. Aber in der Masse und bei der Menge an Dateien war es grottenlangsam und unbenutzbar. Wir suchten zu zweit sicher einen Monat nach dem Problem, bis ich auf die Idee kam, dass die Platten in Form der Hardware schuldig waren. Wir stellten dann ein solches Szenario nach und stellten dem gegenüber ein System mit echten (super teuren) SAS-Festplatten und siehe da: Genau da war das Problem. Die Lösung war schnell da: Neue Festplatten mussten her. Wir besprachen das mit der Geschäftsleitung, räumten ein, dass es letztlich unsere Schuld war, wir das aber vorher nicht wussten und es kein böser Wille war. Das Ende vom Lied war, dass wir neue Festplatten, die teuer waren und eine niedrige Kapazität hatten, kauften und einbauten. Das kostete die Firma natürlich eine Unmenge an Geld (ich habe noch gut 12.000 Euro im Kopf). Uns wurde aber nicht der Kopf abgerissen. Erstens wäre der weitere Betrieb in alter Form ohnehin teurer geworden, da niemand arbeiten konnte, und zweitens wusste man, dass Fehler passieren. Wir haben das zusammengefasst, noch einmal berichtet, was wir gelernt hatten, und solche Probleme traten dann nie wieder auf.

In einer anderen Firma sprach ich einmal an, dass wir einen gewissen Style-Guide einführen sollten, und dieser bezog sich nur auf die Benennung von Variablen, Konstanten und Funktionen. Die Benennung solcher Dinge kann man weiter unten in meinem vorherigen Artikel nachlesen, da habe ich ein Beispiel. Ich sprach mich für „sprechende“ Namen aus. Dies wurde abgelehnt, denn dann hätte man ewig lange Namen, mehr aussagen würden diese auch nicht, und man würde sich tottippen (VI(M) war der Editor der Wahl und mit [CTRL]+[p] bzw. [CTRL]+[n] ergänzt er begonnene Namen vollautomatisch). Aufgrund der Ablehnung und auch aufgrund anderer, vorheriger und späterer Aussagen, war mir klar, dass da keine zielbringende Diskussion möglich war. Also ließ ich es.

In der selben Firma kam man auf die Idee, die (teuer zu bezahlenden) Mitarbeiter ein bis mehrmals pro Woche (später dann die Entwickler, die an einem gewissen Projekt arbeiteten, alle zwei Wochen) halbtägig in den technischen Service zu stecken. Der Tenor, so ich mich noch richtig erinnere, war, dass diese dann mehr vom Drumherum mitbekommen und Prozesse besser verstehen. Man war dann in der Tickethölle und musste bestimmte, ausgewählte, redundante Aufgaben abarbeiten. Das Problem: Für viele Serviceaufgaben gab es entweder keine Tools oder diese waren so dermaßen komplex, fehleranfällig und schwergängig, dass sie ein „normaler“ Servicemitarbeiter nicht hätte benutzen können. Bereits einfache Aufgaben konnten ganze Prozesse zerschießen. Anstatt die Softwareentwickler laut ihrer Kompetenzen dazu zu bringen, Tools zu entwickeln, die der Service nutzen hätte können, nutzten wir die halbgaren Tools in der Hoffnung, nichts Schlimmeres zu machen. Doch trotz großer Vorsicht passierte dies ab und an, auch mir zwei Mal. Einmal, ich weiß es noch, haben ein Kollege und ich mehr als einen halben Tag daran gesessen, das Problem zu fixen. Dabei wäre es wirklich sinnvoller gewesen, diese Tools robust zu machen.

Mir fällt noch ein Beispiel in dieser Firma ein. Wir hatten einen Workshop und mussten danach irgendwelche Funktionen noch fertig machen. Beim Testen wurde bei einem der komplexen Parameter aus Versehen die falsche Datenbank angegeben. Keinem von uns, wir waren drei oder vier Leute, fiel dies auf. Leider wurden dann wichtige Datensätze von Kunden in der Produktivumgebung überschrieben bzw. gelöscht. Die Produktivumgebung für mehrere tausend Kunden war nicht vollständig von der Entwicklungsumgebung abgeschirmt. Mein Chef hat es zwar hinbekommen und war auch nicht böse, aber es hätte auch anders ausgehen können. Beim Vorschlag, dass sowas irgendwie anders gelöst wird, kam nur ein lapidares „Nutzen Sie doch einfach die richtige Datenbank.“. Schlussendlich wurde doch zumindest ein Parameter im Programm umbenannt.

Es gibt an dieser Stelle zwei wichtige Dinge:

  1. Die Fehlerkultur in einem Unternehmen bestimmt auch die Qualität der Software, die Weiterentwicklung dieser, die der Entwickler und zu guter Letzt die des Unternehmens.
  2. Das Unternehmen sollte unbedingt die Vita der Leute, die es beschäftigt, ansehen. Wer kann wo am besten eingesetzt werden? Wert hat wo die besten Erfahrungen? Usw. usf. Das wurde in einigen Unternehmen, in denen ich war, nicht getan.

Die schrecklichste Zeit, die ich je hatte, waren meine zwei Monate bei einem Softwareunternehmen in Koblenz. Das Unternehmen hatte unglaublich viele Probleme. Neben der bescheidenen Bezahlung für die Programmierer war allen voran die Qualität des Codes völlig unzulänglich. Niemand sah sich meine Vita an, doch einer meiner Programmierkollegen meinte irgendwann: „Er soll sich doch mal die Memory-Leaks in unserer Software ansehen, er kennt sich da aus.“

Ich wühlte mich also durch etliche Zeilen kaum lesebaren Codes, da es auch hier keinen einheitlichen Style gab. Viel schlimmer war aber, dass ich nur Zugriff auf einen auf ein Core-System aufsetzenden Code hatte, aber nicht auf das Core-System selbst. Im Core-System gab es aber etliche Probleme. Zugriff bekam ich trotzdem nicht, so dass ich meiner Aufgabe überhaupt nicht sinnvoll nachgehen konnte. Dass nur ich das alles kaum verstand, sah man am Versionsverwaltungssystem (Subversion): Von den meisten Kollegen gab es maximal einen Commit pro Woche und der Commit hatte meistens nur ein bis drei Codezeilen inne. Niemand stieg durch das System.

Auch die Aufteilung innerhalb dieser Firma war äußerst komisch. Es kam SAFE zum Einsatz, das aber nur nebenher. Aufgeteilt wurde die Entwicklung zwischen zwei Menschen: dem Requirements-Engineer (kurz RE) auf der einen, dem Programmierer auf der anderen Seite. Gehen wir von einer Rolle als Senior-Softwareentwickler (was auch immer das sein soll) aus. Der RE bekam den Auftrag für ein neues Modul oder einen Teil eines Moduls. Dieser beschrieb dann, was gemacht werden sollte (aus meiner Sicht noch ok) und dann unterteilte er es in etliche Untertasks. D.h. der RE musste dem Softwareentwickler seine eigenen Kompetenzen wegnehmen und für ihn planen, wie der Softwareentwickler dies umzusetzen hatte. Und der Softwareentwickler musste auf diese Tickets seine Zeiten buchen (das war übrigens die Hauptaufgabe: Verwalten seiner Zeiten, jede Sekunde musste protokolliert werden) und sich dafür rechtfertigen, wenn er länger brauchte oder Dinge nicht funktionierten. Das habe ich in den zwei Monaten, in denen ich da war, öfter erlebt. Man musste sich vor seinem Vorgesetzten und mitunter vor dessen Vorgesetzten verantworten. Es war die pure Hölle, was ich mittlerweile aber auch verstehen kann, weiß ich doch mittlerweile, in welcher Szene sich der Gründer des Unternehmens widerwärtig aufhält.

Kommen wir noch einmal auf die erste Firma zurück. Dort war eines der Probleme, wie ich in einem anderen Artikel bereits schrieb, dass unglaublich viel Code generiert wurde. Dabei ging es um eine Art OR-Mapper für DBMS und XML. Objektorientierte Entwicklung und generische Programmierung wurden hier immer wieder abgelehnt, obwohl diese unglaublich viele Probleme gelöst hätten. Man entschied sich für die Erneuerung des Codes für eine Multiparadigmensprache. Diese kann zwar Objektorientierung, aber nicht wirklich Vererbung. Warum die Wahl auf diese Programmiersprache fiel, war mir nie klar. Letztlich wurde das damit bekräftigt, dass die neue Generation von Programmierern kein C mehr kann. Auf C basierte die meiste alte Software (wenig auf C++, Ruby, Python, Shell-Scripts, usw.). Die Wahl hielt ich für suboptimal. Ein sinnvoller Weg wäre vielleicht gewesen, auf C++ umzusteigen. Da ein Projekt bereits in C++ umgesetzt war, waren auch schon bestimmte Kompetenzen vorhanden. Auch hätte man einen Teil des alten Codes leichter weiterverwenden können, als es mit der ausgewählten Programmiersprache möglich war (wenn diese auch C unterstützte). Die Ablösung wäre vielleicht einfacher gewesen, aber natürlich auch, dass Programmcode 1:1 übernommen worden wäre, was vielleicht nicht das eigentliche Ziel war. Es wurde allerdings Code übernommen und nahezu 1:1 in die neue Programmiersprache gesetzt. Variablen hießen gleich, Funktionen hießen gleich, der Programmablauf war der gleiche.

Zum Einsatz kamen zwei DBMS. Ein teures von einem teuren Hersteller und, für das neue Projekt, ein super gutes, welches ich auch oft empfehle. Beide DBMS wurden aber nicht wirklich als DBMS genutzt, sondern nur als Puffer für irgendwelche Daten. Auch auf vernünftige referentielle Integrität wurde, so wie ich die Datenstrukturen wahrnahm, verzichtet. Je nachdem, ob man in der Entwicklung war und Daten löschen wollte, musste man die händisch aus etlichen Tabellen entfernen. Von Normalisierung und Stored Procedures usw. müssen wir gar nicht sprechen.

Softwareentwicklung: Verwaltung zuerst – aber wie steht es um Softwarequalität?

In den letzten Jahren habe ich in verschiedenen Unternehmen gearbeitet, die zwar unterschiedlich waren, aber mit ähnlichen Problemen konfrontiert waren. Mit diesem Text möchte ich meine Perspektive auf diese Herausforderungen teilen.

Als Softwareentwickler und Administrator habe ich an zahlreichen Projekten im Softwarebereich, in der Administration sowie im Aufbau von Netzwerken und Client-Server-Strukturen gearbeitet. Einige dieser Projekte habe ich selbst geleitet, andere in Zusammenarbeit mit verschiedenen Personen betreut.

In meinen letzten Positionen war ich jedoch hauptsächlich auf die Programmierung beschränkt. Ich hatte keine Entscheidungsbefugnis und konnte mein Wissen und meine Expertise nicht sinnvoll einbringen. Stattdessen führte ich eine monotone und ermüdende Fließbandarbeit aus. Diese Erfahrung ermöglichte es mir jedoch, die Probleme aktueller Softwareunternehmen zu beobachten, die in einem ewigen Kreislauf der Selbstoptimierung gefangen sind, aber im IT-technischen Kernbereich keine bedeutenden Fortschritte erzielen.

Zwei Hauptthemenbereiche traten in diesen Unternehmen hervor (nicht in jedem, aber mindestens in einem):

  1. Die Notwendigkeit, agil zu werden und zu bleiben.
  2. Die Implementierung von CI/CD um jeden Preis.

Für die meisten klingen diese beiden Punkte sinnvoll, und in gewisser Weise sind sie es auch, insbesondere der zweite Punkt. Die Umsetzung dieser Ansätze erfolgte jedoch nicht als strukturierter Prozess, sondern eher als eine übergeordnete Aufgabe, die den Fokus von den wirklich wichtigen Aufgaben ablenkte.

Beginnen wir mit dem Thema Agilität. Was neue Softwarefirmen (Startups) von Anfang an praktizieren, wird in etablierten Unternehmen oft nur mühsam eingeführt. Ich erinnere mich noch gut daran, wie wir uns in einem Unternehmen, das von technischen Schulden geplagt war, ausschließlich auf die Einhaltung agiler Prinzipien konzentrierten, anstatt die eigentlichen Probleme anzugehen. Das bedeutete, dass wir mit Hochdruck Tools einführten und Schulungen durchführten, die die Mitarbeiter hauptsächlich beschäftigten. Da es Architekten, Product Owner und Scrum Master und so weiter gab, wollte kaum noch jemand Techniker sein, sondern einen solchen Titel tragen und Tickets und Epics durch die Gegend schieben. Das Softwareprodukt selbst blieb dabei auf der Strecke.

Wir hatten mehrere Schulungen mit einem Unternehmen, das sich meiner Meinung nach auf die Vermittlung esoterischer Agilität spezialisiert hatte. Alle zwei Wochen fand die Retrospektive statt, in der jeder seine Gefühle offenbaren musste und wir uns an wilden (Kinder-)Spielen wie „Wer ist schneller mit dem Mauszeiger?“ beteiligten. Wichtige Themen wie Bugs, Features, Refactoring, Neuausrichtung, Ideen und die Erweiterung unseres technischen Wissens wurden dabei völlig vernachlässigt. Stattdessen mussten wir uns gegenseitig loben und betonen, wie großartig unser Team sei. Das Produkt blieb oft ein einziges Chaos, und mir war die ganze Nummer mehr als peinlich.

Fahren wir mit CI/CD fort. Obwohl ich es für wichtig halte, ist es nicht so entscheidend wie das Produkt selbst. In einer Firma musste ich ein Frontend entwickeln, das zwei Kommandozeilenprozesse startete und überwachte. Es war eine relativ einfache Software, die schnell geschrieben werden konnte. Tatsächlich musste ich sie zweimal schreiben. Zuerst verwendete ich Qt und C++, was zu einem funktionsfähigen, modernen und effizienten Produkt führte. Es wurde jedoch entschieden, dass es einfacher sein und lieber mit wxWidgets geschrieben werden sollte, da die Firma bereits Erfahrung mit dieser Technologie hatte. Daher begann ich mit dem Schreiben einer neuen Version. Obwohl der Funktionsumfang geringer war, dauerte die Entwicklung aufgrund der geringeren Abstraktion von wxWidgets länger. Schließlich war das Produkt fertig, funktionsfähig und bereit für die Auslieferung. Es handelte sich um eine relativ kleine Codebasis von etwa 4.000 Zeilen C++. Nachdem ich das Produkt fertiggestellt hatte, hatte ich aufgrund von schlechtem Management (man war ja mit Agilität beschäftigt) nichts mehr zu tun. Man schlug vor, dass ich mich mit dem Testing befassen sollte, da das Produkt in CI/CD integriert werden musste. Dies umfasste drei Hauptaspekte:

  1. Unit- und Integrations-Tests mit Google-Test
  2. Statische Codeanalyse mit SonarQube
  3. Automatische GUI-Tests

Ich habe mich dann über ein halbes Jahr ausschließlich mit diesem Projekt beschäftigt. Während die Unit- und Integrations-Tests noch relativ einfach zu handhaben waren, erwies es sich als deutlich schwieriger, Anwendungsfälle für eine Software mit über 4.000 Zeilen Quellcode zu entwickeln, von denen der Großteil GUI-bezogen war. Das agile Testmanagement verlangte eine Code-Coverage von mindestens 70 %. Anstatt mich also auf die eigentliche Kernsoftware zu konzentrieren, die dieses von mir entwickelte Frontend lediglich startete und überwachte, widmete ich mich der ABM und der Erstellung von Tests, die letztendlich keinen wirklichen Zweck erfüllten. Der Grund dafür ist einfach: Die Software war funktionsfähig, sollte nicht weiterentwickelt werden und war nicht anfällig für Fehler. Sie war ausgebaut und lediglich im Bestand. Darüber hinaus sollte sie in naher Zukunft durch eine andere Software ersetzt werden.

Trotz dieser Umstände durfte ich mich weiterhin mit der Umsetzung der teils eigenwilligen Standard-Regeln von SonarQube befassen. In den gesamten 4.000 Zeilen Code entdeckte SonarQube lediglich einen einzigen Bug (einen gelöschten Pointer, der in einem anderen Codesegment erneut aufgerufen wurde). Die restlichen Hinweise bezogen sich auf unbedeutende Aspekte wie die Anzahl der Member-Variablen und die Begrenzung der Methodenanzahl pro Klasse auf 30.

Da die Software auch zwei klickbare Buttons enthielt, musste ich vollautomatische GUI-Tests implementieren. Dies stellte sich bei einer wxWidgets-Anwendung mit C++ als Herausforderung dar, konnte aber erfolgreich gemeistert werden. Dadurch wurde das gesamte GUI vollautomatisch testbar.

Obwohl dies die Software, die im Mittelpunkt stand, nicht direkt voranbrachte, fügte es doch ein weiteres Puzzleteil zur Pipeline hinzu. Ich konnte wertvolle Erkenntnisse gewinnen, die ich bei zukünftigen Softwareprojekten, wo es sinnvoll ist, anwenden kann.

In einer anderen Firma war ich an zwei oder drei Softwareteilen beteiligt. Auch hier wurde, im Zuge des Wachstums des Produkts, zunehmend Wert auf die Pipeline gelegt. Folglich mussten zahlreiche Tests nachimplementiert werden. Dies war nur bedingt sinnvoll, da drei wesentliche Probleme vorlagen:

  1. Die Qualität des Codes und insbesondere der gesamten Architektur war mangelhaft, wenn nicht gar nicht vorhanden.
  2. Es gab Fachverfahren, die eine umfassende Einarbeitung erforderten oder eine gezielte Einweisung notwendig gemacht hätten.
  3. Die Software sollte vollständig durch eine neue Version in einer anderen Programmiersprache ersetzt werden. Diese neue Architektur war jedoch ebenfalls fehlerhaft und entsprach nicht den Qualitätsstandards, die ich vertrete.

Einige der Tests hätten durchaus auch für die zweite Generation der Software verwendet werden können, was sinnvoll war, um das Verhalten der alten und neuen Software zu vergleichen. Doch meiner Meinung nach war das Projekt dazu verdammt, gegen die Wand zu fahren.

Unit-Tests, Integrationstests, Code-Reviews, CI/CD, statische Codeanalyse, GUI-Tests, Dokumentation, nachverfolgbare Ticketbearbeitung, Kompetenztransfer und vieles mehr sind entscheidend für eine nachhaltige Softwareentwicklung. Diese Elemente sollten jedoch von Anfang an integriert sein. Sie später, insbesondere bei großen Projekten, einzuführen, ist ineffektiv, vor allem bei komplexen Projekten mit Hunderttausenden von Codezeilen. Darüber hinaus können andere technische Schulden so hoch sein, dass sie dringendere Aufmerksamkeit erfordern.

Ich habe es immer wieder erlebt, dass Unternehmen weiterhin auf veraltete Frameworks setzen. Ich bin auf Systeme gestoßen, die 20 Jahre alt oder noch älter waren und längst nicht mehr unterstützt wurden. Oder auf Plattformen, die über 20 Jahre alt waren und auf denen immer noch die Software für aktuelle Systeme kompiliert wird, weil die Migration auf aktuelle Plattformen vernachlässigt wurde.

Doch das ist nicht alles. Die Qualität von Software-Code ist ein entscheidender Faktor in der Softwareentwicklung. Ich habe Ein-Personen-Projekte erlebt, die aufgrund ihrer zunehmenden Komplexität oder der Sorge um die langfristige Verfügbarkeit des ursprünglichen Entwicklers zusätzliche Teammitglieder erforderten. Diese neuen Teammitglieder haben jedoch oft Schwierigkeiten, den Code, die Fachverfahren und das gesamte System zu verstehen.

Aber warum ist das so? Ein Ein-Personen-Projekt hat von Natur aus seine Grenzen. Der ursprüngliche Entwickler versteht den Code vielleicht noch, aber das gilt nicht unbedingt für andere. In den letzten Jahren bin ich immer wieder auf schlecht geschriebenen Code gestoßen. Schon die Verwendung von Funktionen, Methoden oder Variablennamen wie „reg_rq_fachver2_23“ ist wenig hilfreich. Darüber hinaus habe ich unglaublich redundanten Code gesehen, wie zum Beispiel:

int za_wwggw_w2(int p, int p_k, int p_key, int k, int key, char *pk) {
int _key;
struct pkey *pkey_p;
return za_wwggw_w3(p, p_k, p_key, k, key, pk, &_key, pkey_p);
}

Selbst nach mehrmaligem Lesen verstehe ich diesen Code nicht. Wenn ich mich durch etwa 50 Dateien mit mehreren zehntausend Zeilen Code kämpfen müsste, der genauso oder noch schlimmer aussieht, würde ich irgendwann aufgeben.

Es gab Software, bei der GUI-Komponenten mit Namen wie Edit1, Edit2, Edit3 bis Edit123 versehen waren. Diese Praxis führte zu immensen technischen Schulden, die ich nicht erklären kann. Schließlich ist allgemein bekannt, dass sauberer und lesbarer Quellcode die Notwendigkeit von Dokumentation minimiert (die oft ohnehin nicht vorhanden ist), das Bugfixing und die Wartbarkeit erhöht sowie die Einarbeitung anderer Menschen vereinfacht.

Betrachten wir das Projekt mit der Methode za_wwggw_w2. Es war offensichtlich, dass das Projekt unkontrolliert gewachsen war und eine Reimplementierung erforderlich war. Meiner Meinung nach war dies der einzige praktikable Ansatz, um das Projekt weiter auszubauen. Allerdings sah ich sofort mehrere Probleme:

  1. Die Reimplementierung wurde nicht als eine vollständige Neubegründung des Projekts verstanden, was angesichts seiner Komplexität eine gewaltige Aufgabe gewesen wäre. Stattdessen wurde sie als eine Portierung des alten Codes auf eine neue Programmiersprache wahrgenommen, mit minimalen Anpassungen, um die Besonderheiten der neuen Sprache zu berücksichtigen. Als ich den Code der anderen Programmierer untersuchte, stellte ich fest, dass er fast identisch mit dem alten Code war, mit nur wenigen geringfügigen Änderungen. Die zugrundeliegenden Probleme blieben bestehen, und ohne jemanden direkt verantwortlich machen zu wollen, würde ich behaupten, dass die meisten, die an dieser Umsetzung beteiligt waren, sie nicht vollständig verstanden.
  2. Darüber hinaus wurde im Prozess keine Architektur implementiert. Da die neue Programmiersprache eine einfache Integration von Code aus dem alten System ermöglichte, wurde diese Funktion häufig genutzt.
  3. Es wurde eine Masse an „gleichem“ Code automatisch generiert, anstatt auf Abstraktion, Ableitung und Konventionen zu setzen. Viele tausende Zeilen gleicher Code mit leicht unterschiedlicher Logik wurde generiert.

Leider wurden die gleichen Fehler gemacht wie bei dem Ein-Personen-Projekt, obwohl das Team aus erfahrenen Programmierern bestand, die jahrelange und jahrzehntelange Erfahrung mitbrachten. (Ich kam relativ spät dazu und wurde hauptsächlich als „Programmieräffchen“ eingestellt.)

Diese Erfahrung habe ich in zahlreichen Projekten gemacht. In einem Projekt, das stark auf eine Datenbank angewiesen war, deaktivierte mein Vorgänger die referentielle Integrität mit der Begründung, es würde die Leistung verbessern. Dies führte jedoch dazu, dass die Datenbank in einen fehlerhaften Zustand geraten konnte (was auch mehr als nur einmal passierte). Solche Probleme hätten leicht behoben werden können, indem beispielsweise ein zuverlässiges Datenbankmanagementsystem (DBMS) verwendet oder qualitativ hochwertiger Code geschrieben worden wäre. Trotzdem wurden diese Maßnahmen nicht ergriffen.

Meine Botschaft ist klar: Anstatt sich ausschließlich auf das Umfeld zu konzentrieren, würde es vielen Produkten zugutekommen, wenn ein stärkerer Fokus auf die Produkte selbst gelegt würde. Auch vorher Gedanken zu machen und Erfahrungen von Menschen einzubringen, die das seit Jahren/Jahrzehnten bereits machen, ist absolut sinnvoll.

Auf der Suche nach neuer Herausforderung

Zur Zeit bin ich wieder aktiv auf der Suche nach einer neuen Herausforderung. Wenn jemand etwas Interessantes im Angebot hat oder jemanden kennt, der das hat oder sogar jemanden kennt, der jemanden kennt…, gerne per E-Mail an mich (-:

Ich suche hauptsächlich im Bereich der Softwareentwicklung, da gerne in Bezug auf neue Projekte. Sehr gerne mit einem Anteil an Administration (80:20 oder 70:30).

Thorsten Geppert
Thorsten Geppert

FreeBSD-Upgrade: vom Desaster doch noch zum Erfolg? Es war schrecklich

Ich gebe es zu: Ich habe meinen Server, der online steht und, unter anderem, dieses Blog betreibt, ziemlich und auch lange vernachlässigt. Installiert war ein FreeBSD 13.3 amd64. Die aktuelle Version aus der 13er-Reihe war 13.4. So weit zurück war ich nicht, was aber das größere Problem war, waren die installierten Packages, allen voran PostgreSQL, MySQL und PHP.

Rauchender Server

Ich dachte mir, ich ziehe mein FreeBSD 13.3 direkt auf 14.2, damit zumindest das Grundsystem mal aktuell ist und Dienste wie SSH und ähnliche mit Sicherheitsupdates versorgt werden. Die Packages wollte ich dann irgendwann später nachziehen.

Also begann ich, das Upgrade durchzuführen. Das lief auch gut, bis zum ersten Reboot. Der Server kam nicht mehr hoch. Zumindest dachte ich das. Von Hetzner ließ ich mir eine KVM anschließen und war doch erstaunt: Der Server ist hochgefahren und der erste Schritt des Upgrades war erfolgreich. Jedoch hatte der Server kein Netzwerk mehr. Warum, weiß ich nicht, ich konnte es aber schnell lösen, indem ich von meiner statischen Netzwerkonfiguration auf DHCP umgestellt habe. Also weiter mit dem Upgrade.

Der zweite Reboot ging dann leider in die Hose. Ich habe mir wieder eine KVM von Hetzner anschließen lassen (die erste hatte ich nur für eine Stunde geliehen) und sah, dass ich beim Mergen der Konfigurationen irgendwo zwei Zeilen „wegoptmiert“ hatte und so ein Script, welches zum Booten benötigt wird, fehlschlug. Reboot. Die Maschine kam hoch, schmiss aber ein paar Fehlermeldungen. Problematisch war, dass ich mich mit keinem meiner Accounts anmelden konnte. Irgendwelche anderen Scripte waren auch kaputt.

Anscheinend habe ich es entweder geschafft, ein paar Dinge kaputt zu machen (was mir zuvor noch nie passiert war), oder es gab irgendwelche anderen Probleme. Durch den Boot in den Single-User-Mode konnte ich mich umsehen und habe versucht, die Probleme zu fixen. Vergeblich. Dann hatte ich aber auch keine Lust mehr und die KVM war ja auch nur für drei Stunden geliehen, es musste eine Lösung her. Fakt war, dass im etc-Verzeichnis einiges kaputt war.

Also kopierte ich das etc-Verzeichnis von einer funktionsfähigen Installation von FreeBSD 14.2, schob meine Konfigurationen hinein und kopierte alles per „scp“ auf meinen Server. Zumindest das Grundsystem funktionierte dann wieder und ich brauchte die KVM nicht mehr.

Doch kaum ein Dienst funktionierte. Wir (meine Familie und ich) sind allerdings auf ein paar Dienste angewiesen: Mail, Card– und CalDav, mein Blog, NextCloud, meine Projekte, Git, usw.

Es blieb mir nichts übrig, als alles hochzuziehen. Wieder einmal dachte ich mir, wie sinnvoll es wäre, verschiedene Dienste in verschiedenen Jails zu organisieren und regelmäßiger Updates und Upgrades durchzuführen. Es war gut ein Tag Arbeit, alles wieder ans Rennen zu bekommen, zumal auch Packages wegfielen (wxWidgets 2.8, welches ich für compow.de benötige).

Redmine 5.1 auf FreeBSD

Obwohl es bereits Redmine 6.0.1 zum jetzigen Zeitpunkt gibt, haben wir unter FreeBSD bisher leider „nur“ Version 5.1 zur Verfügung. Allerdings gab es auch eine ganze Weile lang keine lauffähige Redmine-Version für FreeBSD in den Packages und Ports.

Ich habe Version 5.1 testweise in einer VM installiert und es funktionierte problemlos. Letztlich kann man nach dieser Anleitung vorgehen:

Ich freue mich darüber, dass es funktioniert und wir Redmine weiterhin unter FreeBSD nutzen können und hoffe, dass es bald auch eine aktuellere Version gibt.

Sprechende Namen oder: Code-Qualität

Da es in einem meiner letzten Projekte vorkam und sich jetzt auch öfter wiederholt hat, möchte ich einmal dazu etwas schreiben. Das Thema ist „Programmieren“.

Beim Programmieren in einer der meisten gängigen Programmier- oder Scriptsprachen schreibt man Quellcode. Dieser Quellcode ruft oftmals Prozeduren oder Funktionen auf, die mit den Bibliotheken beim Compiler mitkommen. Der Programmierer schreibt aber auch eigene. Dabei geht es mir um diese Themen:

  • Verzeichnis- und Dateihierarchie
  • Benamung von Dateien
  • Benamung von Codebestandteilen
    • Funktionen
    • Prozeduren
    • Klassen/Interfaces
    • Variablen
    • Konstanten

Mir ist oft aufgefallen, dass diesen Themen oftmals nur ungenügend Aufmerksamkeit geschenkt wird, dabei ist das, meiner Meinung nach, unglaublich wichtig, wenn

  • Der Code gewartet werden soll über Jahre oder Dekaden
  • Andere den Code verstehen sollen
  • Andere den Code ändern oder erweitern sollen
  • Andere den Code portieren sollen
  • Es keine ausreichende Dokumentation gibt

Ein Beispiel. Wir haben eine Funktion, die sieht selbst so aus und hat folgenden Inhalt:

int ab_ad_nmb_re(int pab, int p_ab, bool ab) { 
    int pab_list; 
    char *pa; 
    … 
}

Da gibt es mehrere Probleme:

  1. Der Funktionsname besteht aus etlichen Abkürzungen, die ein anderer nicht kennt, nachschlagen und sich merken muss. Oder immer wieder nachschlagen muss. Dementsprechend nichtssagend ist der Name
  2. Die Variablen heißen alle fast gleich, sind nichtssagend und unglaublich verwirrend

Oftmals, von mehreren unterschiedlichen Leuten, höre ich dann folgende Argumente:

  • Ich weiß ja, was das alles heißt
  • Du kommst da schon irgendwann rein
  • Wir können doch keine aussagekräftigen Namen nehmen, da das dann zu lang ist und dann bringt das auch keinem was

Ehrlicherweise muss ich da sagen: Nein. Ich nehme (s. GitHub) halbwegs aussagekräftige Namen (manchmal, selten, auch mal nicht, das sollte so aber nicht sein). Sie sagen aus, was sie machen, man braucht keine oder wenig Dokumentation und auch andere sind schnell eingearbeitet und können Änderungen vornehmen.

Bezüglich langer Namen: Jeder halbwegs taugliche Editor zum Programmieren bietet Autovervollständigung. Selbst VIM bringt im Standard bereits eine kontextlose Autovervollständigung mit, die ich gerne benutze: [Strg]+[p/n]. Damit sind längere Namen kein Problem mehr, da nur der oder ein paar Anfangsbuchstaben getippt werden müssen.

Das hat viele Vorteile:

  • Der Code wird lesbarer
  • Andere können sich viel schneller einarbeiten
  • Der Code selbst ist Dokumentation

Mein altes Projekte Warehouse nutzt solche Namen an den meisten Stellen. Das Projekt ist von 2009 und wurde mit VIM umgesetzt. Aber schaut euch auch Frameworks an, die Methodennamen mit vernünftiger Benamung haben wie Qt, wxWidgets, Java-SDK, uvm.

Ich kann nur empfehlen, lieber den Code etwas aussagekräftiger zu gestalten, denn meiner Meinung nach zahlt sich das schnell aus. Speicher ist günstig, da machen die paar Bytes den Kohl auch nicht fett.

Bald neue Videos

Viele haben mir geschrieben, dass ich doch weitere Videos bzw. Tutorials machen soll. Das freut mich sehr.

Zur Zeit nimmt mich die neue Arbeitstelle und meine Familie gut ein, ich habe aber schon die nächsten Videos geplant (Themen: wxWidgets, Qt und auch FreeBSD) und freue mich, sie bald machen und veröffentlichen zu können. Es dauert allerdings noch ein paar Tage. Aber: Es wird mit den Tutorials weiter gehen.

Wenn ihr Vorschläge für bestimmte Themen habt, gerne her damit.