Wie kann ich die Verwendung des Builder-Musters in meinem Team fördern?

22

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 " finalist 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 barwird, 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?
rath
quelle
6
Der Builder muss irgendwie Werte setzen. Es löst also nicht das Grundproblem.
Amy Blankenship
3
Was ist der Grund, warum das (gefährlichere / ausnahmewerfende) Zeug vor dem Aufruf von nicht verschoben werden kann setA?
Yatima2975
2
Nur 3 Zeilen Konstruktorparameter? Das ist nicht so schlimm.
pjc50
7
In jedem Software-Design gibt es immer Kompromisse zwischen Komplexität und Entkopplung. Obwohl ich denke, dass ich Ihnen persönlich zustimme, dass der Bauherr hier eine gute Lösung ist, zögert Ihr Kollege aus KISS-Gründen zu Recht. Ich verwalte Software, die so erstaunlich kompliziert ist, und ein Grund dafür ist, dass jeder neue Mitarbeiter abtrünnig wird und sagt: "Das ist blöd, ich mache das auf meine Art und Weise." Daher haben wir 5 Frameworks für die Planung Hintergrundjobs und 8 Methoden zum Abfragen einer Datenbank. Alles ist gut in Maßen und es gibt keine klare richtige Antwort in solchen Fällen.
Brandon
3
KISS ist ein Fuzzy-Konzept, modifizierbare Objekte sind eine von Entwicklern stark unterschätzte Quelle von Komplexität. Sie erschweren die Behandlung von Multithreading, Debugging und Ausnahmen wesentlich mehr als unveränderliche. Entweder ist das Objekt gültig oder es wird eine Ausnahme bei der Konstruktion erstellt (welcher Ort ist besser, um diese Ausnahme abzufangen?).
Alessandro Teruzzi

Antworten:

46

Da ich dachte, dass wir irgendwo anfangen müssen, habe ich es auf mich genommen, eine Klasse für Dateninhaber umzugestalten

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.

gbjbaanb
quelle
7
"Überraschung ist nur gut, wenn es sich um eine Party handelt" , das gilt eigentlich nicht für alle !! Ich würde aufhören zu jedem so genannten Freund sprechen , die mir eine Überraschung warf etwas , speziell eine Partei . Mit Menschen . Pfui.
Darkhogg
3
Wenn also jedes Refactoring- und Designmuster oder jede Entscheidung wie "Benutze ich hier Accessor und Mutator oder Builder-Muster?" Muss von einem Team genehmigt werden, wie werden sich Entwickler jemals befähigt fühlen, das Richtige zu tun? Wie werden Sie vorausschauende Veränderungen vornehmen, wenn alles von einem Ausschuss entworfen werden muss? Ich war in der Rolle des OPs, bevor ich mich gezwungen sah, sinnlosen Code (als der neue Typ) beizubehalten, vor dem alle anderen Angst hatten, ihn zu ändern, weil er konsistent ist . Konsistenz ist gut, aber nicht auf Kosten der Verbesserung.
Brandon
11
@Brandon nein, aber jede weitreichende Änderung, die sie betreffen wird, sollte. Wenn Sie einen Fehler beheben müssen, ist es nur ein weiteres Stück Code - keine große Sache. Wenn Sie eine Entscheidung treffen, die alle anderen betrifft, ist es zumindest höflich, ihnen zu sagen, was Sie tun. Sie können sich vom Team darauf einigen, Ihren sinnlosen Code zu ändern, und dann werden Ihre Änderungen zur neuen Konsistenz. Sie müssen nur mit Ihren Kollegen sprechen. Es ist nichts Schlimmes, zu sagen: "Ich werde das beschissene
Zugriffsmuster
13
@Brandon es gibt ein Sprichwort: "Der Weg zur Hölle ist mit guten Absichten gepflastert". Konsistenz ist nicht nur gut , sondern notwendig ! Stellen Sie sich vor, Sie möchten ein Entwicklerteam verwalten, das zusammen 20 Anwendungen verwaltet, von denen jede in einem anderen Stil und / oder in einer anderen Architektur geschrieben ist, da Vorlieben, aktuelle Technologien, Trends usw. das jeweils Beste vorschrieben. Das Team dazu zu bringen, sich darauf zu einigen, dass sich etwas ändern sollte, kann der Unterschied sein, ob der neue Mann akzeptiert wird, weil er ein langjähriges Problem behoben hat, oder ob er entlassen wird, weil er mit dem, was Sie für das Beste hielten , Kavalier ist .
DrewJordan
3
@Brandon - Wenn Sie versuchen, etwas zu reparieren, bei dem alle zustimmen, dass es falsch ist, dann haben Sie wahrscheinlich mehr Erfolg, wenn Sie sich für etwas entscheiden, bei dem alle zustimmen, dass es falsch ist, anstatt für etwas, das bestenfalls andere Lager hat Thema, wie Unveränderlichkeit. Ein gutes Design / eine gute Architektur macht die Unveränderlichkeit zu einem hohen Preis, für den es praktisch keine Belohnung gibt. Wenn Ihr Team also keine Probleme hat, weil es Setter verwendet, haben Sie überhaupt kein Problem behoben. OTOH, wenn dies eine Quelle für häufige Fehler war, dann scheinen die Auswirkungen eine Teamentscheidung zu rechtfertigen.
Dunk
21

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.

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.

Core-Dump
quelle
Du liegst absolut richtig. Ein kleiner Einwand: Es ist nicht der "alte Weg" gegen "mein neuer, super geiler neuer Weg". Ich bin mir völlig bewusst, dass ich unsinnig reden könnte. Mein Problem ist, dass ich als Entwickler stagnieren könnte, wenn ich weiterhin Software-Praktiken verwende, die alle im Unternehmen für schrecklich halten. Daher versuche ich, eine Veränderung einzuführen, auch wenn ich mich irre. (Die Aufgabe wurde durch die Anforderung ausgelöst, eine verwandte Klasse
umzugestalten.
@rath Werden keine neuen Codebasen entwickelt?
Biziclop
@biziclop Es werden neue Module in die alte Codebasis gesteckt. Ich habe kürzlich an einem gearbeitet. Glückliche Tage.
Rath
5
@rath Benötigen Sie vielleicht ein persönliches Projekt, an dem Sie in Ihrer Freizeit arbeiten können, um Ihre eigene Entwicklung voranzutreiben? Ich bin auch nicht von Ihrem "Builder" -Musterargument überzeugt. Die Getter / Setter scheinen auf der Grundlage der von Ihnen bereitgestellten Informationen eine einwandfreie Lösung zu sein. Denken Sie daran, dass Sie Ihrem Arbeitgeber und Ihrem Team gegenüber rechenschaftspflichtig sind. Ihre Priorität ist es, sicherzustellen, dass Ihre Arbeit für diejenigen von Nutzen ist, für die Sie verantwortlich sind.
Ben Cottrell
@rath Nun, auch wenn Sie sich nicht in einem "alten / neuen" Code befinden, ist es wichtig, wie er vom empfangenden Ende wahrgenommen wird, besonders wenn sie mehr Entscheidungsbefugnis haben als Sie. Es sieht so aus, als ob Sie Änderungen aus Ihrem eigenen Interesse und nicht für das Produkt, das Sie entwickeln, einführen möchten. Wenn jeder in der Firma die Praxis für schrecklich hält, wird sie sich irgendwann ändern, aber dies scheint keine Priorität zu haben.
Coredump
17

Wie kann ich die Verwendung des Builder-Musters in meinem Team fördern?

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.

Telastyn
quelle
Es ist ein großer Datenbehälter für Strings und andere Grundelemente. Es gibt nirgendwo eine Logik, die nicht einmal nach nulls usw. sucht. Es ist also nur reine Größe, nicht Komplexität an sich. Ich dachte, etwas zu tun builder.addA(a).addB(b); /*...*/ return builder.addC(c).build();wäre viel einfacher für die Augen.
Rath
8
@rath: Es ist ein großer Datenbehälter für Strings und andere Grundelemente . => dann hast du andere Probleme, hoffentlich interessiert es niemanden, ob das E-Mail-Feld versehentlich mit der Postadresse des Typen belegt wird ...
Matthieu M.
@MatthieuM. Ein Problem zu einer Zeit, nehme ich an :)
rath
@rath - Es scheint sicher, dass die Integration eines guten Validierungsprüfschemas weitaus nützlicher und einfacher gewesen wäre, als herauszufinden, wie das Builder-Muster in bereits vorhandenen Code zerlegt werden kann. Woanders hast du gesagt, du willst dich verbessern. Zu lernen, wie man mit geringstem Aufwand und mit den geringsten Konsequenzen den größtmöglichen Gewinn erzielt, ist definitiv ein Attribut, das entwickelt werden sollte.
Dunk
1
Ich habe soooooo viele Konstruktoren mit viel mehr Parametern. Notwendig in IoC-Mustern. Schlechte Verallgemeinerung in dieser Antwort.
Djechlin
16

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.

btilly
quelle
2
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
rath
2
@rath Denken Sie daran, dass andere Personen möglicherweise nicht aus Ihrem Buch lesen. Es ist möglich, dass die Person, über die Sie diskutieren, dies als eine Konfrontation betrachtet, die Ihren Zielen kontraproduktiv sein könnte.
Iker
2
@rath: Es gibt kein Richtig oder Falsch. Einfach Kompromisse eingehen. Und oft geht es bei den Kompromissen nicht nur um Code.
Marjan Venema
1
@Dunk Alles, was existiert, sind Kompromisse. Wir nennen sie richtig oder falsch, wenn die Kompromisse glasklar und offensichtlich einseitig sind. Es ist jedoch einfacher zu erkennen, wann dies nicht eindeutig ist, wenn wir uns von Anfang an darauf konzentriert haben, dass es sich um Kompromisse handelt.
btilly
2
Es gibt keine einzige "Best Practice" -Programmierung, von der ich weiß, dass sie keine Ausnahmen hat, bei denen sie nicht die beste ist. Manchmal ist es schwierig, diese Ausnahmen zu finden, aber sie existieren immer.
btilly
11

Gibt es ein anderes Argument für die Verwendung von Buildern anstelle des "alten Wegs"?

"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?

Lohnt sich die von mir vorgeschlagene Änderung überhaupt?

Es ist schwierig, aus diesem kleinen Code-Schnipsel zu unterscheiden. Vielleicht ist es das - Sie und Ihre Kollegen müssen es bewerten.

Haben Sie Tipps, wie Sie solche Argumente besser präsentieren können, wenn Sie sich dafür einsetzen, etwas Neues auszuprobieren?

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.

BЈовић
quelle
7

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.)

Superheld
quelle
Ich kenne die Details Ihrer Situation nicht, aber wenn Sie hereinkamen und versuchten, alles zu ändern, ohne zuerst das Vertrauen der Leute in Ihre Fähigkeiten zu gewinnen oder sich nicht die Zeit zu nehmen, zu lernen, warum sie Dinge so tun, wie sie es tun, dann wurden Sie genau behandelt so wie man bei so gut wie jeder firma behandelt wird, auch bei wirklich guten. Eigentlich vor allem bei richtig guten. Wenn die Leute Vertrauen in die Fähigkeiten einer Person haben, ist es einfach eine Frage der überzeugenden Argumentation für Ihre Vorschläge. Wenn Sie keine überzeugenden Argumente vorbringen können, ist es gut möglich, dass Ihr Vorschlag nicht so gut ist.
Dunk
1
Ich habe nicht versucht, alles zu ändern, ich habe versucht, es aufzuräumen. Und es waren nicht die Leute, die wussten, was sie taten, sie schufen stolz Klassen und Funktionen, die hundert Zeilen Code enthielten, mit idk wie vielen Staaten, global und so weiter. Also stehe ich zu meiner Aussage. Gehen Sie niemals zurück, wenn Sie bemerken, dass Sie sich in einer Position befinden, in der Sie sich an schlechte Praktiken
Superheld
@Dunk Versuche zu ändern, wie Leute Code als Teammitglied ist nicht das, was ich tue. Aber ich erzähle es ihnen von Anfang an. "Ich werde nicht in diesem Projekt arbeiten, ohne es komplett neu zu schreiben" , wenn der Code ein Stück Müll ist. Wenn das nicht angeeignet ist, dann ist es gegenseitig. Es geht nicht nur um Komfort, es geht darum, dass ich Verantwortung für das übernehmen muss, was ich produziere. Ich kann das nicht tun, wenn der umgebende Code im Projekt ein komplettes Durcheinander ist.
Superheld
Sie müssen nicht "für immer" mit Code arbeiten, der Müll ist, oder schlechten Praktiken folgen, nur weil es so gemacht wird. Wenn Sie es jedoch schaffen wollen, Dinge zu ändern, sollten Sie zuerst Ihre Glaubwürdigkeit beweisen. Fast jeder Entwickler denkt, Code, den er erbt, sei Müll. Wenn sich jedes Unternehmen nur jedes Mal mit dem neuen Kollegen einverstanden erklärt, ohne auch nur das wahre Können zu kennen, wird der Müll zu einer Müllhalde. Sie sollten sich auch die Zeit nehmen, um zu verstehen, warum die Dinge so gemacht werden, wie sie sind. Manchmal ist der "falsche" Weg der "richtige" Weg für eine bestimmte Situation.
Dunk
@Dunk Ich sehe, dass du eine andere Meinung hast als ich in dieser Angelegenheit. Ihre scheinen populärer zu sein, wenn Sie aus den anderen Antworten lesen. Ich bin nicht einverstanden, warum ich diese Antwort in Opposition geschrieben habe. Was Sie gesagt haben, hat meine Meinung nicht geändert.
Superheld
2

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.

// business objects

interface CharRange {
   public char getCharacter();
   public int getFrom();
   public int getTo();
}

class MultiCharRange implements CharRange {
   final char ch;
   final int from;
   final int to;

   public char getCharacter() { return ch; }
   public int getFrom() { return from; }
   public int getTo() { return to; }
}

class SingleCharRange implements CharRange {
   final char ch;
   final int position;

   public char getCharacter() { return ch; }
   public int getFrom() { return position; }
   public int getTo() { return position; }
}

// builders

class Builder1 {
   public Builder2 character(char ch) {
      return new Builder2(ch);
   }
}

class Builder2 {
   final char ch;
   int from;
   int to;

   public Builder2 range(int from, int to) {
      if (from > to) throw new IllegalArgumentException("from > to");
      this.from = from;
      this.to = to;
      return this;
   }

   public Builder2 zeroStartRange(int to) {
      this.from = 0;
      this.to = to;
      return this;
   }

   public CharRange build() {
      if (from == to)
         return new SingleCharRange(ch,from);
      else 
         return new MultiCharRange(ch,from,to);
   }
}

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:

  • Instanziieren wir das Objekt nur von einer oder zwei Stellen aus? Wird sich das ändern?
  • Vielleicht sollten wir diese Einschränkungen durchsetzen, indem wir das ursprüngliche Objekt in eine Komposition kleinerer Objekte umgestalten?
  • Würden wir am Ende den Builder von Methode zu Methode weitergeben?
  • Können wir stattdessen nur eine statische Factory-Methode verwenden?
  • Handelt es sich um einen Teil einer externen API, der so kinderleicht und einfach wie möglich sein muss?
  • Ungefähr wie viele unserer aktuellen Fehler könnten vermieden werden, wenn wir Bauherren hätten?
  • Wie viel zusätzlichen Dokumentationsaufwand würden wir einsparen?

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.

biziclop
quelle
1
Indem Sie die Erstellung eines Objekts in einen Prozess umwandeln, können Sie komplexe logische Einschränkungen erzwingen. BAM. Und das alles impliziert Komplexität, wenn es in kleinere, diskrete, einfachere Schritte unterteilt ist.
Radarbob
2

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.

Neil Barnwell
quelle
Es ist definitiv nicht das Design von Komitees, was ein Grund dafür ist, warum der Code so schlecht stinkt. Zu viel des Guten, nehme ich an. Es ist ein DTO, aber ich werde es nicht in Stücke zerbrechen; Wenn die Codebasis schlecht ist, ist die DB sehr viel schlechter. +1 (hauptsächlich) für den letzten Absatz.
Rath