Unsere Code - Basis ist alter und neue Programmierer, wie ich, schnell zu tun , es zu lernen , wie es gemacht wird aus Gründen der Einheitlichkeit. Da ich dachte, dass wir irgendwo anfangen müssen, habe ich es auf mich genommen, eine Dateninhaberklasse als solche umzugestalten:
- Setter-Methoden entfernt und alle Felder gemacht
final
(ich nehme "final
ist gut" axiomatisch). Die Setter wurden, wie sich herausstellte, nur im Konstruktor verwendet, so dass dies keine Nebenwirkungen hatte. - Builder-Klasse eingeführt
Die Builder-Klasse war erforderlich, da der Konstruktor (was in erster Linie zur Umgestaltung führte) ungefähr 3 Codezeilen umfasst. Es hat viele Parameter.
Wie es der Zufall wollte, arbeitete ein Teamkollege von mir an einem anderen Modul und benötigte die Setter, da die von ihm benötigten Werte an verschiedenen Stellen im Fluss verfügbar wurden. So sah der Code aus:
public void foo(Bar bar){
//do stuff
bar.setA(stuff);
//do more stuff
bar.setB(moreStuff);
}
Ich habe argumentiert, dass er stattdessen den Builder verwenden sollte, da durch das Entfernen von Setzern die Felder unveränderlich bleiben (sie haben mich zuvor über die Unveränderlichkeit beschwert) und auch, weil Builder das Erstellen von Objekten als Transaktion zulassen. Ich habe den folgenden Pseudocode entworfen:
public void foo(Bar bar){
try{
bar.setA(a);
//enter exception-throwing stuff
bar.setB(b);
}catch(){}
}
Wenn diese Ausnahme ausgelöst bar
wird, sind beschädigte Daten vorhanden, die mit einem Builder vermieden worden wären:
public Bar foo(){
Builder builder=new Builder();
try{
builder.setA(a);
//dangerous stuff;
builder.setB(b);
//more dangerous stuff
builder.setC(c);
return builder.build();
}catch(){}
return null;
}
Meine Teamkollegen erwiderten, dass die fragliche Ausnahme niemals ausgelöst wird, was für diesen speziellen Codebereich fair genug ist, aber ich glaube, dass der Wald für den Baum fehlt.
Der Kompromiss bestand darin, zur alten Lösung zurückzukehren, nämlich einen Konstruktor ohne Parameter zu verwenden und alles mit Setzern nach Bedarf festzulegen. Die Begründung war, dass diese Lösung dem KISS-Prinzip folgt, gegen das meine verstößt.
Ich bin neu in dieser Firma (weniger als 6 Monate) und mir völlig bewusst, dass ich diese verloren habe. Die Fragen, die ich habe, sind:
- Gibt es ein anderes Argument für die Verwendung von Buildern anstelle des "alten Wegs"?
- Lohnt sich die von mir vorgeschlagene Änderung überhaupt?
aber wirklich,
- Haben Sie Tipps, wie Sie solche Argumente besser präsentieren können, wenn Sie sich dafür einsetzen, etwas Neues auszuprobieren?
setA
?Antworten:
Hier ist es schiefgegangen - Sie haben die Codebasis architektonisch grundlegend geändert, sodass sie sich stark von den Erwartungen unterschied. Sie haben Ihre Kollegen überrascht. Überraschung ist nur dann gut, wenn es sich um eine Party handelt, das Prinzip der geringsten Überraschung ist golden (selbst wenn es sich um eine Party handelt, würde ich wissen, dass Sie saubere Unterhosen tragen!)
Wenn Sie diese Änderung für sinnvoll hielten, wäre es viel besser gewesen, den Pseudocode zu skizzieren, der die Änderung zeigt, und ihn Ihren Kollegen (oder zumindest denjenigen, die die Rolle am nächsten am Architekten haben) zu präsentieren und zu prüfen, was sie gedacht haben, bevor Sie etwas unternehmen. So wie es ist, bist du Schurke geworden und hast gedacht, dass die gesamte Codebasis dir gehört, damit zu spielen, wie du es für richtig hältst. Ein Spieler im Team, kein Teamspieler!
Ich bin vielleicht ein bisschen hart zu dir, aber ich war in der entgegengesetzten Richtung: Sieh dir Code an und denke, "WTF ist hier passiert ?!", nur um herauszufinden, dass der neue Typ (fast immer der neue Typ) beschlossen hat, sich zu ändern Eine Fülle von Dingen, die auf dem basieren, was er für den "richtigen Weg" hält. Schrauben auch mit der SCM-Historie, was ein weiteres großes Problem darstellt.
quelle
Wie beschrieben, sehe ich nicht, warum der Code Setter erfordert . Ich weiß wahrscheinlich nicht genug über den Anwendungsfall, aber warum warten Sie nicht, bis alle Parameter bekannt sind, bevor Sie das Objekt instanziieren?
Als Alternative, wenn die Situation Setter erfordert: Bieten Sie eine Möglichkeit an, Ihren Code für diese Setter einzufrieren, und werfen Sie einen Assertionsfehler (alias Programmiererfehler), wenn Sie versuchen, Felder zu ändern, nachdem das Objekt fertig ist.
Ich denke, die Setter zu entfernen und final zu verwenden, ist die "richtige" Art und Weise, dies zu tun und Unveränderlichkeit durchzusetzen. Aber ist es wirklich das, womit Sie Ihre Zeit verbringen sollten?
Allgemeine Hinweise
Alt = schlecht, neu = gut, mein Weg, dein Weg ... Diese Art der Diskussion ist nicht konstruktiv.
Derzeit folgt die Art und Weise, wie Ihr Objekt verwendet wird, einer impliziten Regel. Dies ist Teil der ungeschriebenen Spezifikation Ihres Codes, und Ihr Team ist möglicherweise der Ansicht, dass für andere Teile des Codes kein großes Risiko besteht, ihn zu missbrauchen. Was Sie hier tun möchten, ist, die Regel mit einem Builder und Überprüfungen zur Kompilierungszeit expliziter zu gestalten.
In gewisser Weise ist das Umgestalten von Code mit der Broken Window- Theorie verknüpft: Sie finden es richtig, jedes Problem so zu beheben, wie Sie es sehen (oder sich eine Notiz für ein späteres "Qualitätsverbesserungs" -Treffen zu machen), damit der Code immer angenehm aussieht, mit dem Sie arbeiten können. ist sicher und sauber. Sie und Ihr Team haben jedoch nicht die gleiche Vorstellung davon, was "gut genug" ist. Was Sie als Gelegenheit sehen, einen Beitrag zu leisten und den Code in gutem Glauben zu verbessern, wird wahrscheinlich anders gesehen als das vorhandene Team.
Übrigens sollte Ihr Team nicht unbedingt unter Trägheit, schlechten Gewohnheiten, mangelnder Bildung leiden ... Das Schlimmste, was Sie tun können, ist, ein Bild von einem Besserwisser zu projizieren, der da ist, um sie zu zeigen wie man codiert. Zum Beispiel ist Unveränderlichkeit nichts Neues , Ihre Kollegen haben wahrscheinlich darüber gelesen, aber nur weil dieses Thema in Blogs immer beliebter wird, reicht es nicht aus, sie zu überzeugen, Zeit damit zu verbringen, ihren Code zu ändern.
Schließlich gibt es unzählige Möglichkeiten, eine vorhandene Codebasis zu verbessern, aber dies kostet Zeit und Geld. Ich könnte mir Ihren Code ansehen, ihn als "alt" bezeichnen und Dinge finden, die ich nicht aussuchen kann. Zum Beispiel: keine formale Spezifikation, nicht genügend Asserts, möglicherweise nicht genügend Kommentare oder Tests, nicht genügend Code-Coverage, nicht optimaler Algorithmus, zu viel Speicherbedarf, nicht immer das "bestmögliche" Designmuster, usw. und Übelkeit . Aber für die meisten Punkte, die ich ansprechen würde, würde man meinen: Das ist in Ordnung, mein Code funktioniert, es besteht keine Notwendigkeit, mehr Zeit damit zu verbringen.
Vielleicht denkt Ihr Team, dass das, was Sie vorschlagen, über den Punkt hinausgeht, an dem die Renditen sinken. Selbst wenn Sie aufgrund eines von Ihnen gezeigten Beispiels eine tatsächliche Instanz eines Fehlers gefunden hätten (mit der Ausnahme), würden sie diesen wahrscheinlich nur einmal beheben und möchten den Code nicht umgestalten.
Die Frage ist also, wie Sie Ihre Zeit und Energie verbringen können, da diese begrenzt sind . Es werden fortlaufend Änderungen an der Software vorgenommen, aber im Allgemeinen beginnt Ihre Idee mit einem negativen Ergebnis, bis Sie gute Argumente dafür liefern können. Auch wenn Sie mit dem Vorteil Recht haben, ist es für sich genommen kein ausreichendes Argument, da es im Korb " Schön zu haben, eines Tages ... " enden wird.
Wenn Sie Ihre Argumente vorbringen, müssen Sie einige "Plausibilitätsprüfungen" durchführen: Versuchen Sie, die Idee oder sich selbst zu verkaufen? Was wäre, wenn jemand anderes dies dem Team vorstellte? Würdest du einige Fehler in ihrer Argumentation finden? Versuchen Sie, einige allgemeine bewährte Methoden anzuwenden, oder haben Sie die Besonderheiten Ihres Codes berücksichtigt?
Dann müssen Sie sicher sein, dass Sie nicht so aussehen, als ob Sie versuchen, die "Fehler" Ihres Teams in der Vergangenheit zu beheben. Es hilft zu zeigen, dass Sie nicht Ihre Idee sind, aber ein vernünftiges Feedback nehmen können. Je öfter Sie dies tun, desto mehr haben Ihre Vorschläge die Möglichkeit, verfolgt zu werden.
quelle
Das tust du nicht.
Wenn Ihr Konstruktor 3 Parameterzeilen enthält, ist er zu groß und zu komplex. Kein Entwurfsmuster wird das beheben.
Wenn Sie eine Klasse haben, deren Daten zu unterschiedlichen Zeiten verfügbar sind, sollten es zwei verschiedene Objekte sein, oder Ihr Consumer sollte die Komponenten aggregieren und dann das Objekt erstellen . Sie brauchen keinen Baumeister, um das zu tun.
quelle
String
s und andere Grundelemente. Es gibt nirgendwo eine Logik, die nicht einmal nachnull
s usw. sucht. Es ist also nur reine Größe, nicht Komplexität an sich. Ich dachte, etwas zu tunbuilder.addA(a).addB(b); /*...*/ return builder.addC(c).build();
wäre viel einfacher für die Augen.Sie scheinen sich mehr darauf zu konzentrieren, richtig zu liegen, als gut mit anderen zusammenzuarbeiten. Schlimmer noch, Sie erkennen, dass Sie einen Machtkampf führen und nicht darüber nachdenken, wie sich die Dinge für die Menschen anfühlen, deren Erfahrung und Autorität Sie herausfordern.
Kehren Sie das um.
Konzentrieren Sie sich auf die Arbeit mit anderen. Richte deine Gedanken als Vorschläge und Ideen ein. Lassen Sie SIE IHRE Ideen durchsprechen, bevor Sie Fragen stellen, damit sie über Ihre nachdenken. Vermeiden Sie direkte Konfrontationen und akzeptieren Sie äußerlich, dass es (für den Moment) produktiver ist, Dinge auf Gruppenebene zu tun, als einen harten Kampf zu führen, um die Gruppe zu verändern. (Aber bring die Dinge zurück.) Mache die Arbeit mit dir zu einer Freude.
Wenn Sie dies konsequent tun, sollten Sie weniger Konflikte verursachen und feststellen, dass mehr Ihrer Ideen von anderen übernommen werden. Wir alle leiden unter der Illusion, dass das perfekte logische Argument andere begeistern und den Tag gewinnen wird. Und wenn es nicht so funktioniert, denken wir, dass es sollte .
Das steht aber in direktem Widerspruch zur Realität. Die meisten Argumente gehen verloren, bevor der erste logische Punkt gemacht wurde. Sogar unter vermeintlich logischen Menschen ist die Psychologie die Vernunft überlegen. Menschen zu überzeugen bedeutet, psychologische Barrieren zu überwinden, um richtig gehört zu werden, und keine perfekte Logik zu haben.
quelle
Frame your thoughts as suggestions and ideas. Get THEM to talk through THEIR ideas before asking questions to make them think about yours
+1 für das trotzdem"Wenn Sie einen neuen Hammer haben, wird alles wie ein Nagel aussehen." - Das habe ich mir gedacht, als ich deine Frage gelesen habe.
Wenn ich Ihr Kollege wäre, würde ich Sie fragen: "Warum nicht das ganze Objekt im Konstruktor initialisieren?" Das ist es doch, es ist Funktionalität. Warum sollte das Builder-Muster (oder ein anderes Muster) verwendet werden?
Es ist schwierig, aus diesem kleinen Code-Schnipsel zu unterscheiden. Vielleicht ist es das - Sie und Ihre Kollegen müssen es bewerten.
Ja, erfahren Sie mehr über das Thema, bevor Sie es diskutieren. Rüsten Sie sich mit guten Argumenten und Überlegungen aus, bevor Sie in die Diskussion einsteigen.
quelle
Ich war in der Situation, in der ich für meine Fähigkeiten angeworben wurde. Als ich den Code sah, war es mehr als schrecklich. Wenn jemand dann versucht, es zu bereinigen, unterdrückt er die Änderungen immer, weil er die Vorteile nicht sieht. Es klingt wie etwas, das Sie beschreiben. Es endete damit, dass ich diese Position aufgab und ich kann mich jetzt viel besser in einem Unternehmen entwickeln, das eine bessere Praxis hat.
Ich denke nicht, dass Sie nur mit den anderen im Team zusammenarbeiten sollten, weil sie schon länger dort sind. Wenn Sie sehen, dass Ihre Teammitglieder in den Projekten, in denen Sie arbeiten, schlechte Praktiken anwenden, ist es eine Verantwortung, dass Sie darauf hinweisen, wie Sie es getan haben. Wenn nicht, sind Sie keine sehr wertvolle Ressource. Wenn Sie die Dinge immer wieder aufzeigen, aber niemand zuhört, bitten Sie das Management um einen Ersatz oder einen Jobwechsel. Es ist sehr wichtig, dass Sie sich nicht erlauben, sich an schlechte Praktiken anzupassen.
Zur eigentlichen Frage
Warum unveränderliche Objekte verwenden? Weil Sie wissen, womit Sie es zu tun haben.
Angenommen, Sie haben eine DB-Verbindung, über die Sie den Host über einen Setter ändern können. Dann wissen Sie nicht, um welche Verbindung es sich handelt. Unveränderlich sein, dann weißt du es.
Angenommen, Sie haben eine Datenstruktur, die aus der Persistenz abgerufen und dann mit neuen Daten erneut persistent gemacht werden kann. Dann ist es sinnvoll, dass diese Struktur nicht unveränderlich ist. Es ist dieselbe Entität, aber die Werte können sich ändern. Verwenden Sie stattdessen unveränderliche Wertobjekte als Argumente.
Worauf Sie sich konzentrieren, ist jedoch ein Builder-Muster, um Abhängigkeiten im Konstruktor zu beseitigen. Ich sage ein dickes NEIN dazu. Die Instanz ist offensichtlich schon zu komplex. Versuchen Sie nicht, es zu verstecken, es zu reparieren!
Tl; dr
Das Entfernen der Setter kann je nach Klasse korrekt sein. Das Builder-Muster löst das Problem nicht, sondern blendet es nur aus. (Schmutz unter dem Teppich ist immer noch vorhanden, auch wenn Sie ihn nicht sehen können.)
quelle
Während alle anderen Antworten sehr nützlich sind (nützlicher als meine), gibt es eine Eigenschaft von Buildern, die Sie noch nicht erwähnt haben: Indem Sie die Erstellung eines Objekts in einen Prozess umwandeln, können Sie komplexe logische Einschränkungen erzwingen.
Sie können beispielsweise festlegen, dass bestimmte Felder zusammen oder in einer bestimmten Reihenfolge festgelegt werden. In Abhängigkeit von diesen Entscheidungen können Sie sogar eine andere Implementierung des Zielobjekts zurückgeben.
Dies ist ein einfaches Beispiel, das wenig Sinn macht, aber alle drei Eigenschaften demonstriert: Das Zeichen wird immer zuerst festgelegt, die Bereichsgrenzen werden immer zusammen festgelegt und validiert, und Sie wählen Ihre Implementierung zum Zeitpunkt der Erstellung aus.
Es ist leicht zu erkennen, wie dies zu besser lesbarem und zuverlässigerem Benutzercode führen kann, aber wie Sie auch sehen können, hat dies einen Nachteil: sehr viel Builder-Code (und ich habe sogar die Konstruktoren weggelassen, um die Snippets zu verkürzen). Sie versuchen also, den Kompromiss zu berechnen, indem Sie Fragen stellen wie:
Ihre Kollegen haben einfach entschieden, dass der Kompromiss nicht vorteilhaft ist. Sie sollten die Gründe offen und ehrlich diskutieren, vorzugsweise ohne auf abstrakte Prinzipien zurückzugreifen, aber sich auf die praktischen Auswirkungen dieser oder jener Lösung konzentrieren.
quelle
Es hört sich so an, als ob diese Klasse tatsächlich mehr als eine Klasse ist, die in derselben Datei- / Klassendefinition zusammengefasst ist. Wenn es sich um ein DTO handelt, sollte es möglich sein, es auf einmal zu instanziieren und unveränderlich zu machen. Wenn Sie nicht alle Felder / Eigenschaften in einer Transaktion verwenden, verstößt dies mit ziemlicher Sicherheit gegen das Prinzip der Einzelverantwortung. Es könnte hilfreich sein, es in kleinere, zusammenhängendere, unveränderliche DTO-Klassen aufzuteilen. Lesen Sie Clean Code, wenn Sie dies noch nicht getan haben, damit Sie die Probleme und die Vorteile einer Änderung besser beschreiben können.
Ich glaube nicht, dass Sie Code auf dieser Ebene von einem Komitee entwerfen können, es sei denn, Sie sind im wahrsten Sinne des Wortes Mob-Programmierer (es hört sich nicht so an, als wären Sie in einem solchen Team) bestes Urteil, und nehmen Sie es dann auf das Kinn, wenn sich herausstellt, dass Sie es falsch beurteilt haben.
Solange Sie jedoch in der Lage sind, die potenziellen Probleme mit dem Code so zu artikulieren, wie er ist, können Sie immer noch darüber diskutieren, dass eine Lösung erforderlich ist , auch wenn Ihre nicht die akzeptierte ist. Den Menschen steht es dann frei, Alternativen anzubieten.
" Starke Meinungen, schwach gehalten " ist ein gutes Prinzip - Sie gehen mit Zuversicht vor, basierend auf dem, was Sie wissen, aber wenn Sie neue Informationen finden, die dem entgegenwirken, sind Sie bescheiden und treten zurück und diskutieren, was die richtige Lösung sein sollte Sein. Die einzig falsche Antwort ist, es noch schlimmer werden zu lassen.
quelle