„Es fehlen Spalten“ – die zugleich beste und schlimmste Codebasis
(jimmyhmiller.github.io)„Die Tabelle
merchants2? Ja, wir habenmerchants2erstellt, weilmerchantsnicht genug Spalten hatte.“
- Als ich mit dem Programmieren anfing, wusste ich nicht, dass Menschen damit Geld verdienen
- In meinem ersten Softwarejob habe ich viel gelernt, und die Codebasis dort war zugleich die schlimmste und die beste
Datenbanken überleben für immer
- In Legacy-Systemen ist die Datenbank mehr als nur ein Datenspeicher. Sie legt die Einschränkungen des gesamten Systems fest und ist der Treffpunkt für allen Code
- SQL Server hat eine Begrenzung für die Anzahl der Spalten in einer Tabelle. Damals waren es 1024, heute sind es 4096. In der Tabelle
Merchantsreichten die Spalten nicht aus, also wurdeMerchants2erstellt (mit mehr als 500 Spalten) MerchantsundMerchants2waren der Kern des Systems. Alles war mitMerchantsverbunden. Es gab auch andere normalisierte Tabellen, aber sie hatten Fremdschlüsselbeziehungen zuMerchants
SequenceKey
SequenceKeyist eine einfache Tabelle mit nur einer Spalte und einem einzigen Wert- Sie wurde zur Erzeugung von IDs verwendet. Vermutlich wurde sie erstellt, weil SQL Server keine automatisch inkrementierenden IDs unterstützt habe
- In jeder Stored Procedure wurde ein Schlüssel aus
SequenceKeygeholt und erhöht und dann als ID in mehreren Tabellen verwendet. Sie fungierte als impliziter Join
Calendar
Calendarist eine manuell gepflegte Kalendertabelle. WennCalendarablief, konnte man sich nicht im System anmelden- Das ist vor einigen Jahren tatsächlich passiert, und ein Praktikant hat weitere fünf Jahre eingetragen. Niemand weiß, welches System das verwendet
Employees
- Jeden Morgen um 7:15 Uhr wurde die Tabelle
employeesgelöscht und mit einer von ADP erhaltenen CSV-Datei neu befüllt - Während dieses Vorgangs konnte man sich nicht im System anmelden. Manchmal schlug dieser Vorgang auch fehl
- Die Daten mussten an die Zentrale repliziert werden, also wurden sie per E-Mail an eine Person geschickt, die jeden Tag einen Button drückte, um die Daten zu kopieren
Ersatzdatenbank
- Man könnte denken, man könne die Datenbank aufräumen. Das dachte auch das Unternehmen
- Es gab eine Kopie der Datenbank, deren Daten etwa 10 Minuten hinterherhinkten. Die Synchronisierung verlief nur in eine Richtung
- Diese Datenbank war normalisiert, sodass man 7 Joins brauchte, um eine Telefonnummer aus
merchantszu finden
Vertriebserfolge
- Alle Vertriebsmitarbeiter hatten jeden Monat ein Soll an „wins“, das sie erreichen mussten
- Die Tabelle zur Verwaltung davon war äußerst komplex. Täglich lief ein Job, der hinzugefügte oder geänderte Zeilen fand und sie mit dem System der Zentrale synchronisierte
- Ein Problem entstand, als ein Vertriebsmitarbeiter darum bat, einen Datensatz manuell ändern zu lassen
- Dieser Mitarbeiter hatte sein Soll bereits erfüllt und zusätzlich in diesem Monat noch einen großen Verkauf gemacht, wollte diesen aber in den nächsten Monat verschieben
- Ein Praktikant übernahm diese Aufgabe, und als sich das herumsprach, stiegen die Anfragen über drei Jahre exponentiell an
- Zeitweise bestand die gesamte Arbeit von drei Praktikanten darin, SQL-Statements dafür zu schreiben. Eine Anwendung dafür zu bauen galt als zu schwierig
Die Codebasis
- Die erste Codebasis, mit der ich zu tun hatte, lag in Team Foundation Server, einem zentralisierten Versionsverwaltungssystem
- Die Codebasis, an der ich hauptsächlich arbeitete, bestand zur Hälfte aus VB und zur Hälfte aus C#. Sie lief auf IIS und verwendete überall Session State
- Das bedeutete praktisch, dass man auf derselben Seite völlig unterschiedliche Dinge sah, je nachdem, ob man über Pfad A oder Pfad B dorthin gelangte
- Jedes JavaScript-Framework, das es damals gab, war in dieses Repository eingecheckt worden. Meist mit benutzerdefinierten Änderungen, die der jeweilige Autor für nötig hielt. Besonders auffällig waren
knockout,backboneundmarionette, dazujqueryundjquery-Plugins - Zusätzlich zu dieser Codebasis gab es etwa 12 SOAP-Services und mehrere native Windows-Anwendungen
Gilfoyles Festplatte
- Gilfoyle galt als unglaublich schneller Programmierer. Ich habe ihn nie getroffen, aber ich kannte ihn durch seinen Code und den Code, der auf seiner Festplatte übrig geblieben war
- Munch bewahrte Gilfoyles Festplatte noch Jahre nachdem er das Unternehmen verlassen hatte als RAID-Konfiguration auf seinem Schreibtisch auf
- Denn Gilfoyle war dafür bekannt, Code nicht einzuchecken und stattdessen zufällige Wegwerf-Windows-Anwendungen für einzelne Benutzer zu bauen
- Es war nicht ungewöhnlich, dass Benutzer mit Bugreports für Anwendungen ankamen, die nur auf Gilfoyles Festplatte existierten
Versand-Bug
- Der Großteil meiner Arbeit bestand darin, Bugs nachzuverfolgen, die das Team keiner eigentlichen Arbeit zuweisen wollte
- Es gab einen besonders lästigen Bug, der alle paar Monate auftrat: Es gab Bestellungen, die nach dem Versand in der Versandwarteschlange hängen blieben und als nicht versandt erschienen, obwohl sie bereits versandt waren
- Für die Behebung wurden mehrere Ansätze ausprobiert (SQL-Skripte, Windows-Anwendungen usw.). Mir wurde geraten, der eigentlichen Ursache nicht nachzugehen, aber ich konnte es nicht lassen
- Dabei lernte ich Gilfoyles Denkweise kennen. Die Versand-App lud die gesamte Datenbank und filterte dann nach Datum, sodass alle Bestellungen seit dem Startdatum der Anwendung gehalten wurden
- Die App hing von einem SOAP-Service ab, aber nicht, um serviceartige Dinge zu tun, sondern als reine Funktion. Alle Nebenwirkungen verursachte der Client
- In diesem Client entdeckte ich eine riesige Klassenhierarchie mit 120 Klassen, jeweils mit diversen Methoden, und Vererbung bis zu 10 Ebenen tief
- Das einzige Problem war, dass alle Methoden leer waren
- Das diente dazu, eine Struktur aufzubauen, die Reflection verwenden konnte. Diese Reflection erzeugte einen durch Pipes getrennten String (datenbankgestützt, aber völlig statisch aufgebaut) und schickte ihn über einen Socket
- Am Ende wurde das an Kewill geschickt, einen Service zur Kommunikation mit Frachtführern. Der Bug trat auf, weil Kewill jeden Monat 9-stellige Zahlen wiederverwendete und jemand den Cron-Job deaktiviert hatte, der alte Bestellungen löschte
Wunderschönes Chaos
- Über diese Codebasis ließe sich noch viel mehr sagen: über das Team von Senior-Entwicklern, das fünf Jahre lang keine Software auslieferte und alles neu schrieb, oder über die Red-Hat-Berater, die eine einzige Datenbank bauen wollten, die alles kontrolliert
- Diese Codebasis hatte viele verrückte Ecken und genug Gründe, warum man ein eigenes Team gebraucht hätte, nur um eine einzelne Funktion von Grund auf neu zu beginnen
- Die wichtigste Geschichte ist aber die, wie Justin die Seite
Merchants Searchverbessert hat. Diese Seite war der Einstiegspunkt in die gesamte Anwendung - Alle Customer-Service-Mitarbeiter suchten während eines Telefonats mit einem Händler nach Informationen, indem sie eine ID oder einen Namen eingaben. Danach landeten sie auf einer riesigen Seite mit allen Informationen
- Diese Seite war mit allen nötigen Informationen und allen relevanten Links vollgepackt und auf die bestmögliche Weise informationsdicht. Aber sie war unglaublich langsam
- Justin war der einzige Senior-Entwickler in meiner Gruppe. Er war klug, sarkastisch und am Business kaum interessiert
- Er sagte die Dinge, wie sie waren, nahm kein Blatt vor den Mund und konnte Probleme allein immer schneller lösen als die Teams um ihn herum
- Eines Tages hatte Justin genug davon, ständig zu hören, wie langsam die Händler-Suchseite war, also ging er hin und reparierte sie
- Jede Box auf dem Bildschirm bekam ihren eigenen Endpoint. Beim Laden wurde alles oberhalb des Folds angefragt, und sobald eines geladen war, folgten weitere Requests
- Die Ladezeit der Seite sank von mehreren Minuten auf unter eine Sekunde
Zwei Wege zur Entkopplung
- Justin konnte das tun, weil es in dieser Codebasis keinen Masterplan gab
- Es gab keinen groben Bauplan, an den sich das System halten musste, kein erwartetes Format für APIs, kein dokumentiertes Design-System und kein Architektur-Review-Board, das Konsistenz sicherstellte
- Die App war ein komplettes Chaos. Niemand konnte sie reparieren, also hat es auch niemand versucht. Stattdessen erschufen wir unsere eigenen kleinen Inseln der Vernunft
- Diese monolithische App wuchs aus reiner Notwendigkeit an ihren Rändern zu einem Mikrokosmos guter kleiner Apps heran
- Jede Person, die den Auftrag bekam, einen Teil der App zu verbessern, gab zwangsläufig den Versuch auf, das Spinnennetz zu entwirren, suchte sich stattdessen eine gute kleine Ecke, um etwas Neues zu bauen, aktualisierte dann nach und nach die Links auf das neue gute Ding und machte das alte damit zum Waisenkind
- Das mag chaotisch klingen. Aber es war überraschend angenehm, darin zu arbeiten. Die Sorge um Code-Duplizierung verschwand, ebenso die Sorge um Konsistenz und um Skalierbarkeit
- Code wurde für die Nutzung geschrieben, so dass möglichst wenig von den umliegenden Bereichen berührt wurde und er leicht ersetzbar blieb. Unser Code war entkoppelt, weil Koppeln einfach schwieriger war
Danach
- In meiner weiteren Laufbahn hatte ich nie wieder das Privileg, in einer so erstaunlich hässlichen Codebasis zu arbeiten
- Jede hässliche Codebasis, die ich danach gesehen habe, konnte das Bedürfnis nach Konsistenz nicht überwinden
- Vielleicht lag es daran, dass die „ernsthaften“ Entwickler die Codebasis schon lange zuvor aufgegeben hatten. Übrig geblieben waren nur chaotische Praktikanten und Junior-Entwickler
- Oder vielleicht lag es daran, dass es keine Zwischenschicht zwischen Entwicklern und Benutzern gab. Keine Übersetzung, keine Anforderungserhebung, keine Tickets. Man stand einfach am Schreibtisch eines Customer-Service-Mitarbeiters und fragte, wie man sein Leben verbessern könnte
- Mir fehlt diese direkte Verbindung. Das schnelle Feedback, die Tatsache, dass man keine großen Pläne machen musste, die direkte Verbindung zwischen einem einfachen Problem und dem Code
- Vielleicht ist es einfach naive Nostalgie. Aber wie bei dem Wunsch, in die schlimmsten Jahre meiner Kindheit zurückzukehren, kehrt mein Herz jedes Mal, wenn ich mit „Enterprise Design Patterns“ konfrontiert werde, zu dieser wunderschönen, schrecklichen Codebasis zurück
Meinung von GN⁺
- Dieser Text kann Entwicklern, die mit Legacy-Systemen arbeiten, Verständnis und Trost geben. Er zeigt, dass auch unvollkommene Codebasen wertvoll sein und viele Lernchancen bieten können
- Die Probleme dieser Codebasis sollten jedoch nicht romantisiert werden. Wenn sich technische Schulden anhäufen, verlangsamt das die Entwicklung erheblich und erschwert die Wartung. Langfristig kostet es mehr
- Die richtige Antwort ist nicht, Versuche zur Verbesserung der Codebasis aufzugeben und weiter Provisorien anzuhäufen. Es braucht eine Strategie, um Legacy-Systeme schrittweise zu verbessern oder zu migrieren
- Auch Entwicklungskultur und Prozesse sind wichtig. Gute Engineering-Praktiken wie Code-Reviews, Architekturdesign und Dokumentation helfen dabei, bessere Codebasen zu schaffen
- Die enge Kommunikation mit Benutzern und schnelles Feedback sind positiv. Ideal ist es, das etwa durch Methoden wie Agile zu fördern und gleichzeitig die Codequalität zu steuern
- Letztlich ist alles eine Frage des Gleichgewichts. Wichtiger als Perfektion ist es, die Bedürfnisse der Benutzer nachhaltig zu erfüllen und technische Schulden zu managen
3 Kommentare
In meinem ersten Job als Firmware-Entwickler bestand meine Aufgabe darin, den aus der Hex-Datei eines 8051-MCUs extrahierten Assemblercode eines Produkts ohne Entwickler und ohne Quellcode zu analysieren und ihn in C neu zu implementieren …
Zum Glück gab es immerhin ein funktionierendes Produkt, also habe ich mir irgendwie damit geholfen, den Code anzuschauen, das Produkt zu testen und es so am Ende doch hinzubekommen …
Ich wurde sogar schon bedroht nach dem Motto, ich solle es entweder auf einer Dienstreise in der Provinz reparieren oder mir den Finger abschneiden und dann gehen.
Und ein mysteriöser Bug stellte sich einmal tatsächlich als der Aufzug hinter der Wand heraus, an der das Gerät installiert war.
Außerdem erinnere ich mich noch daran, wie ich vor der offiziellen Eröffnung des APEC-Tagungsorts auf der Dongbaekseom-Insel in Busan hineinging und dies und das installiert habe, haha
Hacker-News-Kommentare
Im ersten Unternehmen eine komplexe VB-Anwendung betreut
Im ersten Job ein Legacy-Produkt gewartet, das in COBOL und Java geschrieben war
Ein Perl-Skript mit mehr als 12.000 Zeilen refaktoriert
Den Unterschied zwischen Theorie und Praxis gespürt
Die Codebasis des Telegram-Android-Clients war extrem komplex
Im ersten Job Speicherprobleme bei Reporting-Aufgaben gelöst
Die Erfahrung, Probleme im direkten Austausch mit Kunden zu lösen, war positiv
Ein System entwickelt, das mehrere Märkte unterstützte
Im ersten Job gab es viele unerfahrene Leute
Erklärt, wie sich Probleme in modernem SQL Server lösen lassen
Sequenznummern-Tabelle (
SequenceKey) und Geschäftstags-Tabelle (Calendar)wecken Erinnerungen. Ich weiß nicht, wie man das heute macht, aber früher waren das weit verbreitete Tabellen. Wenn man SI-Projekte gemacht hat, wurde die zugehörige Funktionalität im geschäftsübergreifenden Teil implementiert.