
Seit Anfang 2018 bin ich Teamleiter/Projektleiter/Führender Entwickler in meinem Team – nenn es, wie du willst, aber im Grunde bin ich vollständig für eines der Module und alle Entwickler, die daran arbeiten, verantwortlich. Diese Position eröffnet mir eine neue Perspektive auf den Entwicklungsprozess, da ich an einer größeren Anzahl von Projekten beteiligt bin und aktiver an Entscheidungsprozessen teilnehme. Kürzlich wurde mir dank dieser beiden Umstände bewusst, wie stark das Maß an Verständnis den Code und die Anwendung beeinflusst.
Der Gedanke, den ich ausdrücken möchte, lässt sich so zusammenfassen, dass die Qualität des Codes (und des Endprodukts) eng mit dem Zusammenhang steht, wie sehr die Menschen, die mit dem Entwerfen und Schreiben von Code beschäftigt sind, sich bewusst sind, was genau sie tun.
Vielleicht denken Sie jetzt: „Danke, Kapitän. Natürlich wäre es gut zu verstehen, was man überhaupt schreibt. Andernfalls könnte man genauso gut eine Gruppe von Affen engagieren, die wahllos auf die Tasten hauen.“ Und Sie haben vollkommen recht. Daher gehe ich davon aus: Sie sind sich bewusst, dass es notwendig ist, ein allgemeines Verständnis dafür zu haben, was man tut. Dies kann als nullter Grad des Verständnisses bezeichnet werden, und darüber werden wir nicht im Detail sprechen. Wir werden im Detail untersuchen, was genau verstanden werden muss und wie sich das auf die Entscheidungen auswirkt, die Sie jeden Tag treffen. Hätte ich diese Dinge im Voraus gekannt, hätte ich mir eine Menge wertvoller Zeit und fragwürdigen Codes gespart.
Obwohl Sie im Folgenden keinen einzigen Codezeile sehen werden, bin ich dennoch der Meinung, dass alles, was hier gesagt wurde, von großer Bedeutung für das Schreiben von qualitativ hochwertigem, ausdrucksstarkem Code ist.
Erste Stufe des Verständnisses: Warum funktioniert es nicht?
In der Regel erreichen Entwickler diese Stufe in den frühesten Phasen ihrer Karriere, manchmal sogar ohne jegliche Unterstützung von außen – zumindest sind das meine Beobachtungen. Stellen Sie sich vor, Sie haben einen Bug-Report erhalten: Eine bestimmte Funktion in der Anwendung funktioniert nicht, sie muss repariert werden. Wie gehen Sie vor?
Das Standardverfahren sieht folgendermaßen aus:
- Den Codeabschnitt finden, der das Problem verursacht (wie das gemacht wird, ist ein eigenes Thema, das ich in meinem Buch über veralteten Code behandle)
- Änderungen an diesem Abschnitt vornehmen
- Sich vergewissern, dass der Bug behoben ist und keine regressiven Fehler aufgetreten sind
Lass uns nun auf den zweiten Punkt konzentrieren – Änderungen im Code vorzunehmen. Es gibt zwei Ansätze für diesen Prozess. Der erste: Verstehen, was im aktuellen Code genau passiert, den Fehler identifizieren und ihn beheben. Der zweite: Auf gut Glück vorgehen – zum Beispiel +1 in eine Bedingung oder Schleife einfügen, sehen, ob die Funktion im vorgesehenen Szenario funktioniert, dann etwas anderes versuchen und so weiter bis in alle Ewigkeit.
Der erste Ansatz ist der richtige. Wie Steve McConnell in seinem Buch Code Complete erklärt (übrigens kann ich es sehr empfehlen), müssen wir jedes Mal, wenn wir etwas im Code ändern, in der Lage sein, mit Zuversicht vorherzusagen, wie sich das auf die Anwendung auswirkt. Ich zitiere aus dem Gedächtnis, aber wenn ein Bugfix nicht so funktioniert, wie Sie es erwartet haben, sollte Sie dies sehr beunruhigen. Sie sollten Ihren gesamten Handlungsplan in Frage stellen.
Zusammenfassend lässt sich sagen, dass man, um einen soliden Bugfix durchzuführen, der die Codequalität nicht beeinträchtigt, sowohl die gesamte Code-Struktur als auch die Quelle des spezifischen Problems verstehen muss.
Zweite Verständnisstufe: Warum funktioniert es?
Diese Stufe wird viel weniger intuitiv erfasst als die vorherige. Ich, als noch unerfahrener Entwickler, habe sie durch meinen Chef gelernt und habe sie später mehrfach selbst Neulingen erklärt.
Stellen wir uns diesmal vor, Sie erhalten gleichzeitig zwei Bugberichte: Im ersten geht es um das Szenario A, im zweiten um das Szenario B. In beiden Szenarien läuft etwas schief. Dementsprechend kümmern Sie sich zunächst um den ersten Bug. Nach den Prinzipien, die wir für die erste Verständnisstufe abgeleitet haben, tauchen Sie tief in den Code ein, der mit dem Problem zu tun hat, finden heraus, warum er das Verhalten der Anwendung im Szenario A verursacht, und nehmen sinnvolle Anpassungen vor, die genau das Ergebnis liefern, das Sie erwartet haben. Alles läuft hervorragend.
Dann gehen Sie zum Szenario B über. Sie wiederholen das Szenario, um den Fehler zu provozieren, aber – Überraschung! – jetzt funktioniert alles wie gewünscht. Um Ihre Vermutung zu bestätigen, setzen Sie die Änderungen, die Sie beim Arbeiten an Fehler A gemacht haben, zurück, und der Bug B tritt erneut auf. Ihr Bugfix hat beide Probleme gelöst. Glück gehabt!
Sie hatten damit überhaupt nicht gerechnet. Sie haben eine Möglichkeit gefunden, den Fehler im Szenario A zu beheben und haben keine Ahnung, warum dies auch für Szenario B funktioniert hat. In dieser Phase ist die Versuchung groß zu glauben, dass beide Aufgaben erfolgreich gelöst wurden. Das ist durchaus logisch: Es ging schließlich darum, Fehler zu beseitigen, oder? Aber die Arbeit ist noch nicht abgeschlossen: Sie müssen noch herausfinden, warum Ihre Maßnahmen den Fehler im Szenario B behoben haben. Warum? Denn möglicherweise basiert es auf falschen Prinzipien, und dann müssen Sie nach einem anderen Ausweg suchen. Hier sind ein paar Beispiele solcher Fälle:
- Da die Lösung nicht gezielt für den Fehler B unter Berücksichtigung aller Faktoren ausgearbeitet wurde, haben Sie möglicherweise unbeabsichtigt die Funktion C kaputt gemacht.
- Es ist nicht auszuschließen, dass sich irgendwo auch ein dritter Fehler versteckt hat, der mit derselben Funktion zusammenhängt, und Ihr Bugfix stellt die korrekte Funktionsweise des Systems im Szenario B darauf ab. Momentan sieht alles gut aus, aber eines Tages wird dieser dritte Fehler entdeckt und behoben. Dann wird im Szenario B wieder ein Fehler auftreten, und es ist gut, wenn es nur dort ist.
All das bringt Chaos in den Code, und eines Tages wird es Ihnen auf die Füße fallen — wahrscheinlich genau zu dem ungünstigsten Zeitpunkt. Sie müssen Ihre Kraft zusammennehmen, um sich die Zeit zu nehmen, zu verstehen, warum alles auf den ersten Blick funktioniert, aber es lohnt sich.
Dritte Verständnisstufe: Warum funktioniert es?
Meine kürzliche Erkenntnis steht genau mit dieser Stufe im Zusammenhang, und wahrscheinlich hätte sie mir die größten Vorteile verschafft, wenn ich früher zu diesem Gedanken gekommen wäre.
Um es klarer zu machen, lassen Sie uns ein Beispiel ansehen: Ihr Modul muss mit Funktion X kompatibel gemacht werden. Sie sind nicht besonders gut mit Funktion X vertraut, aber man hat Ihnen gesagt, dass Sie für die Kompatibilität das Framework F verwenden müssen. Andere Module, die sich mit X integrieren, arbeiten genau damit.
Ihr Code hatte von Anfang an keinerlei Berührungspunkte mit dem Framework F, daher wird es nicht ganz einfach sein, es zu implementieren. Dies wird ernsthafte Konsequenzen für einige Komponenten des Moduls nach sich ziehen. Dennoch stürzen Sie sich voll in die Entwicklung: Sie schreiben wochenlang Code, testen, bringen Pilotversionen heraus, erhalten Feedback, korrigieren Regressionen, stoßen auf unerwartete Komplikationen, halten die ursprünglich vereinbarten Fristen nicht ein, schreiben noch mehr Code, testen, erhalten Rückmeldungen, korrigieren Regressionen – all dies nur, um das Framework F zu implementieren.
Und irgendwann wird Ihnen plötzlich bewusst – oder vielleicht hören Sie es von jemandem – dass das Framework F Ihnen möglicherweise keine Kompatibilität mit der Funktion X bieten wird. Vielleicht waren all diese Zeit und Mühe völlig umsonst.
Ähnliches ist einmal während der Arbeit an einem Projekt passiert, für das ich verantwortlich war. Wie konnte das passieren? Weil ich nicht gut verstand, worin die Funktion X besteht und wie sie mit dem Framework F verbunden ist. Was hätte ich tun sollen? Eine Person, die die Entwicklungsaufgabe vergibt, auffordern, verständlich zu erklären, wie der vorgesehene Handlungsplan zu dem gewünschten Ergebnis führt, anstatt einfach das zu wiederholen, was für andere Module gemacht wurde, oder blind zu glauben, dass es für die Funktion X notwendig ist.
Die Erfahrung dieses Projekts hat mich gelehrt, den Entwicklungsprozess nicht zu beginnen, solange wir nicht klar verstehen, warum wir gebeten werden, bestimmte Maßnahmen zu ergreifen. Direkt abzulehnen. Wenn man eine Aufgabe erhält, ist der erste Impuls – sofort damit zu beginnen, um keine Zeit zu verlieren. Aber die Politik „wir stoppen das Projekt, bis wir in alle Einzelheiten eintauchen“ kann die vergeudete Zeit erheblich reduzieren.
Selbst wenn Druck auf Sie ausgeübt wird, um die Arbeit zu beginnen, während Sie nicht verstehen, warum dies gerechtfertigt ist – widerstehen Sie. Zuerst sollten Sie klären, mit welchem Ziel Ihnen diese Aufgabe gestellt wird, und entscheiden, ob dies der richtige Weg zum Ziel ist. Ich musste all dies auf die harte Tour lernen – ich hoffe, dass mein Beispiel denen, die dies lesen, das Leben erleichtert.
Vierte Ebene des Verständnisses: ???
In der Programmierung gibt es immer etwas zu lernen, und ich glaube, ich habe nur die oberflächlichen Schichten des Verständnisses angesprochen. Welche weiteren Verständnistiefen haben Sie im Laufe der Jahre bei der Arbeit mit Code entdeckt? Welche Entscheidungen haben sich positiv auf die Qualität des Codes und der Anwendung ausgewirkt? Welche Entscheidungen erwiesen sich als fehlerhaft und haben Ihnen eine wertvolle Lektion erteilt? Teilen Sie Ihre Erfahrungen in den Kommentaren.
Quelle: habr.com
