Subjektiv: Refactoring ist eine jugendliche „Krankheit“. Nach persönlichen Beobachtungen beginnt irgendwo nach 26 Jahren loszulassen. Wie in diesem alten Satz: "Wer in seiner Jugend kein Revolutionär war - er hat kein Herz, wer in seiner Reife nicht konservativ wird - er hat keinen Verstand." Bis ich endlich loslasse, werde ich daher versuchen, die Refactoring-Benutzerfälle und mögliche Ziele zu beschreiben, die damit erreicht werden können.
Inspiratoren
Ich begann nach dem nächsten Anzeigen der Pull-Anfrage für mehr als 150 Dateien zu schreiben, wobei neue Funktionen und das Refactoring der vorhandenen Dateien sehr wichtig waren. Refactoring war nicht nur kosmetisch, sondern auch logisch, was den größten Schmerz verursachte. In Ruby wurde beispielsweise amount == 0
fett durch amount.zero?
ohne zu berücksichtigen, dass diese Konstruktionen für den Fall der nil
nicht äquivalent sind. All dies wurde ungefähr wie folgt erklärt: "Aber laut Code wird der Standard so angenommen!" Auf die logische Frage "Was ist der Zweck, dem Code zum Standard zu folgen und was ist Ihr Ziel als Entwickler im Allgemeinen?" Der Mann schloss sich ein und wiederholte ein wenig schuldig "aber nach dem Code-Standard muss man so schreiben ..." und sah aus wie eine Blondine in einem Bekleidungsgeschäft, das das Verlangen nicht bewältigen konnte Refactor alles kaufen.
Definition
Das Thema ist sensibel, daher müssen Sie der Frage "Wer ist wer?" Besondere Aufmerksamkeit widmen. Laut Wiki ist Refactoring ein Prozess zur Änderung der internen Struktur eines Programms, der sich nicht auf sein externes Verhalten auswirkt und das Verständnis seiner Arbeit erleichtern soll.
Ich für meinen Teil möchte die Grenzen eingrenzen und Refactoring (im schlimmsten Sinne des Wortes) als alle Änderungen definieren, die nicht direkt mit dem zu lösenden Problem zusammenhängen und das externe Verhalten des Systems nicht ändern, sondern als Teil der ursprünglichen Aufgabe ausgeführt werden.
Das heißt, ich möchte nicht über die geplante Änderung der Codebasis sprechen, für die der Arbeitsumfang umrissen und spezifische Ziele festgelegt wurden, sondern über die spontanen Änderungen, die während der Entwicklung auftreten.
Produktwert
Jetzt fange ich von weitem an. Der Quellcode ist weder ein Ziel noch ein Wert. Natürlich kann es ästhetisch oder künstlerisch von Interesse sein, aber dies sind Ausnahmen. Im Allgemeinen ist Code ein Werkzeug zum Erstellen eines Softwareprodukts, das von jedem verwendet wird. Für den Anfang wäre es daher gut, die Werte im Produkt zu bestimmen.
Direkte Produktwerte
Hier ist alles einfach. Sie verwenden das Produkt, so dass direkte Werte das sind, was der Benutzer klar fühlt / sieht / fühlt. Nämlich:
- alle Arten von Produktfunktionen;
- Benutzerfreundlichkeit (UI / UX, Leistung, Fehlertoleranz usw.).
Der zweite Punkt kann zu Diskussionen führen. Schließlich glauben viele, dass dies nicht die Hauptsache ist. Wenn die Funktionalität gut ist, spielt es keine Rolle, in was sie eingewickelt ist. Gute Beispiele für Funktionen ohne vernünftige UI / UX: Redmine und SAP . Ich bin jedoch mit diesem Blick nicht einverstanden und denke näher an Genosse Alan Cooper und sein "Psychiatrisches Krankenhaus in den Händen von Patienten".
Indirekte Produktwerte
Dies sind Werte, die an sich keinen Einfluss auf den Benutzer haben. Sie können jedoch „schießen“ oder „akkumulieren“ und Auswirkungen (unterschiedlicher Schwere) auf das Produkt oder seine Funktionalität haben.
- Bugs. Ein Grenzfall von Werten. Sie sind sekundär, weil die Werte selbst nicht tragen, sondern von benachbarten Merkmalen stammen.
- Sauberkeit. Hier geht es um Lesbarkeit, Modularität, Minimierung eingehender Komponenten, Standardisierung und Vereinheitlichung von Schnittstellen usw.
- Dokumentation Hier geht es um Code und Erklärungen für Entwickler, nicht um Geschäftsbeschreibungen oder Benutzerkonten. Der Satz eines fröhlichen Bauern aus einem der Interviews zeigt dies gut: "Die Logik in der Datenbank ist wie ein Buch geschrieben."
- Skalierbarkeit / Sicherheit / Sicherheit. Der Benutzer sieht sie erst, wenn etwas Schlimmes passiert.
Entwicklerwerte
Eine sehr wichtige Kategorie, die viele übersehen, die aber immer das Ergebnis beeinflusst.
- Standardmäßig Code.
- Einrückung auf Feng Shui.
- Andere Transaktionen mit Gewissen. Immerhin wurde der Code geschrieben, so dass es ein Ergebnis für den Tag gibt, und daher gibt es einen Vorteil.
- Übereinstimmung des Codes mit der inneren Welt.
Aber seien wir ehrlich. Bei all dem geht es nicht um die Werte, die mit dem Produkt und dem Endbenutzer verbunden sind. Hier geht es um Psychologie und persönliche Kakerlaken.
Blick von der Seite des Geschäfts
Der Vollständigkeit halber müsste man dies alles von der Seite des Geschäfts betrachten und nicht von einem Softwareprodukt. In diesem Fall wird die Aufteilung in direkte und indirekte Werte ziemlich banal: direkt - bringen Sie offensichtlich Geld und Sie können eine eindeutige quantitative Bewertung abgeben; indirekt - sie bringen kein Geld und / oder es ist sehr schwer zu quantifizieren; Werte für den Entwickler bringen kein Geld in irgendeiner Form (vielleicht sogar wegnehmen).
Zum Beispiel.
- Eine neue Funktion mit OAuth-Schrauben erhöhte die Anzahl der Registrierungen um 10% und wir erhielten + 1k $.
- Wir haben das Abrechnungsmodul basierend auf dem Einzelverantwortungsmuster in mehrere unabhängige Teile unterteilt. Es scheint einfacher zu warten, aber es war nicht möglich zu messen.
- Wir haben die Codebasis an den Codestandard angepasst und ... nichts erhalten.
Es ist erwähnenswert, dass nach den obigen Schätzungen die Beine bei der geliebten Geschäftsbeschleunigung, der allgemeinen Eile und der Zurückhaltung wachsen, Zeit für etwas anderes als Funktionalität und möglicherweise einen Bugfix aufzuwenden. In der Tat können direkte Werte geschätzt und "verkauft" werden, und indirekte sind sehr schwierig oder unmöglich. Und es stellt sich heraus, dass indirekte Werte entweder aufgrund eines technischen Hintergrunds realisiert oder auf einer intuitiven Ebene verstanden oder als "wertlos" verworfen werden.
Fairerweise müssen wir hier an das Konzept des Enablers erinnern, das den Weg für die Implementierung der gewünschten Funktion "ebnet", aber für den Benutzer keinen offensichtlichen Gewinn bringt. Aber das ist eine andere Geschichte.
Und was ist mit Refactoring?
Zumindest trotz der Tatsache, dass er nur die indirekten Werte des Produkts beeinflussen kann. Daher wird sich der Benutzer durch ein Refactoring nicht besser fühlen.
Es ist auch wichtig, sich an die Entropie zu erinnern. Refactoring minimiert es immer. Um die Entropie zu reduzieren, benötigen Sie im Idealfall ein Team von Architekten, die die Entropie in der Entwurfsphase minimieren. Um ein Stück aus dem Mythical Man-Month zu zitieren:
Die Systemprogrammierung ist ein Prozess, der die Entropie reduziert und daher eine Metastabilität aufweist. Die Programmwartung ist ein Prozess, der die Entropie erhöht, und selbst die geschickteste Wartung verzögert nur, dass das System in eine hoffnungslose Veralterung gerät.
Wenn wir das Refactoring als Teil des Programmwartungsprozesses betrachten, gilt: Je weniger Refactor, desto länger lebt der Code ohne Umschreiben.
Welche Ziele kann Refactoring haben?
Ich möchte Sie daran erinnern, dass es sich um eine spontane Änderung während der Implementierung von Funktionen handelt und nicht um die geplanten Änderungen. In diesem Fall liegt die Definition des Ziels vollständig beim Entwickler. Er muss sich die Hauptfrage „Warum?“ Stellen, sie beantworten und sich danach dem beabsichtigten Ziel nähern.
Für die Entropie!
Es ist schwer, es selbst zu tun. Und die Überprüfung durchzuziehen ist im Allgemeinen unrealistisch. Das Ziel ist sicherlich gut: den Brückenkopf für neue Errungenschaften freizumachen sowie die während der Produktunterstützung angesammelten Toxine und Toxine zu entfernen. Es ist jedoch keine leichte Aufgabe, ein paar Module von Grund auf neu zu schaufeln, ohne dabei etwas zu verlieren. Es sollte in Zusammenarbeit mit Geschäftsanalysten und Architekten gelöst werden, falls vorhanden. So wenige Menschen riskieren dies auf freiwilliger Basis.
Für die Dokumentation!
Es ist schon einfacher. Benennen Sie Variablen / Funktionen nach dem Prinzip „Was ist auf der Box, dann in der Box?“ Umbenennen, vereinfachen Sie das Design aufgrund der Funktionen der Sprache und der Bibliotheken, fügen Sie Kommentare an nicht offensichtlichen Stellen hinzu usw. Dies kann alleine und mit dem richtigen Ansatz sowohl für sich selbst als auch für benachbarte Kollegen gut gemacht werden.
Für Geschwindigkeit!
Um ehrlich zu sein, sollte eine solche Arbeit als separate Aufgabe hervorgehoben werden. Da entweder die aktuellen Funktionen des Systems für Sie ausreichen und Sie nichts tun müssen oder Sie genau wissen, was und wie viel Sie beschleunigen müssen.
Alles fällt in diese Kategorie: von der harmlosen Korrektur von N + 1 bis zur ernsthaften Beschleunigung aufgrund von Änderungen in den Betriebsalgorithmen. Das ganze Problem ist, dass die „Parität“ der Fehler immer schnell ist. Hier ein Beispiel: In einer Transaktion werden Daten in der Datenbank gepusht und in derselben Transaktion wird eine Aufgabe in Sidekiq festgelegt. Die Warteschlange von Sidekiq in Redis und die Transaktion gelten nicht für diese. Wenn die Geschwindigkeit der Warteschlange zunimmt, wird die Aufgabe manchmal ausgeführt, bevor die Daten festgeschrieben werden. Sie können sich die Konsequenzen und den Debug-Prozess selbst vorstellen.
Zum Refactoring!
Stellen Sie sich vor, Sie haben den Reinigungsservice für Wohnungen genutzt. Sie kamen, begannen zu putzen, aber auf dem Weg dorthin bewegten sie alle Möbel in der Wohnung und umrissen die Vorhänge vom Wohnzimmer zur Badewanne mit dem Argument: „Unter solchen Bedingungen war die Putzfrau angenehmer, ihre Arbeit zu erledigen.“ Bild aus "WTF ?!" Sie können es sich vorstellen.
Ich hoffe, Sie verstehen, dass Sie nicht an sich selbst denken müssen, sondern daran, für wen Sie es tun.
Demut und Akzeptanz
Zusammenfassend ist es notwendig, vor dem Refactoring ein „Handbuch“ zu geben, was zu tun ist. Dies ist zwar keine TODO-Liste, sondern eine Liste von Fakten, mit denen Sie sich abfinden und entweder akzeptieren oder keine Maßnahmen ergreifen müssen.
- Ich erhöhe die Anzahl der Fehler im Projekt und kann ein Tamburin dafür bekommen.
- Ich werde Eigentümer des überarbeiteten Codes und alle Fragen dazu werden zunächst an mich gesendet.
- Durch meine Handlungen produziere ich für den Endbenutzer nichts Wertvolles.
Eine kleine Erklärung.
- Jede Änderung am Code hat eine Chance ungleich Null, einen Fehler zu generieren. Und da diese Aktion nicht mit der ultimativen Funktionalität verbunden ist, erzeugen Sie einfach Fehler, ohne Kernwerte zu generieren. Es ist gut, sich dessen bewusst zu sein und sich nicht als Schläuche auszugeben, wenn sie mit Fragen zu Ihnen kommen.
- Ausreden wie "vorheriges Anotieren" und dergleichen sind sehr miserabel, weil es im selben Github / Gitlab keine solche Funktion gibt. Außerdem hat der vorherige Autor bestätigt, dass alles in seiner Konfiguration funktioniert, und er trägt keine Verantwortung für Ihre Änderungen und verliert einen Teil des Bildes von dem, was passiert. Genauer gesagt, Sie nehmen es ihm zusammen mit der Verantwortung weg.
- Dem Benutzer ist das Refactoring wirklich egal, er interessiert sich für Stabilität und Funktionalität, und beim Refactoring geht es nicht darum.
Und noch einmal: Wenn Sie mit mindestens einem der Punkte nicht einverstanden sind, beginnen Sie nicht mit dem Refactoring. Lesen Sie besser Habr, Lurk, trinken Sie Tee oder sprengen Sie im schlimmsten Fall das nächste Feature vom Armaturenbrett.
Das Ende
Nicht streng beurteilen. Wenn möglich, konstruktiv konstruieren. Und denken Sie immer über den Zweck Ihrer Handlungen nach. Vielen Dank.