https://d226lax1qjow5r.cloudfront.net/blog/blogposts/improve-your-software-project-part-one-understanding-a-codebase/making-projects-better_part-one.png

Verbessern Sie Ihr Softwareprojekt - Teil eins: Verstehen einer Codebasis

Zuletzt aktualisiert am November 15, 2022

Lesedauer: 8 Minuten

Haben Sie schon einmal eine Codebasis übernommen und festgestellt, dass Sie mit der Art, wie der Code geschrieben oder organisiert ist, nicht zufrieden sind? Das kommt häufig vor, kann aber eine Menge Kopfschmerzen verursachen. Technische Schulden können zu einem Schneeballsystem werden, das es exponentiell schwieriger macht, den Code zu verstehen und neue Funktionen hinzuzufügen.

In dieser dreiteiligen Serie gehe ich auf einige der wichtigsten Dinge ein, die Sie tun sollten, um mit Ihrem glänzenden (alten) Projekt zufriedener zu werden. Anhand einiger konkreter Beispiele werde ich erläutern, wie ich das Open-Source Vonage Python SDKeine Bibliothek, die HTTP-Aufrufe zu Vonage-APIs macht, aber die Prinzipien gelten für jede Art von Softwareprojekt.

Die Beispiele in diesem Beitrag werden in Python geschrieben, aber diese Prinzipien gelten für Projekte in jeder Sprache. Außerdem gibt es eine praktische Checkliste, die Sie befolgen können wenn Sie speziell versuchen, ein Python-Projekt zu reparieren.

Die Serie, in Abschnitten

  1. Teil Eins: Verstehen einer Codebasis (dieser Artikel)

  2. Zweiter Teil: Änderungen vornehmen

  3. Dritter Teil: Erweiterungen der nächsten Stufe

Worum geht es in dieser Reihe?

In dieser Serie werden wir über Folgendes sprechen:

  1. Sich mit dem Code vertraut machen

  2. Selbstvertrauen in die Durchführung von Änderungen und die Behebung technischer Mängel

  3. Aufbau von Vertrauen bei Ihrem Chef, Ihrem Team und Ihren Kunden/Gemeinschaften

  4. Erweiterungen vornehmen

  5. Was ist zu tun, wenn es Zeit ist, das Projekt zu übergeben?

Am Ende jedes Artikels werden Sie einige Strategien haben, um selbst mit dieser Situation umzugehen, und Sie werden sich befähigt fühlen, genau das zu tun!

Fahren wir ohne Umschweife mit dem ersten Teil fort...

Erster Teil: Das Projekt verstehen

Lesestoff!

Als Erstes müssen Sie versuchen zu verstehen, was der von Ihnen geerbte Code tut und wie er organisiert ist.

Sprechen Sie zunächst mit jemandem, der sich mit dem Projekt auskennt, und lesen Sie alle verfügbaren Unterlagen. In meinem Fall gab es eine Readme-Datei im Repo, die mir als Ausgangspunkt diente. Sie bot einen guten Überblick über den Stand des Codes, als er zuletzt aktualisiert wurde.

Image of readme

Es gab auch eine Produktdokumentation, die mir half zu verstehen, was der Code derzeit tun sollte, da sie die APIs beschrieb, die ich aufrufen musste, und deren aktuelles Verhalten.

Image of main docs page

Baue Sachen!

Sobald Sie eine Vorstellung davon haben, was der Code tut, besteht der nächste Schritt darin, ihn zu erkunden, indem Sie eine Art "Hello, World"-Projekt erstellen - ein einfaches Projekt, das den Code verwendet und etwas Kleines, aber Nützliches tut. Da mein Projekt APIs aufruft, habe ich ein sehr einfaches Stück Code geschrieben, das mir eine SMS sendet.

import vonage


client = vonage.Client(key=MY_KEY, secret=MY_SECRET)

client.sms.send_message({
    "from": "Max",
    "to": MY_NUMBER,
    "text": "Hello, world!",
})

Es hat geklappt!

Screenshot of my phone with a new message

Spielen Sie mit Ihrer Codebasis und erstellen Sie Ihr eigenes "Hello, World".

Verstehen, wie der Code strukturiert ist

Es ist wichtig zu verstehen, wie der Code des Projekts organisiert ist, damit Sie sich leichter vorstellen können, was passiert, wenn Ihr "Hello, World" läuft. Dies ist auch eine gute Möglichkeit, Ihre Fähigkeiten im architektonischen Denken zu trainieren, da Sie ein mentales Modell der Funktionsweise des Codes entwickeln müssen. Diese Denkweise wird Ihnen dabei helfen, das Projekt in verschiedene Teile aufzuteilen, die leichter zu verstehen sind, was auch später hilfreich ist, wenn Sie die Code-Kopplung und andere Nebeneffekte reduzieren wollen.

Im Fall unseres SDK war der Code in sechs separate Dateien aufgeteilt (Python ist eine sehr kompakte Sprache, die entsprechende Java-Codebasis ist etwa 10 Mal so groß!), die wie folgt aussehen:

  • Eine Datei zur Initialisierung des Projekts und zum Umgang mit Importen,

  • Eine Datei, die interne Methoden enthält,

  • eine Datei, die benutzerdefinierte Fehlerklassen enthält, und

  • Drei Dateien mit jeweils einer Klasse, die sich auf eine der APIs von Vonage bezieht

Image showing the different files with the descriptions above applied to them

Die Alarmglocken begannen zu läuten, als ich feststellte, dass es 3 Dateien gab, die nach Vonage-APIs benannt waren, aber in der README stand, dass 12 verschiedene APIs unterstützt wurden.

Ich stellte fest, dass sich der meiste Code in einer Datei (__init__.py) befand, die normalerweise nur für Importe verwendet wird, und zwar in einer großen Klasse, die sich mit allem befasste. Da dies für die Struktur nicht gerade hilfreich war, beschloss ich, mir die Struktur der Tests anzusehen, um mehr Informationen über die Organisation des Codes zu erhalten.

Die Tests waren sinnvollerweise in Module gruppiert, was mir half, die verschiedenen Komponenten zu verstehen. Ich würde empfehlen, zu versuchen, die Struktur sowohl Ihres Codes als auch Ihrer Tests zu verstehen, da beide aufschlussreich sein können.

Screenshot of the tests folder

Richten Sie sich für die Entwicklung ein und führen Sie die Tests durch!

Nun ist es an der Zeit, die Projektabhängigkeiten zu installieren und die Tests durchzuführen. Wenn sie mit der neuesten Version Ihrer Sprache und Abhängigkeiten erfolgreich sind, ist das eine gute Nachricht! Bei mir war das nicht der Fall, also habe ich mit genau den genannten Versionen der Abhängigkeiten begonnen und die Abhängigkeiten schrittweise aktualisiert, um herauszufinden, welche nicht mit der neuesten Version meiner Programmiersprache harmonieren.

In dieser Situation sollten Sie die Abhängigkeiten schrittweise aktualisieren und die Probleme selbst erkennen. Bei einer Ihrer Abhängigkeiten gab es seit der letzten Verwendung der Codebasis wahrscheinlich ein Release mit einer bahnbrechenden Änderung. (In meinem Fall änderte eine Abhängigkeit die Art und Weise, wie sie Daten zwischen den Versionen zurückgab, so dass ich einige Tests neu schreiben musste, um die Daten richtig zu verarbeiten).

Hilfsmittel, die Ihnen helfen können

In diesem Abschnitt werden einige Möglichkeiten aufgezeigt, wie Sie Tools einsetzen können, um ein Projekt in Gang zu bringen. Der Einsatz von Code-Analyse-Tools kann äußerst nützlich sein, da ihre Verwendung automatisiert werden kann, was bedeutet, dass Sie die Tools so oft wie gewünscht ausführen und Ihre Fortschritte bei der Verbesserung der Codebasis verfolgen können.

Die Werkzeuge sind auch für die Arbeitsplanung von großem Nutzen, da sie Aufschluss darüber geben, wo die technischen Schulden und Code-Hotspots liegen und wie Sie Ihre Zeit priorisieren sollten!

Analyse-Tools

Die statische Analyse ist ein Verfahren zur automatischen Analyse von Quellcode, ohne dass dieser tatsächlich ausgeführt werden muss. Sie kann einen Einblick in die Struktur einer Codebasis geben, Duplikationen und andere Refactoring-Ziele aufzeigen und Sie vor möglichen Schwachstellen warnen. Für die meisten Sprachen gibt es kostenlose Tools im Internet, und viele kostenpflichtige Anbieter haben eine kostenlose Ebene für nicht-kommerzielle oder Open-Source-Projekte, z. B. sonarcloud.

Bei der Verhaltensanalyse geht es darum, anhand des Commit-Verlaufs etwas über ein Projekt zu erfahren. So können Sie herausfinden, wer wann an dem Projekt gearbeitet hat, was geändert wurde, welche Komponenten häufig gemeinsam geändert werden und vieles mehr. Dies ist eine sehr nützliche Methode für große Projekte mit vielen Committern. CodeScene hat eine kostenlose Ebene für Open-Source-Projekte und funktioniert gut.

Testabdeckung

Die Testabdeckung (der Prozentsatz der von Ihren Tests abgedeckten Code-Anweisungen) ist nützlich, um herauszufinden, was genau Ihre Unit-Tests testen. Sie kann auch Bereiche einer Codebasis hervorheben, die nicht getestet werden. Werkzeuge sind für die meisten Sprachen verfügbar; für Python empfehle ich Abdeckung.

Image of test coverage outputs

Mutation score

Die Testabdeckung gibt Aufschluss darüber, wie viel von Ihrem Code durch Tests abgedeckt wird, aber sie sagt nichts darüber aus, wie gut Ihre Tests das Verhalten Ihres Codes tatsächlich testen! Mutationstests geben mehr Aufschluss darüber, inwieweit Sie darauf vertrauen können, dass Ihre Tests ihre Aufgabe erfüllen und sicherstellen, dass Ihr Code wie vorgesehen funktioniert.

Dabei werden Anweisungen in Ihrem Code leicht verändert, z. B. eine Zeichenkette geändert, ein Plus in ein Minus verwandelt usw., um viele "mutante" Versionen Ihres Codes zu erzeugen. Ihre Testsuite wird dann gegen jede dieser mutierten Versionen Ihres Codes ausgeführt. Da sich die Dinge geändert haben, erwarten wir, dass die Tests fehlschlagen - wir sagen, wir haben die Mutante erwischt. Wenn Ihre Tests jedoch trotz dieser Änderungen erfolgreich sind, ist die Mutante entkommen und diese kleinen Änderungen könnten es in die Produktion geschafft haben! Daher wird die Mutationswert (Verhältnis der abgefangenen Mutanten zur Gesamtzahl der erzeugten Mutanten) gibt uns also Aufschluss darüber, wie viel Vertrauen wir in unsere Tests haben sollten.

Davon gibt es Versionen in vielen Sprachen, darunter Stryker das Unterstützung für Javascript, Node.js und C# bietet. In Python empfehle ich mutmutzu probieren, das einfach und effektiv ist.

Image of mutation score output

Verstehen Sie den Aufrufstapel, indem Sie ein Profil Ihrer Probe erstellen!

Ich würde empfehlen, zu versuchen, den Stapel von Aufrufen zu verstehen, der passiert, wenn Ihr "Hello, World" läuft. In den meisten Sprachen gibt es dafür Werkzeuge.

Für Python empfehle ich ein Tool namens Snakeviz um Ihren Aufrufstapel visuell darzustellen. Fügen Sie Ihren "Hello, World"-Code in eine Funktion ein und erstellen Sie ein Profil, etwa so:

with cProfile.Profile() as pr:
    send_sms() # This function is where the Hello, World code lives
stats = pstats.Stats(pr)
stats.dump_stats(filename='send_sms.prof')

Das erzeugt eine Datei namens send_sms.prof. Wenn Sie diese in der Befehlszeile mit Snakeviz ausführen...

python -m pip install snakeviz snakeviz send_sms.prof

...wird ein interaktives Eiszapfen-Diagramm erstellt, das Ihnen alle Funktionen zeigt, die Ihre Funktion aufruft, alle Funktionen sie aufruft, und so weiter. Dies kann nützlich sein, um den Weg des Computers durch den Code zu verfolgen, und kann die Funktionsweise beleuchten.

Image of an icicle plot of my profiled function

Was kommt als Nächstes?

Wenn Sie die Vorschläge in diesem Artikel befolgen, sind Sie in einer guten Position, um Vertrauen aufzubauen, technische Schulden zu beseitigen und Änderungen an Ihrer Codebasis vorzunehmen. Schauen Sie bald wieder vorbei für Teil 2, in dem wir all dies im Detail besprechen werden.

In der Zwischenzeit können Sie sich mit uns auf unserem Vonage Community Slack oder senden Sie uns eine Nachricht auf Twitter.

Teilen Sie:

https://a.storyblok.com/f/270183/400x400/92109caf6a/max-kahan.png
Max KahanVonage Ehemaliges Teammitglied

Max ist ein Python-Entwickler und Software-Ingenieur, der sich für Kommunikations-APIs, maschinelles Lernen, Entwicklererfahrung und Tanz interessiert! Er hat Physik studiert, aber jetzt arbeitet er an Open-Source-Projekten und stellt Dinge her, die das Leben von Entwicklern verbessern.