Zum Inhalt springen

Blogeintrag

Problemstellen im Legacy Code aufspüren

Programmierung & DevOps 

Viele Entwicklerteams leiden unter Legacy Code. Mit der Dauer eines Projektes werden Änderungen am Legacy Code immer komplexer und das Risiko von Seiteneffekten steigt. Bei Entwicklern macht sich Unsicherheit, Frustration und Kontrollverlust breit. Das sind keine guten Voraussetzungen für motiviertes und produktives Arbeiten.

Ein neuer Blick auf Legacy Code

Für viele Entwickler ist Legacy Code etwas, was vor langer Zeit von jemand anderem entwickelt wurde und schlecht wartbar ist. Gibt man Legacy in ein Übersetzungsprogramm ein, so erhält man Ergebnisse wie Altlast, Erbe und Hinterlassenschaft.

Eine moderne Definition wirft einen ganz anderen Blick auf Legacy Code. Sie besagt: „Legacy Code ist alles was nicht automatisch getestet wird.“  Für viele ist das eine Überraschung, denn plötzlich kann Code, den man vor wenigen Minuten selbst geschrieben hat, schon als Legacy Code eingestuft werden. Bei dieser modernen Definition geht es nicht um Zeit oder wer Code geschrieben hat, sondern um Information - Information darüber, ob Code funktioniert! Diesen Nachweis kann man meist nur mit Tests erbringen. Bei häufigen Änderungen braucht man diese Informationen schnell und häufig, was Testautomatisierung unabkömmlich macht. Automatisierte Tests sind somit ein Sicherheitsnetz. Es fängt Entwickler auf, wenn sie Seiteneffekte in ihren Code einbauen. 

Strategie beim Umgang mit Legacy Code

Durch fehlende automatisierte Tests lässt sich also Legacy Code aufspüren. In den meisten Projekten ist es jedoch nicht möglich, den gesamten Legacy Code zu sanieren (Sanieren bedeutet u. a., den Code einem Refactoring zu unterziehen und ihn mit automatisierten Tests abzusichern). Die Aufwände wären zu groß und nur wenige Auftraggeber sind bereit, das dafür notwendige Budget freizugeben. Es ist daher ein Kompromiss notwendig, der wie folgt aussehen kann:

  1. Neuer Code wird testgetrieben entwickelt. Dies führt automatisch zu besserer Qualität, gutem Design und hoher Codeabdeckung.
  2. Wird bestehender Code geändert, müssen die betreffenden Stellen einem Refactoring unterzogen und mit automatisierten Tests (vorwiegend Unit-Test) abgesichert werden. Die Grundregel sollte hier lauten: „Hinterlasse den Code in einem besseren Zustand, als zu ihn vorgefunden hast.“
  3. Strategisch wichtige Bausteine und Problempunkte im Code werden proaktiv saniert.

Ein Baustein gilt als strategisch wichtig, wenn er für den Erfolg eines Unternehmens einen wesentlichen Beitrag leistet und eine schlechte Qualität hohe geschäftliche Nachteile mit sich brächte. Problempunkte zeichnen sich dadurch aus, dass sie bereits viele Probleme verursachen und hohes Risiko in sich bergen.

Problempunkte im Code mit statischer Codeanalyse aufspüren

Problempunkte lassen sich schon mit einfacher statischer Codeanalyse aufspüren. Statische Codeanalyse ist „State of the Art“ in der Softwareentwicklung. Als Datenquelle dient dabei ausschließlich Code. Demzufolge kann statische Codeanalyse auch „nur“ Erkenntnisse liefern, die aus dem Code gewonnen werden können: Länge, Verschachtelungstiefen, Verletzung von Clean Code Regeln, Fehlermuster, … Diese Informationen reichen jedoch oft schon aus, um die wichtigsten Problempunkte im Code zu identifizieren, wie das nachfolgende Beispiel zeigt:

Teamscale Codeanalyse
Abbildung 1 – Brandherde anhand statischer Codeanalyse in Teamscale

Im dargestellten Beispiel gibt es große Qualitätsunterschiede in den Bausteinen. Während der Baustein mac eine befriedigende Qualität aufweist, sind im Baustein controller zahlreiche Probleme zu finden. Die Code-Abdeckung mit Unit-Test ist bei allen Bausteinen 0% (siehe Line Coverage).

Soll man also jetzt die Bausteine controller als erstes einem Refactoring unterziehen und automatisierte Tests entwickeln? Auf den ersten Blick lautet die Antwort Ja! Jedoch sollte man noch hinterfragen und analysieren, ob der Baustein controller z.B. gar nicht mehr geändert werden muss und im Test und Betrieb im controller vielleicht noch nie Fehler entdeckt wurden. In diesen Fällen ist die Refactoring-Strategie entsprechend anzupassen.

Es ist daher immer gut, das Ergebnis einer statischen Code-Analyse mit dem Umfeld- und Fachwissen eines Experten zu bewerten und „zurechtzurücken“.

Big Data hilft

Um Problempunkte präziser identifizieren zu können, braucht es möglicherweis auch mehr Daten. Eine neue Generation von Werkzeugen ermöglicht Daten aus verschiedenen Quellen zu verknüpfen und Antworten auf hilfreiche Fragen zu finden:

  • An welchem Baustein arbeiten die meisten Entwickler gleichzeitig?
  • In welchem Baustein häufen sich Fehler?
  • Häufen sich Fehler in Bausteinen, an denen mehrere Entwickler arbeiten?
  • Gibt es einen Zusammenhang zwischen der Komplexität des Codes und der Zeit, die für die Behebung von Fehlern aufgewendet werden muss?
  • Wie lange dauert es, neue Features in einen Baustein einzuarbeiten?

 

Datenquellen
Abbildung 2 - Verknüpfung verschiedener Datenquellen

Um diese umfangreichen Daten besser auswerten zu können, kommen häufig zwei- oder dreidimensionale Diagramme zum Einsatz:

Teamscale Treemap
Abbildung 3- Treemap in Teamscale

Codecity 3D-Ansicht
Abbildung 4- 3D-Ansicht in Codecity

Abbildung 4 stellt Bausteine (Klassen, Dateien) als Türme dar. Die Größe der Grundfläche eines Turms entspricht der Größe eines Bausteins. Die Höhe steht für die Komplexität des Codes. Die Farbe gibt wieder, wie oft der Baustein im Zuge einer Fehlerbehebung bereits geändert werden musste.  Der rot markierte Baustein ist folglich ein idealer Kandidat, um mit dem Refactoring und Testautomatisieren zu beginnen.

Fazit

Problempunkte im Code lassen sich meist schon ganz gut mit statischer Codeanalyse aufspüren. Verknüpft man die Daten außerdem noch mit den Daten aus der Fehlerdatenbank, dem Versionsverwaltungssystem, Aufgabenmanagementwerkzeug, usw., lassen sich die Problempunkte noch besser identifizieren und eingrenzen. Die begrenzten Budgets zur Sanierung des Legacy Codes werden dadurch effizienter und effektiver eingesetzt.

Werkzeuge

Die nachfolgende Tabelle stellt den Funktionsumfang einiger Werkzeuge gegenüber:

Werkzeug Codecity Seerene Teamscale
URL marketplace.eclipse.org content/codecity seerene.com www.cqse.eu
Sprachen Java ABAP, ActionScript, Apex ASP.NET, Bash, C, C#, C++, Cobol-80, CobolSWT, CoffeeScript, Delphi, Freemarker, Gradle, Groovy, HanaSQL Script, Java Server Pages, Java, Java Properties, JavaScript, Kornshell, Objective-C, Oracle Siebel, Perl, PHP, PL/1, PL/SQL, PowerBuilder, Python, Scala, SQL, Swift, TypeScript, VisualAge Generator, Visual Basic, Xpp/X++ ABAP, Ada, C#, C/C++, Cobol, Delphi, Fortran, Groovy, Gosu, IEC 61131-3 ST, Java, JavaScript, Kotlin, Magik, Matlab, Open CL, OScript, PHP, PL/SQL, Python, Rust, Simulink/StateFlow, SQLScript, Swift, TypeScript, Visual Basic .NET, Xtend
Versionierung Git CA Endevor, Concurrent Versioning System, Git, IBM Rational ClearCase, IBM Rational TeamConcert, Mercurial, MKS Integrity/PTC Integrity, SAP Transport System, Subversion, Team Foundation Server Git, Gerrit, Subversion Team Foundation Server,  Artifactory
Code Checker jQAssistant Findbug, SonarQube Findbugs, FxCop,  StyleCop, Code Inspector (ABAP), PC-Lint, FlexeLint, Astrée RuleChecker, Goanna,  Clang Static Analyzer,  Pylint, SpCop, ESLint,  TSLint
Codeabdeckung Jacoco Cobertura, Jacoco BullseyeCoverage,  Cobertura, coverage.py,  CTC,  dotCover, JaCoCo, gcov, lcov, SAP SCOV, Visual Studio Test, Coverage,  XR.Baboon
Aufgabenmanagement - Jira Jira, Redmine, Team Foundation Server, IBM RTC/Jazz

 

 

Kontakt für Anfragen

Johannes Bergsmann Profilbild

Johannes Bergsmann

johannes.bergsmann@software-quality-lab.com

 +43 676 840072 420

Fachlicher Kontakt

Johannes Hochreiner Profilbild

Johannes Hochrainer