Ich verstehe die Bedeutung von gut dokumentiertem Code. Ich verstehe aber auch die Bedeutung von selbstdokumentierendem Code. Je einfacher es ist, eine bestimmte Funktion visuell zu lesen, desto schneller können wir bei der Softwarewartung fortfahren.
Vor diesem Hintergrund möchte ich große Funktionen in andere kleinere Funktionen aufteilen. Aber ich mache das bis zu einem Punkt, an dem eine Klasse mehr als fünf von ihnen haben kann, nur um eine öffentliche Methode zu bedienen. Multiplizieren Sie nun fünf private Methoden mit fünf öffentlichen, und Sie erhalten ungefähr fünfundzwanzig versteckte Methoden, die von diesen öffentlichen Methoden wahrscheinlich nur einmal aufgerufen werden.
Sicher, es ist jetzt einfacher, diese öffentlichen Methoden zu lesen, aber ich kann nicht anders, als zu viele Funktionen zu haben, ist eine schlechte Übung.
[Bearbeiten]
Die Leute haben mich gefragt, warum ich denke, dass es schlecht ist, zu viele Funktionen zu haben.
Die einfache Antwort: Es ist ein Bauchgefühl.
Meiner Meinung nach kann ich nicht auf stundenlange Erfahrung in der Softwareentwicklung zurückgreifen. Es ist nur eine Ungewissheit, die mir eine "Schreibblockade" gab, aber für einen Programmierer.
In der Vergangenheit habe ich nur persönliche Projekte programmiert. Erst kürzlich bin ich zu teambasierten Projekten übergegangen. Jetzt möchte ich sicherstellen, dass andere meinen Code lesen und verstehen können.
Ich war mir nicht sicher, was die Lesbarkeit verbessern würde. Einerseits dachte ich daran, eine große Funktion durch verständliche Namen in andere kleinere zu trennen. Aber es gab eine andere Seite von mir, die sagte, dass es nur überflüssig ist.
Also bitte ich dies, mich selbst zu erleuchten, um den richtigen Weg zu finden.
[Bearbeiten]
Unten I der zwei Versionen , wie ich konnte mein Problem lösen. Die erste Lösung besteht darin, keine großen Codestücke voneinander zu trennen. Der zweite macht verschiedene Dinge.
Erste Version:
public static int Main()
{
// Displays the menu.
Console.WriteLine("Pick your option");
Console.Writeline("[1] Input and display a polynomial");
Console.WriteLine("[2] Add two polynomials");
Console.WriteLine("[3] Subtract two polynomials");
Console.WriteLine("[4] Differentiate two polynomials");
Console.WriteLine("[0] Quit");
}
Zweite Version:
public static int Main()
{
DisplayMenu();
}
private static void DisplayMenu()
{
Console.WriteLine("Pick your option");
Console.Writeline("[1] Input and display a polynomial");
Console.WriteLine("[2] Add two polynomials");
Console.WriteLine("[3] Subtract two polynomials");
Console.WriteLine("[4] Differentiate two polynomials");
Console.WriteLine("[0] Quit");
}
Letzterer ruft in den obigen Beispielen eine Funktion auf, die während der gesamten Laufzeit des Programms nur einmal verwendet wird.
Hinweis: Der obige Code ist verallgemeinert, entspricht jedoch der Art meines Problems.
Nun, hier ist meine Frage: welche? Wähle ich den ersten oder den zweiten aus?
Antworten:
Dies ist die sogenannte Kapselung , die auf höherer Ebene eine Kontrollabstraktion erzeugt . Das ist eine gute Sache.
Dies bedeutet , dass jemand Ihren Code zu lesen, wenn sie auf die erhalten
startTheEngine()
Methode in Ihrem Code können alle unteren Ebene Details ignorieren wieopenIgnitionModule()
,turnDistributorMotor()
,sendSparksToSparkPlugs()
,injectFuelIntoCylinders()
,activateStarterSolenoid()
, und alle anderen komplexen, kleinen, Funktionen, um ausgeführt werden müssen erleichtern die viel größere, abstraktere Funktion vonstartTheEngine()
.Sofern sich das Problem, mit dem Sie sich in Ihrem Code befassen, nicht direkt mit einer dieser Komponenten befasst, können die Codewartenden fortfahren und die in einer Sandbox gekapselte Funktionalität ignorieren.
Dies hat auch den zusätzlichen Vorteil, dass Sie Ihren Code einfacher testen können. . Zum Beispiel kann ich einen Testfall schreiben
turnAlternatorMotor(int revolutionRate)
und seine Funktionalität völlig unabhängig von den anderen Systemen testen. Wenn es ein Problem mit dieser Funktion gibt und die Ausgabe nicht den Erwartungen entspricht, weiß ich, woran es liegt.Code, der nicht in Komponenten zerlegt ist, ist viel schwieriger zu testen. Plötzlich betrachten Ihre Betreuer nur noch die Abstraktion, anstatt sich in messbare Komponenten einarbeiten zu können.
Mein Rat ist, weiterhin das zu tun, was Sie tun, da sich Ihr Code skalieren lässt, einfach zu warten ist und über Jahre hinweg verwendet und aktualisiert werden kann.
quelle
myString.replaceAll(pattern, originalData);
Oder füge ich die gesamte replaceAll-Methode in meinen Code ein, einschließlich des Zeichenarrays, das das zugrunde liegende Zeichenfolgenobjekt darstellt, jedes Mal, wenn ich die Funktionalität einer Zeichenfolge verwenden möchte?Ja und nein. Der grundlegende Grundsatz lautet: Eine Methode sollte nur eines und nur eines tun
Es ist richtig, Ihre Methode in kleinere Methoden zu unterteilen. Andererseits sollten diese Methoden optimalerweise allgemein genug sein, um nicht nur dieser "großen" Methode zu dienen, sondern auch an anderen Orten wiederverwendbar zu sein. In einigen Fällen folgt eine Methode jedoch einer einfachen Baumstruktur, z. B. einer Initialize-Methode, die InitializePlugins, InitializeInterface usw. aufruft.
Wenn Sie eine wirklich große Methode / Klasse haben, ist dies normalerweise ein Zeichen dafür, dass sie zu viel bewirkt, und Sie müssen einige Umgestaltungen vornehmen, um den "Blob" aufzulösen. Perphaps verbergen eine gewisse Komplexität in einer anderen Klasse unter einer Abstraktion und verwenden die Abhängigkeitsinjektion
quelle
Ich denke im Allgemeinen ist es besser, sich auf die Seite zu vieler Funktionen zu setzen, als auf die Seite zu weniger. Die beiden Ausnahmen von dieser Regel, die ich in der Praxis gesehen habe, betreffen die DRY- und YAGNI- Prinzipien. Wenn Sie viele nahezu identische Funktionen haben, sollten Sie diese kombinieren und Parameter verwenden, um Wiederholungen zu vermeiden. Sie können auch zu viele Funktionen haben, wenn Sie sie "nur für den Fall" erstellt haben und sie nicht verwendet werden. Ich sehe absolut nichts Falsches daran, eine Funktion zu haben, die nur einmal verwendet wird, wenn sie die Lesbarkeit und Wartbarkeit erhöht.
quelle
Die großartige Antwort von jmort253 hat mich dazu inspiriert, mit einem "Ja, aber" zu antworten ...
Viele kleine private Methoden zu haben, ist keine schlechte Sache, aber achten Sie auf das nervige Gefühl, das Sie dazu bringt, hier eine Frage zu stellen :). Wenn Sie an einem Punkt angelangt sind, an dem Sie Tests schreiben, die sich nur auf private Methoden konzentrieren (entweder durch direkten Aufruf oder indem Sie ein Szenario einrichten, in dem einer auf eine bestimmte Weise aufgerufen wird, damit Sie das Ergebnis testen können), dann du solltest einen Schritt zurück machen.
Was Sie vielleicht haben, ist eine neue Klasse mit einer eigenen öffentlichen Schnittstelle, die versucht zu entkommen. An diesem Punkt sollten Sie überlegen, ob Sie eine Klasse extrahieren möchten, um den Teil Ihrer vorhandenen Klassenfunktionalität zu kapseln, der derzeit in einer privaten Methode ausgeführt wird. Jetzt kann Ihre ursprüngliche Klasse Ihre neue Klasse als Abhängigkeit verwenden, und Sie können direkt fokussiertere Tests für diese Klasse schreiben.
quelle
Fast jedes OO-Projekt, an dem ich jemals teilgenommen habe, litt stark unter zu großen Klassen und zu langen Methoden.
Wenn ich das Gefühl habe, einen Kommentar zu benötigen, der den nächsten Codeabschnitt erklärt, extrahiere ich diesen Abschnitt in eine separate Methode. Auf lange Sicht wird der Code dadurch kürzer. Diese kleinen Methoden werden häufiger wiederverwendet, als Sie zunächst erwarten würden. Sie sehen Möglichkeiten, einige davon in einer separaten Klasse zu sammeln. Bald denken Sie über Ihr Problem auf einer höheren Ebene nach, und die ganze Anstrengung geht viel schneller. Neue Funktionen lassen sich einfacher schreiben, da Sie auf den kleinen Klassen aufbauen können, die Sie mit diesen kleinen Methoden erstellt haben.
quelle
Eine Klasse mit 5 öffentlichen Methoden und 25 privaten Methoden scheint mir nicht so groß zu sein. Stellen Sie einfach sicher, dass Ihre Klassen klar definierte Verantwortlichkeiten haben, und sorgen Sie sich nicht zu sehr um die Anzahl der Methoden.
Diese privaten Methoden sollten sich jedoch auf einen bestimmten Aspekt der gesamten Aufgabe konzentrieren, jedoch nicht auf die Weise "doSomethingPart1", "doSomethingPart2". Sie gewinnen nichts, wenn diese privaten Methoden nur Teile einer willkürlich unterteilten langen Geschichte sind, von denen jede außerhalb des gesamten Kontexts bedeutungslos ist.
quelle
Auszug aus R. Martins Clean Code (S. 176):
quelle
Einige Optionen:
Das ist gut. Nennen Sie einfach die privaten Methoden sowie Ihre öffentlichen Methoden. Und nennen Sie Ihre öffentlichen Methoden gut.
Abstrahieren Sie einige dieser Hilfsmethoden in Hilfsklassen oder Hilfsmodule. Stellen Sie sicher, dass diese Hilfsklassen / -module gut benannt sind und solide Abstraktionen für sich sind.
quelle
Ich glaube nicht, dass es jemals ein Problem mit "zu vielen privaten Methoden" gibt, wenn es sich so anfühlt, als wäre es wahrscheinlich ein Symptom für eine schlechte Codearchitektur.
Hier ist, wie ich darüber denke ... Wenn die Architektur gut entworfen ist, ist es im Allgemeinen offensichtlich, wo der Code, der X ausführt, sein sollte. Es ist akzeptabel, wenn es ein paar Ausnahmen gibt - aber diese müssen wirklich außergewöhnlich sein, sonst wird die Architektur überarbeitet, um diese als Standard zu behandeln.
Wenn das Problem beim Öffnen Ihrer Klasse darin besteht, dass sie voller privater Methoden ist, die größere Teile in kleinere Teile Code aufteilen, ist dies möglicherweise ein Symptom für fehlende Architektur. Anstelle von Klassen und Architekturen wurde dieser Codebereich prozedural in einer Klasse implementiert.
Hier ein Gleichgewicht zu finden, hängt vom Projekt und seinen Anforderungen ab. Das Gegenargument dazu ist das Sprichwort, dass ein Junior-Programmierer die Lösung in 50 Codezeilen hochfahren kann, für die ein Architekt 50 Klassen benötigt.
quelle
Ja.
In Python gibt es das Konzept von "privat" (wie es von C ++, Java und C # verwendet wird) nicht wirklich.
Es gibt eine Art private Namenskonvention, aber das war's.
Privat kann zu schwer zu testendem Code führen. Es kann auch das "Open-Closed-Prinzip" brechen, indem Code einfach geschlossen wird.
Folglich haben private Funktionen für Leute, die Python verwendet haben, keinen Wert. Mach einfach alles öffentlich und mach es fertig.
quelle