Wie kann ein großes und komplexes Softwareprodukt über die Jahre gewartet werden?


156

Ich arbeite seit vielen Jahren als Softwareentwickler. Ich habe die Erfahrung gemacht, dass Projekte komplexer und nicht mehr aufrechtzuerhalten sind, je mehr Entwickler an der Entwicklung des Produkts beteiligt sind.

Es scheint, dass Software in einem bestimmten Entwicklungsstadium die Tendenz hat, "hackiger" und "hackiger" zu werden, insbesondere wenn keines der Teammitglieder, die die Architektur definiert haben, mehr im Unternehmen arbeitet.

Ich finde es frustrierend, dass es einem Entwickler, der etwas ändern muss, schwer fällt, den Überblick über die Architektur zu behalten. Daher besteht die Tendenz, Probleme zu beheben oder Änderungen auf eine Weise vorzunehmen, die der ursprünglichen Architektur entgegenwirkt. Das Ergebnis ist Code, der immer komplexer und noch schwerer zu verstehen ist.

Gibt es hilfreiche Tipps, wie Sie den Quellcode über die Jahre hinweg wirklich pflegbar halten können?


9
Sehr empfehlenswerte Bücher: "Software Project Survival Guide" von Steve McConnell, "Rapid Development" von Steve McConnell, "Refactoring" von Martin Fowler
Imran Omar Bukhsh

15
... und 'Clean Code' von Onkel Bob;) (Robert C. Martin)
Gandalf

34
Ist das nicht genau diese Frage, aus der mehrere Jahrzehnte lang intensive Lektüre und ganze Kurse an Universitäten hervorgegangen sind?
Detly

17
@ Eric Yin - Ich bin nicht einverstanden mit den Kommentaren. Für mich sind sie ein Code-Geruch und auf längere Sicht schaden Projekte eher als sie nützen, weil sie unweigerlich veralten und irreführend werden.
JohnFx

8
@Eric Yin: Strebe nach selbstdokumentierendem Code. Verwenden Sie Absichtserklärungen nur, wenn sie das Verständnis verbessern.
Mitch Wheat

Antworten:


138

Die einzige wirkliche Lösung, um Code Rot zu vermeiden, besteht darin, gut zu codieren!

Wie man gut codiert, ist eine andere Frage. Es ist schwer genug, auch wenn Sie ein ausgezeichneter Programmierer sind, der alleine arbeitet. In einem heterogenen Team wird es noch viel schwieriger. In ausgelagerten (Unter-) Projekten ... beten Sie einfach.

Die üblichen guten Praktiken können helfen:

  1. Halte es einfach.
  2. Halte es einfach. Dies gilt insbesondere für die Architektur, das "große Ganze". Wenn es Entwicklern schwer fällt, den Überblick zu behalten , werden sie dagegen programmieren. Machen Sie die Architektur so einfach, dass alle Entwickler darauf zugreifen können. Wenn die Architektur nicht einfach sein muss, müssen die Entwickler geschult werden, um diese Architektur zu verstehen. Wenn sie es nicht verinnerlichen, sollten sie es nicht einprogrammieren.
  3. Streben Sie eine niedrige Kopplung und eine hohe Kohäsion an . Stellen Sie sicher, dass jeder im Team diese Idee versteht. In einem Projekt, das aus lose gekoppelten, zusammenhängenden Teilen besteht, können Sie dieses Teil einfach entfernen und neu schreiben, wenn einige der Teile nicht mehr zu warten sind. Es ist schwieriger oder fast unmöglich, wenn die Kupplung fest sitzt.
  4. Seien Sie konsequent. Welche Standards zu befolgen sind, spielt keine Rolle, aber bitte befolgen Sie einige Standards. In einem Team sollte natürlich jeder den gleichen Standards folgen. Auf der anderen Seite ist es leicht, sich zu sehr an Standards zu binden und den Rest zu vergessen: Bitte haben Sie Verständnis dafür, dass Standards zwar nützlich sind, aber nur einen kleinen Teil der Erstellung von gutem Code ausmachen. Mach keine große Zahl daraus.
  5. Codeüberprüfungen können hilfreich sein, um ein Team zur beständigen Arbeit zu bewegen.
  6. Stellen Sie sicher, dass alle Tools - IDEs, Compiler, Versionskontrolle, Build-Systeme, Dokumentationsgeneratoren, Bibliotheken, Computer , Lehrstühle , allgemeine Umgebung usw. usw. - gut gewartet sind, damit Entwickler ihre Zeit nicht mit sekundären Problemen wie z Im Kampf gegen Dateiversionskonflikte, Windows-Updates, Lärm und andere banale, aber irritierende Dinge. Das wiederholte Verschwenden von viel Zeit mit solchen uninteressanten Dingen senkt die Moral, was zumindest die Codequalität nicht verbessert. In einem großen Team könnte es einen oder mehrere Mitarbeiter geben, deren Hauptaufgabe darin besteht, die Entwicklerwerkzeuge zu warten.
  7. Überlegen Sie sich bei technologischen Entscheidungen, was erforderlich ist, um die Technologie zu wechseln. Welche Entscheidungen sind irreversibel und welche nicht. Bewerten Sie die irreversiblen Entscheidungen besonders sorgfältig. Wenn Sie sich beispielsweise dazu entschließen, das Projekt in Java zu schreiben , ist dies eine ziemlich irreversible Entscheidung. Wenn Sie sich dafür entscheiden, ein selbstgekochtes Binärformat für Datendateien zu verwenden, ist dies ebenfalls eine ziemlich irreversible Entscheidung (sobald der Code nicht mehr verfügbar ist und Sie dieses Format weiterhin unterstützen müssen). Die Farben der Benutzeroberfläche können jedoch problemlos angepasst werden. Funktionen, die ursprünglich ausgelassen wurden, können später hinzugefügt werden.

8
Das sind großartige Punkte. Ich muss zugeben, dass ich mit "einfach halten" zu kämpfen habe. Es scheint verschiedene Dinge für verschiedene Menschen in verschiedenen Kontexten zu bedeuten, was "einfach" ziemlich komplex macht (aber dann neige ich natürlich dazu, Dinge zu komplizieren).
Kramii

3
Ich stimme vollkommen mit Ihren Punkten überein, besonders mit "KIS". Aber ich sehe eine Tendenz, dass immer mehr (jüngere?) Entwickler ziemlich komplexe Strukturen verwenden, um selbst die einfachsten Zusammenhänge zu beschreiben.
Chrmue


8
Umm und "8. Mach es einfach".
Dawood ibn Kareem

7
# 6 verdient eine +10.
Jim G.

55

Unit-Tests sind dein Freund . Ihre Implementierung erzwingt eine geringe Kopplung. Dies bedeutet auch, dass die "hackigen" Teile des Programms leicht identifiziert und überarbeitet werden können. Dies bedeutet auch, dass Änderungen schnell getestet werden können, um sicherzustellen, dass vorhandene Funktionen nicht beeinträchtigt werden. Dies sollte Ihre Entwickler ermutigen, vorhandene Methoden zu ändern, anstatt Code zu duplizieren, aus Angst, Dinge zu beschädigen.

Unit-Tests dienen auch als zusätzliche Dokumentation für Ihren Code und beschreiben, was die einzelnen Teile tun sollen. Mit umfangreichen Komponententests sollten Ihre Programmierer nicht die gesamte Architektur Ihres Programms kennen müssen, um Änderungen vorzunehmen und aufregende Klassen / Methoden zu verwenden.

Als netter Nebeneffekt reduzieren Unit-Tests hoffentlich auch Ihre Fehleranzahl.


3
Sehr wichtiger Punkt. Ich habe ein Altsystem übernommen, viele Klassen, viele Codezeilen, keine Dokumentation, keine Komponententests. Nach sorgfältiger Erstellung von Komponententests für alle Codefixes und -verbesserungen hat sich das Systemdesign zu einem saubereren und besser wartbaren Zustand entwickelt. Und wir haben den "Mut", wichtige Kernbereiche neu zu schreiben (abgedeckt durch Unit-Tests).
Sam Goldberg

40

Alle hier erwähnen schnell Code Rot , und ich verstehe und stimme dem zu, aber es fehlt immer noch das Gesamtbild und das größere Problem, das hier zur Sprache kommt. Code rot passiert nicht einfach so. Weiterhin werden Unit-Tests genannt, die gut sind, aber das Problem nicht wirklich ansprechen. Man kann eine gute Unit-Test-Abdeckung und relativ fehlerfreien Code haben, jedoch immer noch verrotteten Code und Design.

Sie haben erwähnt, dass der Entwickler, der an einem Projekt arbeitet, Schwierigkeiten hat, ein Feature zu implementieren, das Gesamtbild der Architektur übersieht und somit einen Hack in das System implementiert. Wo ist die technische Führung, um das Design durchzusetzen und zu beeinflussen? Wo sind die Codeüberprüfungen in diesem Prozess?

Sie leiden nicht wirklich unter Code Rot, aber Sie leiden unter Team Rot . Tatsache ist, dass es keine Rolle spielen sollte, ob die ursprünglichen Entwickler der Software nicht mehr im Team sind. Wenn der technische Leiter des vorhandenen Teams das zugrunde liegende Design vollständig und wirklich versteht und die Rolle des technischen Leiters gut beherrscht, ist dies kein Problem.


Sehr guter Punkt, Sie haben ins Schwarze getroffen! Traurig zu sagen, aber genau das passiert hier. Und es scheint unmöglich zu sein, Dinge ohne den technischen
Leiter

4
@chrmue So wie es läuft, denke ich, aber ich werde es leid. In vielerlei Hinsicht wünschte ich mir, ich wäre wieder ein Junior-Entwickler, als mir nicht so bewusst war, wie falsch alles um mich herum zu sein scheint. Es sieht so aus, als würde ich meine berufliche Krise frühzeitig überwinden. Aber ich streife ... bin froh zu helfen.
maple_shaft

1
@Murph Warum sollten Sie während der Wartungsphase keinen allwissenden Teamleiter haben? Jeder Chef, den ich jemals von einem Teamleiter erwartet hatte, auch wenn ich ein Teamleiter war, erwartete ich nichts weniger von mir.
maple_shaft

1
@maple_shaft weil a) ich nicht davon ausgehen , dass es ein Team zu führen ist gewidmet zu dieser einem Projekt und das ist mehr oder weniger die erste Anforderung und b) ich glaube , Sie brauchen das Design zu verstehen und die Implemenation (alles) und das ist hart. Einerseits argumentieren wir alle, dass wir nicht eine einzige Schrift allen Wissens in unseren Projekten haben sollten, und doch sagen wir hier, dass wir eine haben müssen? Das passt nicht zusammen?
Murph

2
@maple_shaft wahrscheinlich bin ich ein mürrischer alter Programmierer (-: Aber es gibt ein Problem darin, dass es oft "Implementierungsstil" ist, der tief in einer existierenden Codebasis befolgt werden muss - und der sowohl dem Codierer als auch dem Lead fremd sein kann (für viele) aus realen Gründen)
Murph

18

Wir können verschiedene Dinge tun:

Geben Sie einer Person die Gesamtverantwortung für die Architektur. Stellen Sie bei der Auswahl dieser Person sicher, dass sie über die Vision und die Fähigkeit verfügt, eine Architektur zu entwickeln und zu warten, und dass sie den Einfluss und die Autorität besitzt, anderen Entwicklern zu helfen, der Architektur zu folgen. Diese Person sollte ein erfahrener Entwickler sein, dem das Management vertraut und der von seinen Kollegen respektiert wird.

Erstellen Sie eine Kultur, in der alle Entwickler Eigentümer der Architektur sind. Alle Entwickler müssen in den Prozess der Entwicklung und Aufrechterhaltung der architektonischen Integrität einbezogen werden.

Entwickeln Sie eine Umgebung, in der Architekturentscheidungen einfach kommuniziert werden können. Ermutigen Sie die Menschen, über Design und Architektur zu sprechen - nicht nur im Kontext des aktuellen Projekts, sondern auch allgemein.

Die besten Codierungsmethoden erleichtern das Erkennen der Architektur im Code. Nehmen Sie sich Zeit, um den Code zu überarbeiten, zu kommentieren, Komponententests zu entwickeln usw. Dinge wie Namenskonventionen und saubere Codierungsmethoden können bei der Kommunikation der Architektur sehr hilfreich sein Nehmen Sie sich Zeit, um Ihre eigenen Standards zu entwickeln und zu befolgen.

Stellen Sie sicher, dass alle erforderlichen Unterlagen klar, präzise, ​​aktuell und zugänglich sind. Machen Sie sowohl High-Level- als auch Low-Level-Architekturdiagramme öffentlich (Anheften an die Wand kann hilfreich sein) und lassen Sie sie öffentlich warten.

Schließlich muss ich (als natürlicher Perfektionist) erkennen, dass architektonische Integrität ein würdiger Anspruch ist, aber dass es wichtigere Dinge geben kann - wie die Bildung eines Teams, das gut zusammenarbeiten und ein funktionierendes Produkt liefern kann.


1
+1, insbesondere für "Aufbau eines Teams, das gut zusammenarbeiten und ein funktionierendes Produkt liefern kann."
Deworde

1
Es ist eine gute Idee, eine Person als Hauptverantwortlichen für die Architektur zu haben. Sie haben jedoch einen "Team-Geruch", wenn diese Verantwortung häufig verwendet wird: Das Team sollte natürlich zu gemeinsamen Schlussfolgerungen kommen, anstatt sich auf eine Person zu verlassen, um die Antworten zu geben. Warum? Das gesamte Wissen über das Projekt wird immer geteilt. Wenn Sie es an eine Person binden, treten am Ende größere Probleme auf: Nur seine Sichtweise ist zufrieden und schneidet dem Rest des Teams die Flügel. Stellen Sie stattdessen die besten Leute ein und lassen Sie sie gemeinsam arbeiten.
Kasper

1
@casper: Genau. Du drückst das, was ich mir vorgestellt hatte, besser aus als ich.
Kramii

18

Ich gehe dieses Problem folgendermaßen an:

In meiner Erklärung werden Begriffe aus Microsoft / .NET verwendet , sie gelten jedoch für jede Plattform / Toolbox:

  1. Verwenden Sie Standards für die Benennung, Codierung, das Einchecken, den Fehlerfluss und den Prozessfluss - im Grunde genommen alles.
  2. Haben Sie keine Angst, sich von Teammitgliedern zu verabschieden, die sich nicht an Standards halten. Einige Entwickler können einfach nicht innerhalb eines festgelegten Satzes von Standards arbeiten und werden zu Feinden der fünften Spalte auf dem Schlachtfeld, um die Codebasis sauber zu halten
  3. Haben Sie keine Angst, gering qualifizierte Teammitglieder für längere Zeit zum Testen zuzuweisen.
  4. Verwenden Sie jedes Tool in Ihrem Arsenal, um das Einchecken von verrottetem Code zu vermeiden. Dazu gehören dedizierte Tools sowie vorab geschriebene Komponententests , mit denen die Build-Dateien, Projektdateien, die Verzeichnisstruktur usw. getestet werden.
  5. Lassen Sie in einem Team von etwa 5-8 Mitgliedern Ihren Besten fast ständig umgestalten - das Durcheinander beseitigen, das die anderen hinterlassen. Selbst wenn Sie die besten Spezialisten auf dem Gebiet finden, werden Sie immer noch ein Durcheinander haben - es ist unvermeidlich, aber es kann durch das ständige Refactoring eingeschränkt werden.
  6. Schreiben Sie Komponententests und warten Sie sie - hängen Sie NICHT von den Komponententests ab, um das Projekt sauber zu halten.
  7. Besprechen Sie alles. Haben Sie keine Angst, Stunden damit zu verbringen, Dinge im Team zu besprechen. Dadurch werden die Informationen verbreitet und eine der Hauptursachen für fehlerhaften Code beseitigt: Verwirrung in Bezug auf Technologien, Ziele, Standards usw.
  8. Seien Sie sehr vorsichtig mit Beratern, die Code schreiben: Ihr Code wird per definitionem die eigentliche Scheiße sein.
  9. Führen Sie Überprüfungen vorzugsweise als Prozessschritt vor dem Einchecken durch. Haben Sie keine Angst, Commits zurückzusetzen.
  10. Verwenden Sie das Öffnungs- / Schließprinzip nur in der letzten Phase vor der Veröffentlichung: Es führt einfach dazu, dass der verrottete Code riecht.
  11. Wenn ein Problem auftritt, nehmen Sie sich Zeit, um es vollständig zu verstehen, bevor Sie eine Lösung implementieren. Der größte Teil des Code-Rot stammt aus der Implementierung von Lösungen für Probleme, die nicht vollständig verstanden wurden.
  12. Nutze die richtigen Technologien. Diese kommen oft in Sets und sind frisch: Es ist besser, sich auf eine Beta-Version eines Frameworks zu verlassen, von dem Sie zukünftig Support erhalten, als sich auf extrem stabile, aber veraltete Frameworks zu verlassen, die nicht unterstützt werden.
  13. Stellen Sie die besten Leute ein.
  14. Entlassen Sie den Rest - Sie betreiben kein Café.
  15. Wenn das Management nicht die besten Architekten sind und sich in den Entscheidungsprozess einmischen, suchen Sie einen anderen Job.

1
Was würden Sie tun, wenn Sie eine albtraumhafte 12-jährige VB6-App mit Hunderten von Formularen und Klassen pflegen und verbessern müssten, während Sie in Ihrer Freizeit an einem C # -Re-Write arbeiten?
Jfrankcarr

7
Nicht einverstanden mit # 3. Testen sollte nicht als Strafe für Ungeübte angesehen werden. Tatsächlich sollte es von allen Entwicklern gemacht werden und genauso wichtig sein wie das Kodieren und Entwerfen! Wenn Sie Mr Untrained im Team haben, holen Sie ihn für ein Training aus dem Team !.
NWS

1
"Nicht einverstanden mit # 3. Testen sollte nicht als Strafe für den Ungeübten angesehen werden." - Es sollte und ist nicht das, was ich geschrieben habe. Lassen Sie mich erklären: Testen ist ein guter Weg, um Menschen, denen Sie noch nicht vertrauen, Änderungen an ihrem Code zu übertragen. Die besten Tester, die ich gefunden habe, sind diejenigen, die Code beisteuern möchten, und beweisen ihre Kompetenz, indem sie den Code durchsehen, das Programm ausführen und die Fähigkeit zeigen, ihre Ergebnisse in der Laufzeit mit dem Quellcode zu korrelieren. Es ist keine Bestrafung - sein Training.
Kasper

1
"Nicht einverstanden mit # 10 - das hilft bei der Codequalität, wenn es richtig gemacht wird" Dies ist absolut falsch in meiner Arbeitserfahrung: Code, der weggesperrt ist, kann nicht umgestaltet werden, was bedeutet, dass er in seinem aktuellen Zustand bleibt, bis er entsperrt wird. Es kann überprüft werden, ob dieser Zustand zu einem bestimmten Zeitpunkt funktioniert, aber zu einem späteren Zeitpunkt ist diese Überprüfung falsch positiv: Der gesamte Code sollte bis zur Phase vor dem endgültigen Systemtest für das Refactoring offen bleiben.
Kasper

3
@casper: IMHO, Das Open / Closed-Prinzip sollte nicht als "Sie können die Quelle nicht ändern" verstanden werden, sondern als "den Code so gestalten, dass er eingefroren wird". Stellen Sie sicher, dass der Code nach Bedarf erweitert werden kann, ohne dass Änderungen erforderlich sind. Das Ergebnis ist inhärent lockerer gekoppelt und in hohem Maße zusammenhängend als durchschnittlicher Code. Dieses Prinzip ist auch beim Entwickeln einer Bibliothek für die Verwendung durch Dritte von entscheidender Bedeutung, da diese nicht einfach Ihren Code eingeben und ändern können, sodass Sie ihn ordnungsgemäß erweitern müssen.
Kevin Cathcart

12

Bereinigen Sie verrotteten Code durch Refactoring, während Sie Komponententests schreiben. Zahle (dies) Design-Schulden für den gesamten Code, den du berührst, wann immer du:

  • Entwickeln Sie eine neue Funktion
  • Ein Problem lösen

Beschleunigen Sie Ihren Test-First-Entwicklungszyklus erheblich, indem Sie:

  • Refactoring zum Konvertieren von Codemodulen in eine Skriptsprache
  • Verwenden Sie schnelle, cloudbasierte Testmaschinen

Refactor-Code für die Verwendung einer niedrigen Kopplung (von Einheiten mit hohem innerem Zusammenhalt) durch:

  • Einfachere (mehr) Funktionen (Routinen)
  • Module
  • Objekte (und Klassen oder Prototypen)
  • Reine Funktionen (ohne Nebenwirkungen)
  • Bevorzugen Sie die Delegation gegenüber der Vererbung
  • Ebenen (mit APIs)
  • Sammlungen kleiner, zweckgebundener Programme, die zusammenarbeiten können

Das organische Wachstum ist gut; großes Design ist schlecht.

Haben Sie einen Leiter, der sich mit dem aktuellen Design auskennt. Wenn nicht, lesen Sie den Projektcode, bis Sie über ausreichende Kenntnisse verfügen.

Lesen Sie Refactoring-Bücher.


1
+1 Gute erste Antwort, perfekte Möglichkeit, sich uns vorzustellen!
Yannis

11

Einfache Antwort: Sie können nicht .

Deshalb sollten Sie darauf abzielen, kleine und einfache Software zu schreiben . Es ist nicht einfach.

Dies ist nur möglich, wenn Sie über Ihr scheinbar komplexes Problem lange genug nachdenken, um es so einfach und präzise wie möglich zu definieren.

Die Lösung von Problemen, die wirklich groß und komplex sind, lässt sich oftmals immer noch auf kleinen und einfachen Modulen aufbauen.

Mit anderen Worten, wie andere betonten, sind Einfachheit und lose Kopplung die Hauptzutaten.

Wenn dies nicht möglich oder machbar ist, forschen Sie wahrscheinlich (komplexe Probleme ohne bekannte einfache oder gar keine bekannte Lösung). Erwarten Sie nicht, dass die Forschung direkt wartbare Produkte hervorbringt, das ist nicht der Zweck der Forschung.


9

Ich arbeite an einer Codebasis für ein Produkt, das seit 1999 kontinuierlich weiterentwickelt wird. Sie können sich also vorstellen, dass es inzwischen ziemlich komplex ist. Die häufigste Ursache für Unsicherheit in unserer Codebasis ist die Tatsache, dass wir sie häufig von ASP Classic nach ASP.NET portieren mussten , von ADO nach ADO.NET, von Postbacks nach Ajax , zum Wechseln von UI-Bibliotheken, Codierungsstandards usw.

Alles in allem haben wir vernünftige Arbeit geleistet, um die Codebasis wartbar zu halten. Die wichtigsten Dinge, die wir dazu beigetragen haben, sind:

1) Ständiges Refactoring - Wenn Sie einen Teil des Codes anfassen müssen, der hacky oder schwer zu verstehen ist, wird von Ihnen erwartet, dass Sie sich die zusätzliche Zeit nehmen, um ihn zu bereinigen, und Ihnen den Zeitrahmen dafür einräumen. Unit-Tests machen dies viel weniger beängstigend, weil Sie leichter gegen Regressionen testen können.

2) Sorgen Sie für eine saubere Entwicklungsumgebung - Achten Sie darauf, nicht mehr verwendeten Code zu löschen, und belassen Sie keine Sicherungskopien / Arbeitskopien / experimentellen Codes im Projektverzeichnis.

3) Konsistente Codierungsstandards für die Laufzeit des Projekts - Seien wir ehrlich, unsere Ansichten zu Codierungsstandards ändern sich im Laufe der Zeit. Ich schlage vor, den Codierungsstandard beizubehalten, mit dem Sie während der gesamten Laufzeit eines Projekts begonnen haben, es sei denn, Sie haben Zeit, den gesamten Code erneut zu installieren, um den neuen Standard zu erfüllen. Es ist großartig, dass Sie die ungarische Notation jetzt überwunden haben , aber wenden Sie diese Lektion auf neue Projekte an und wechseln Sie nicht nur bei diesem neuen Projekt den Mid-Stream.


8

Da Sie die Frage mit Projektmanagement markiert haben, habe ich versucht, einige Nicht-Code-Punkte hinzuzufügen :)

  • Umsatzplan - Nehmen Sie an, dass das gesamte Entwicklerteam zum Zeitpunkt der Wartungsphase verschwunden ist - kein Entwickler, der es wert ist, dass er nicht aufhört, sein System für immer zu warten. Bereiten Sie die Übergabematerialien vor, sobald Sie Zeit haben.

  • Konsistenz / Homogenität kann nicht genug betont werden. Dies entmutigt eine Kultur des "Alleingangs" und ermutigt neue Entwickler, sich zu erkundigen, ob sie Zweifel haben.

  • Behalten Sie den Mainstream bei - verwendete Technologien, Entwurfsmuster und Standards -, da ein neuer Entwickler im Team (auf jeder Ebene) mehr Chancen hat, schnell einsatzbereit zu sein.

  • Dokumentation - insbesondere Architektur - warum Entscheidungen getroffen wurden und Kodierungsstandards. Behalten Sie außerdem Referenzen / Notizen / Roadmaps in der Dokumentation der Geschäftsdomäne - Sie werden erstaunt sein, wie schwierig es für Unternehmen ist, einem Entwickler ohne Domänenerfahrung zu erklären, was sie tun.

  • Legen Sie die Regeln klar fest - nicht nur für Ihr aktuelles Entwicklungsteam, sondern denken Sie an zukünftige Wartungsentwickler. Wenn dies bedeutet, auf jeder Seite einen Hyperlink zu den relevanten Dokumentationen zum Design und zur Kodierung von Standards zu setzen, dann sei es so.

  • Stellen Sie sicher , dass die Architektur und vor allem Codeschichten klar abgegrenzt und getrennt werden - dies ermöglicht es möglicherweise für den Ersatz von Schichten von Code als neue Technologien zusammen kommen, zum Beispiel, ersetzen Sie eine Web Forms UI mit einem HTML5 jQuery UI , etc., die können Kaufen Sie ein Jahr mehr Langlebigkeit.


7

Eine Eigenschaft von in hohem Maße verwaltbarem Code ist die Funktionsreinheit .

Reinheit bedeutet, dass Funktionen für dieselben Argumente dasselbe Ergebnis zurückgeben sollten. Das heißt, sie sollten nicht von Nebenwirkungen anderer Funktionen abhängen. Darüber hinaus ist es nützlich, wenn sie selbst keine Nebenwirkungen haben.

Diese Eigenschaft ist leichter nachzuweisen als die Kopplungs- / Kohäsionseigenschaften. Sie müssen sich nicht anstrengen, um dies zu erreichen, und ich persönlich halte es für wertvoller.

Wenn Ihre Funktion rein ist, ist ihr Typ eine sehr gute Dokumentation für sich. Darüber hinaus ist das Schreiben und Lesen von Dokumentation in Bezug auf Argumente / Rückgabewert viel einfacher als das Erwähnen eines globalen Status (möglicherweise von anderen Threads O_O zugegriffen).

Als Beispiel für die umfassende Verwendung von Reinheit zur Verbesserung der Wartbarkeit können Sie GHC sehen . Es handelt sich um ein großes Projekt, das etwa 20 Jahre alt ist und bei dem große Umbauten durchgeführt und neue Hauptfunktionen eingeführt werden.

Zuletzt mag ich den Punkt "Einfach halten" nicht zu sehr. Sie können Ihr Programm nicht einfach halten, wenn Sie komplexe Dinge modellieren. Wenn Sie versuchen, einen einfachen Compiler zu erstellen, wird Ihr generierter Code wahrscheinlich sehr langsam enden. Natürlich können (und sollten) Sie einzelne Funktionen einfach gestalten, aber das ganze Programm wird dadurch nicht einfach.


2
Ein anderer Name für das, was Sie beschreiben, ist die Eigenschaft, deterministisch zu sein
jinglesthula

6

Zusätzlich zu den anderen Antworten würde ich Schichten empfehlen. Nicht zu viele, aber genug, um verschiedene Codetypen zu trennen.

Für die meisten Anwendungen verwenden wir ein internes API-Modell. Es gibt eine interne API, die eine Verbindung zur Datenbank herstellt. Dann eine UI- Ebene. Auf jeder Ebene können verschiedene Personen arbeiten, ohne andere Teile der Anwendungen zu stören oder zu beschädigen.

Ein weiterer Ansatz ist, dass jeder die comp.risks und The Daily WTF liest, damit er die Konsequenzen von schlechtem Design und schlechter Programmierung erkennt und sich davor fürchtet, seinen eigenen Code auf The Daily WTF zu sehen .


6

Da sich viele dieser Antworten von Anfang an auf große Teams zu konzentrieren scheinen, werde ich meine Ansicht als Teil eines zweiköpfigen Entwicklungsteams (drei, wenn Sie den Designer mit einbeziehen) für ein Startup vertreten.

Einfache Designs und Lösungen sind natürlich am besten, aber wenn Sie den Mann haben, der buchstäblich Ihr Gehalt bezahlt, haben Sie nicht unbedingt Zeit, über die eleganteste, einfachste und wartbarste Lösung nachzudenken. In diesem Sinne ist mein erster großer Punkt:

Dokumentation Kein Kommentar, Code sollte größtenteils selbstdokumentierend sein, aber Dinge wie Designdokumente, Klassenhierarchien und -abhängigkeiten, Architekturparadigmen usw. Alles, was einem neuen oder sogar vorhandenen Programmierer hilft, die Codebasis zu verstehen. Es kann auch hilfreich sein, die seltsamen Pseudobibliotheken zu dokumentieren, die irgendwann auftauchen, z. B. "Diese Klasse zu einem Element für diese Funktionalität hinzufügen", da dadurch auch verhindert wird, dass Benutzer Funktionen neu schreiben.

Aber auch wenn Sie ein strenges Zeitlimit haben, ist Folgendes zu beachten:

Vermeiden Sie Hacks und schnelle Lösungen. Wenn es sich bei der Schnellkorrektur nicht um die eigentliche Korrektur handelt, ist es immer besser, das zugrunde liegende Problem zu ermitteln und dann zu beheben. Wenn Sie nicht buchstäblich ein Szenario haben, in dem Sie das in den nächsten 2 Minuten zum Laufen bringen oder gefeuert werden, ist es eine bessere Idee, das Problem jetzt zu beheben, da Sie den Code später nicht reparieren, sondern nur Fahren Sie mit der nächsten Aufgabe fort, die Sie haben.

Und mein persönlicher Lieblingstipp ist eher ein Zitat, obwohl ich mich nicht an die Quelle erinnern kann:

"Code als ob die Person, die nach dir kommt, ein Mordpsychopath ist, der weiß, wo du lebst"


Ich habe Funktions- und Klassenkommentare immer als hilfreich empfunden, auch wenn nur die Trennung von Codesegmenten an Funktions- und Klassenpositionen mithilfe von Syntaxhervorhebungen möglich war. Ich schreibe sehr selten Kommentare in den Funktionscode, aber ich schreibe eine Zeile für jede Klasse und Funktion, wie zum Beispiel /** Gets the available times of a clinic practitioner on a specific date. **/oder /** Represents a clinic practitioner. **/.
Nick Bedford

5

Ein Prinzip, das nicht erwähnt wurde, das ich aber für wichtig halte, ist das offene / geschlossene Prinzip .

Sie sollten keinen Code ändern, der entwickelt und getestet wurde: Ein solcher Code ist versiegelt. Erweitern Sie stattdessen vorhandene Klassen durch Unterklassen, oder verwenden Sie Wrapper, Decorator- Klassen oder ein beliebiges Muster, das Sie für geeignet halten. Aber nicht ändern Code arbeiten .

Nur meine 2 Cent.


Was ist, wenn sich die im Arbeitscode ausgedrückten Geschäftsanforderungen ändern? Wenn Sie sich nicht mit schlecht faktorisiertem, aber technisch 'funktionierendem' Code befassen, kann dies auf lange Sicht Probleme bereiten, insbesondere wenn es an der Zeit ist, die erforderlichen Änderungen vorzunehmen.
Jinglesthula

@jinglesthula: Offen für Erweiterungen bedeutet, dass Sie die neue Funktionalität als neue Implementierung (z. B. Klasse) einer vorhandenen Schnittstelle hinzufügen können. Natürlich erlaubt schlecht strukturierter Code dies nicht: Es sollte eine Abstraktion wie eine Schnittstelle geben, die es dem Code ermöglicht, durch Hinzufügen von neuem Code "zu ändern", anstatt bestehenden Code zu ändern.
Giorgio

5
  • Sei ein Späher . Lassen Sie den Code immer sauberer als Sie ihn vorgefunden haben.

  • Repariere die zerbrochenen Fenster . Alle diese Kommentare "in Version 2.0 ändern", wenn Sie auf Version 3.0 sind.

  • Entwerfen Sie bei größeren Hacks als Team eine bessere Lösung und tun Sie dies. Wenn Sie den Hack als Team nicht beheben können, verstehen Sie das System nicht gut genug. "Bitten Sie einen Erwachsenen um Hilfe." Die ältesten Menschen in der Umgebung haben das vielleicht schon einmal gesehen. Versuchen Sie, ein Diagramm des Systems zu zeichnen oder zu extrahieren. Zeichnen oder extrahieren Sie Anwendungsfälle, die als Interaktionsdiagramme besonders schwierig sind. Dies behebt es nicht, aber zumindest können Sie es sehen.

  • Welche Annahmen stimmen nicht mehr, die das Design in eine bestimmte Richtung gelenkt haben? Es könnte eine kleine Umgestaltung geben, die sich hinter etwas von diesem Durcheinander verbirgt.

  • Wenn Sie erklären, wie das System funktioniert (auch nur einen Anwendungsfall) und sich immer wieder für ein Subsystem entschuldigen müssen, ist dies das Problem. Welches Verhalten würde den Rest des Systems vereinfachen (egal wie schwierig die Implementierung im Vergleich zu dem, was vorhanden ist). Das klassische Subsystem, das neu geschrieben werden muss, ist eines, das jedes andere Subsystem mit seiner Betriebssemantik und Implementierung belastet. "Oh, Sie müssen die Werte grozen, bevor Sie sie in das froo-Subsystem einspeisen, und dann die Grozierung wieder aufheben, wenn Sie von der froo ausgegeben werden. Vielleicht sollten alle Werte groziert werden, wenn sie vom Benutzer & Speicher gelesen werden. und der Rest des Systems ist falsch? Dies wird spannender, wenn es zwei oder mehr verschiedene Grozifikationen gibt.

  • Verbringen Sie eine Woche im Team damit, Warnungen zu entfernen, damit echte Probleme sichtbar werden.

  • Formatieren Sie den gesamten Code auf den Codierungsstandard.

  • Stellen Sie sicher, dass Ihr Versionskontrollsystem mit Ihrem Bug-Tracker verbunden ist. Dies bedeutet, dass zukünftige Änderungen nett und rechenschaftspflichtig sind und Sie herausfinden können, WARUM.

  • Mach ein bisschen Archäologie. Finden Sie die Originaldokumente und überprüfen Sie sie. Sie könnten sich auf diesem alten PC in der Ecke des Büros, in den verlassenen Büroräumen oder im Aktenschrank befinden, den niemand jemals öffnet.

  • Veröffentlichen Sie die Designdokumente erneut in einem Wiki. Dies hilft, Wissen zu institutionalisieren.

  • Schreiben Sie Checklisten-ähnliche Prozeduren für Releases und Builds. Das verhindert, dass die Leute nachdenken müssen, damit sie sich auf die Lösung von Problemen konzentrieren können. Automatisieren Sie Builds, wo immer dies möglich ist.

  • Versuchen Sie die kontinuierliche Integration . Je früher Sie einen fehlgeschlagenen Build erhalten, desto weniger Zeit kann das Projekt abseits der Schienen verbringen.

  • Wenn Ihr Teamleiter diese Dinge nicht tut, ist das schlecht für das Unternehmen.

  • Stellen Sie sicher, dass alle neuen Codes ordnungsgemäße Unit-Tests mit gemessener Abdeckung erhalten. Das Problem kann also nicht viel schlimmer werden.

  • Versuchen Sie, einige der alten Bits, die nicht einheitlich getestet wurden, zu testen. Dies hilft, die Angst vor Veränderungen abzubauen.

  • Automatisieren Sie Ihren Integrations- und Regressionstest, wenn Sie können. Zumindest eine Checkliste. Piloten sind schlau und werden viel bezahlt und verwenden Checklisten. Sie vermasseln auch ziemlich selten.


4

Lesen Sie den Code Complete von Steve McConnell und wiederholen Sie ihn . Es ist wie eine Bibel des guten Software-Schreibens, vom anfänglichen Projektdesign bis hin zu einer einzelnen Codezeile und allem dazwischen. Was mir am besten gefällt, ist, dass es auf jahrzehntelangen soliden Daten basiert. Es ist nicht nur der nächstbeste Codierungsstil.


3

Ich bin gekommen, um dies den "Winchester Mystery House Effect" zu nennen. Wie das Haus fing es einfach an, aber im Laufe der Jahre haben viele verschiedene Arbeiter so viele merkwürdige Funktionen hinzugefügt, dass niemand mehr wirklich versteht, was es ist. Warum führt diese Treppe ins Nichts und warum öffnet sich diese Tür nur in eine Richtung? Wer weiß?

Die Möglichkeit, diesen Effekt einzuschränken, besteht darin, mit einem guten Design zu beginnen, das so flexibel ist, dass es für Erweiterungen geeignet ist. Hierzu wurden bereits einige Vorschläge unterbreitet.

Aber oft werden Sie einen Job annehmen, bei dem der Schaden bereits angerichtet wurde, und es ist zu spät für ein gutes Design, ohne eine teure und möglicherweise riskante Neugestaltung und Umschreibung durchzuführen. In solchen Situationen ist es am besten, Wege zu finden, um das Chaos zu begrenzen, während man es bis zu einem gewissen Grad aufgreift. Es kann Ihre Entwurfssensibilität stören, dass alles eine riesige, hässliche "Manager" -Klasse durchlaufen muss oder die Datenzugriffsschicht eng an die Benutzeroberfläche gekoppelt ist, aber lernen, damit umzugehen. Code defensiv innerhalb dieses Frameworks und versuche, das Unerwartete zu erwarten, wenn "Geister" vergangener Programmierer auftauchen.


2

Code-Refactoring und Unit-Tests sind völlig in Ordnung. Da dieses langjährige Projekt jedoch von Hacks heimgesucht wird, bedeutet dies, dass das Management nicht den Fuß nach unten setzt, um die Fäule zu säubern. Das Team muss Hacks einführen, da jemand nicht genügend Ressourcen für die Schulung von Personen und die Analyse des Problems / der Anforderung bereitstellt.

Die Aufrechterhaltung eines langfristigen Projekts liegt in der Verantwortung des Projektmanagers ebenso wie eines einzelnen Entwicklers.

Die Leute stellen keine Hacks vor, weil sie es mögen. Sie werden durch die Umstände gezwungen.


Durch die Umstände gezwungen? Die Leute führen Hacks ein, weil (a) sie es nicht besser wissen => Coaching benötigen, (b) sie nicht das Gesamtbild sehen => Kommunikation, Dokumentation und Disziplin erforderlich sind, (c) sie denken, sie sind schlauer => das ist die größte Hürde zur Überwindung (d) durch die Umstände gezwungen => schnelle Hotfixes sind in Ordnung, wenn Zeitdruck herrscht, aber jemand muss die Verantwortung übernehmen und den Code anschließend bereinigen. Jeder andere "Umstand" ist einfach BS . Es gibt Ausnahmen von dieser Faustregel, aber die meisten sogenannten Ausnahmen sind "faul".
JensG

2

Ich möchte nur ein nicht-technisches Problem und einen (vielleicht) pragmatischen Ansatz ansprechen.

Wenn Ihrem Manager die technische Qualität (überschaubarer Code, einfache Architektur, zuverlässige Infrastruktur usw.) nicht wichtig ist, kann das Projekt nur schwer verbessert werden. In diesem Fall ist es notwendig, den Manager zu schulen und zu überzeugen, Anstrengungen in die Wartbarkeit und den Umgang mit technischen Schulden zu "investieren" .

Wenn Sie von der Codequalität dieser Bücher träumen, brauchen Sie auch einen Chef, der sich darum kümmert.

Oder wenn Sie nur ein "Frankenstein-Projekt" zähmen wollen, sind dies meine Tipps:

  • Organisieren und vereinfachen
  • Funktionen kürzen
  • Priorisieren Sie die Lesbarkeit vor der Effizienz (wenn dies akzeptabel ist und einige Effizienzgewinne zu miserabel sind, um sie beizubehalten).

Nach meiner Erfahrung ist das Programmieren eher entropisch als neu (zumindest im populären imperativ-strukturierten Paradigma). Wenn Leute Code schreiben, um "nur zu arbeiten", besteht die Tendenz, die Organisation zu verlieren. Jetzt erfordert das Organisieren von Code viel Zeit, manchmal mehr als nur das Funktionieren.

Nehmen Sie sich neben der Implementierung von Funktionen und der Behebung von Fehlern auch Zeit für die Code-Bereinigung.


"... das Projekt ist zum Scheitern verurteilt" - meiner Erfahrung nach ist das nicht unbedingt so. Alternative ist mit dem Manager zu erziehen und überzeugen Bemühungen in zu „investieren“ Wartbarkeit und Adressierung technisch-Schulden
gnat

Tut mir leid, ich konnte es mir nicht verkneifen, das zu schreiben, da ich bereits eine Erfahrung gemacht hatte, als der Manager alle meine Ratschläge zur technischen Verschuldung ignorierte. Aber ich denke, Sie haben Recht: Ungefähr ein Jahr nach der Aufgabe dieses Projekts verlor der Manager all seine Autorität über das Tech-Team, weil er nicht in der Lage war, sie zu managen.
Eric.Void

1

Ich war überrascht, dass keine der zahlreichen Antworten das Offensichtliche hervorhob: Die Software besteht aus zahlreichen kleinen, unabhängigen Bibliotheken. Mit vielen kleinen Bibliotheken können Sie eine große und komplexe Software erstellen. Wenn sich die Anforderungen ändern, müssen Sie nicht die gesamte Codebasis wegwerfen oder untersuchen, wie eine große Hup-Codebasis geändert werden kann, um etwas anderes als das zu tun, was sie gerade tut. Sie entscheiden lediglich, welche dieser Bibliotheken nach einer Änderung der Anforderungen noch relevant sind und wie Sie sie miteinander kombinieren, um die neue Funktionalität zu erhalten.

Verwenden Sie beliebige Programmiertechniken in den Bibliotheken, die die Verwendung der Bibliothek vereinfachen. Beachten Sie, dass z. B. nicht objektorientierte sprachunterstützende Funktionszeiger tatsächlich objektorientiertes Programmieren (OOP) unterstützen. So können Sie zB in C OOP machen.

Sie können sogar erwägen, diese kleinen, unabhängigen Bibliotheken für viele Projekte freizugeben (Git-Submodule sind Ihre Freunde).

Selbstverständlich sollte jede kleine, unabhängige Bibliothek einem Komponententest unterzogen werden. Wenn eine bestimmte Bibliothek nicht Unit-testbar ist, machen Sie etwas falsch.

Wenn Sie C oder C ++ verwenden und die Idee nicht mögen, viele kleine .so-Dateien zu haben, können Sie alle Bibliotheken zu einer größeren .so-Datei verknüpfen, oder Sie können alternativ statische Verknüpfungen durchführen. Gleiches gilt für Java. Ändern Sie einfach .so in .jar.


Dies scheint aus meiner Sicht ein bisschen zu theoretisch zu sein. Natürlich bestanden die Projekte, die ich in meiner Frage erwähnte, aus mehreren Bibliotheken und Modulen. Meine Erfahrung in den letzten 26 Jahren der Softwareentwicklung war, dass das Projekt mit
zunehmendem Alter

0

Einfach: Reduzieren Sie die Wartungskosten für den größten Teil Ihres Codes auf Null, bis Sie eine wartbare Anzahl beweglicher Teile haben. Code, der niemals geändert werden muss, verursacht keine Wartungskosten. Ich empfehle das Ziel für wirklich macht Code Null Wartungskosten, nicht versuchen , die Kosten über viele kleine und pingelig Refactoring Iterationen zu verringern. Machen Sie es gleich Null kosten .

Zugegeben, das ist sehr viel schwieriger, als es sich anhört. Aber es ist nicht schwer anzufangen. Sie können einen Teil der Codebasis nehmen, sie testen, eine schöne Schnittstelle darüber erstellen, wenn das Schnittstellendesign unübersichtlich ist, und die Teile der Codebasis erweitern, die zuverlässig und stabil sind (wie aus Gründen, die nicht geändert werden müssen), während gleichzeitig Schrumpfen der Teile, die unzuverlässig und instabil sind. Codebasen, die sich oft wie ein Albtraum anfühlen, unterscheiden die beweglichen Teile, die ausgetauscht werden müssen, nicht von den Teilen, die nicht ausgetauscht werden müssen, da alles als unzuverlässig und anfällig für Änderungen angesehen wird.

Eigentlich empfehle ich, die Organisation Ihrer Codebasis in "stabile" und "instabile" Teile zu unterteilen, wobei die stabilen Teile eine riesige PITA sind, die wiederhergestellt und geändert werden muss (was eine gute Sache ist, da sie nicht benötigt werden sollten) geändert und umgebaut werden, wenn sie wirklich in den Bereich "Stall" gehören).

Es ist nicht die Größe einer Codebasis, die die Wartbarkeit erschwert. Es ist die Größe der Codebasis, die beibehalten werden muss. Ich bin immer auf Millionen von Codezeilen angewiesen, wenn ich beispielsweise die API des Betriebssystems verwende. Dies trägt jedoch nicht zu den Wartungskosten meines Produkts bei, da ich den Quellcode des Betriebssystems nicht warten muss. Ich benutze nur den Code und es funktioniert. Code, den ich nur verwende und nie warten muss, verursacht auf meiner Seite keine Wartungskosten.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.