Welche gängigen „Best Practices“ sind nicht immer die besten und warum? [geschlossen]


100

"Best Practices" gibt es in unserer Branche überall. Bei einer Google-Suche nach "Coding Best Practices" werden fast 1,5 Millionen Ergebnisse erzielt. Die Idee scheint vielen Trost zu bringen; Folgen Sie einfach den Anweisungen und alles wird gut.

Wenn ich über eine bewährte Methode lese - zum Beispiel habe ich kürzlich einige in Clean Code durchgelesen -, werde ich nervös. Bedeutet das, dass ich diese Praxis immer anwenden sollte? Sind an Bedingungen geknüpft? Gibt es Situationen, in denen dies möglicherweise keine gute Praxis ist? Wie kann ich sicher wissen, bis ich mehr über das Problem erfahren habe?

Einige der in Clean Code erwähnten Praktiken stimmten nicht mit mir überein, aber ich bin mir ehrlich gesagt nicht sicher, ob das daran liegt, dass sie möglicherweise schlecht sind oder ob das nur meine persönliche Voreingenommenheit ist. Ich weiß, dass viele Prominente in der Technologiebranche zu glauben scheinen, dass es keine Best Practices gibt. Zumindest bringen mich meine nörgelnden Zweifel in gute Gesellschaft.

Die Anzahl der Best Practices, über die ich gelesen habe, ist einfach zu groß, um sie hier aufzulisten oder einzelne Fragen zu stellen. Deshalb möchte ich dies als allgemeine Frage formulieren:

Welche als "Best Practices" bezeichneten Codierungsmethoden können unter bestimmten Umständen nicht optimal oder sogar schädlich sein? Was sind diese Umstände und warum machen sie die Praxis zu einer schlechten?

Ich würde gerne von konkreten Beispielen und Erfahrungen hören.


8
Mit welchen Praktiken sind Sie nicht einverstanden? Nur neugierig.
Sergio Acosta

Jeder kann ein Buch schreiben, dem muss ich nicht zustimmen - so einfach ist das.
Job

Eine Sache, die ich an dem Buch "Code Complete" von Steve McConnell mag, ist, dass er all seine Tipps mit harten Beweisen und Nachforschungen untermauert. Sag es einfach
JW01

5
@Walter: Das ist seit Monaten offen, es ist definitiv konstruktiv, warum es schließen?
Orbling

2
Angesichts der Tatsache, wie mein Name hier erwähnt wird, sollte ich mich einmischen: Ich glaube, dass die Antworten hier wertvoll sind, aber die Frage könnte in etwas definitiv weniger Abstimmungsmäßiges umformuliert werden, ohne dass eine der Antworten ungültig wird. Beispieltitel: "Welche gängigen 'Best Practices' können manchmal schädlich sein und wann / warum?"
Aaronaught

Antworten:


125

Ich denke, Sie haben mit dieser Aussage den Nagel auf den Kopf getroffen

Ich würde es hassen, Dinge zum Nennwert zu nehmen und nicht kritisch darüber nachzudenken

Ich ignoriere fast alle Best Practices, wenn es keine Erklärung gibt, warum sie existieren

Raymond Chen bringt es am besten in diesen Artikel, wenn er sagt

Guter Rat hat eine Begründung, damit Sie erkennen können, wann er zu einem schlechten Rat wird. Wenn Sie nicht verstehen, warum etwas getan werden sollte, sind Sie in die Falle der Frachtkultprogrammierung geraten und tun dies auch dann, wenn es nicht mehr erforderlich ist oder sogar schädlich wird.


4
Wunderbares Zitat.
David Thornley

Der nächste Absatz dieses Zitats von Raymond Chen beschreibt wahrscheinlich die ungarische Notation! Die meisten Unternehmen, die ich sehe, verwenden es ohne wirklich guten Grund, den sie erklären können.
Craig

3
Ich hoffe, die Leute nehmen dies nicht als Ausrede, um nicht nachzuschlagen, was die Gründe für die Best Practices sind. ;) Leider habe ich Entwickler mit dieser Einstellung gesehen.
Vetle

3
Begründung ist gut. Forschung ist besser.
Jon Purdy

7
Absolut wahr, und das habe ich auch schon gesagt. Vielleicht sollte die erste Norm in einem "Norm" -Dokument lauten: "Um Wissen auszutauschen und die Informationen bereitzustellen, die erforderlich sind, um Normen zu einem späteren Zeitpunkt aufzuheben, müssen alle Normen die Gründe für ihre Existenz enthalten."
Scott Whitlock

95

Könnte auch dies in den Ring werfen:

Premature optimization is the root of all evil.

Nein, ist es nicht.

Das vollständige Zitat:

"Wir sollten kleine Wirkungsgrade vergessen, sagen wir in 97% der Fälle: Vorzeitige Optimierung ist die Wurzel allen Übels. Dennoch sollten wir unsere Chancen bei diesen kritischen 3% nicht verpassen."

Dies bedeutet, dass Sie während Ihres gesamten Konstruktionsprozesses von spezifischen, strategischen Leistungsverbesserungen profitieren . Dies bedeutet, dass Sie Datenstrukturen und Algorithmen verwenden, die mit den Leistungszielen übereinstimmen. Dies bedeutet, dass Sie Überlegungen zum Design kennen, die sich auf die Leistung auswirken. Es bedeutet aber auch, dass Sie nicht leichtfertig optimieren, wenn Sie dies tun, was zu geringfügigen Gewinnen auf Kosten der Wartbarkeit führt.

Anwendungen müssen gut strukturiert sein, damit sie am Ende nicht herunterfallen, wenn Sie sie ein wenig belasten, und dann werden sie neu geschrieben. Das abgekürzte Zitat birgt die Gefahr, dass Entwickler es allzu oft als Ausrede benutzen, um überhaupt nicht an die Leistung zu denken, bis es zu spät ist, etwas dagegen zu unternehmen. Es ist besser, von Anfang an eine gute Leistung zu erzielen, vorausgesetzt, Sie konzentrieren sich nicht auf Kleinigkeiten.

Angenommen, Sie erstellen eine Echtzeitanwendung auf einem eingebetteten System. Sie wählen Python als Programmiersprache, weil "die vorzeitige Optimierung die Wurzel allen Übels ist". Jetzt habe ich nichts gegen Python, aber es ist eine interpretierte Sprache. Wenn die Rechenleistung begrenzt ist und eine bestimmte Menge an Arbeit in Echtzeit oder nahezu in Echtzeit erledigt werden muss und Sie eine Sprache wählen, die mehr Rechenleistung für die Arbeit erfordert als Sie, sind Sie königlich, weil Sie Jetzt muss ich mit einer fähigen Sprache von vorne anfangen.


4
+1 für die Starken Nein, ist es nicht.
Stephen

21
Aber wenn Sie bereits erkannt haben, dass eine bestimmte Optimierung innerhalb dieser kritischen 3% liegt, sind Sie verfrüht, sie zu optimieren?
John

7
@Robert: Worin besteht dann die Uneinigkeit mit der Aussage, dass "vorzeitige Optimierung die Wurzel allen Übels ist"?
John

8
Es ist nie verfrüht, anspruchsvolles Design und technische Entscheidungen wie die Sprachauswahl zu optimieren. Allerdings werden Ineffizienzen oft erst sichtbar, nachdem Sie ein Design größtenteils fertiggestellt haben. Aus diesem Grund schreibt Fred Brooks, dass die meisten Teams eine Wegwerfversion schreiben, unabhängig davon, ob sie dies beabsichtigen oder nicht. Ein weiteres Argument für das Prototyping.
Dominique McDonnell

8
@ Robert, das Knuth-Zitat wurde vorzeitig optimiert ...

94

Eine Rückgabe pro Funktion / Methode.


7
Ich würde das sagen. Ich liebe mich einige frühe Rückkehrerklärungen.
Carson Myers

4
Absolut! Die Leute erfinden einen ziemlich interessanten Programmablauf, um eine frühe returnAussage zu vermeiden . Entweder tief verschachtelte Kontrollstrukturen oder kontinuierliche Überprüfungen. Dies kann eine Methode wirklich aufblähen, wenn if returnsich dieses Problem wirklich vereinfachen lässt.
Snmcdonald

4
Wenn Sie mehrere Rückgaben in einer Funktion benötigen (abgesehen von Wachen), ist Ihre Funktion wahrscheinlich zu lang.
EricSchaefer

18
Es hat keinen Sinn, ein Return-Schlüsselwort zu haben, es sei denn, es sollte an mehreren Stellen erscheinen. Früh zurückkehren, oft zurückkehren. Es wird nur dazu dienen, Ihren Code weiter zu vereinfachen. Wenn die Leute verstehen können, wie break / continue-Anweisungen funktionieren, warum haben sie dann Probleme mit der Rendite?
Evan Plaice

7
Ich denke, dies ist eine sehr veraltete Best Practice. Ich denke nicht, dass es eine moderne Best Practice ist.
Skilldrick

87

Das Rad nicht neu erfinden ist ein häufig missbrauchtes Dogma. Wenn es eine geeignete Lösung gibt, verwenden Sie sie, anstatt Ihre eigene zu erstellen. Neben der Einsparung von Aufwand ist die vorhandene Lösung wahrscheinlich besser implementiert (fehlerfrei, effizient, getestet) als ursprünglich geplant. So weit, ist es gut.

Das Problem ist, dass eine 100% geeignete Lösung selten existiert. Möglicherweise gibt es eine zu 80% geeignete Lösung, und die Verwendung ist wahrscheinlich in Ordnung. Aber wie wäre es mit 60% geeignet? 40%? Wo ziehst du die Linie? Wenn Sie die Grenze nicht ziehen, können Sie eine aufgeblähte Bibliothek in Ihr Projekt einbinden, weil Sie 10% der Funktionen nutzen - nur weil Sie vermeiden möchten, das Rad neu zu erfinden.

Wenn Sie das Rad neu erfinden, erhalten Sie genau das, was Sie wollen. Sie lernen auch , wie man Räder herstellt. Learning by Doing sollte nicht unterschätzt werden. Und am Ende kann ein benutzerdefiniertes Rad durchaus besser sein als ein handelsübliches generisches Rad.


3
Ich habe das andersherum passieren lassen. Ich habe meine eigene Ajax-Grid-Komponente gebaut, weil es zu der Zeit keine gab, die das taten, was ich wollte, aber sie später durch Ext JS-Grids ersetzte. Es hat geholfen, dass ich von Anfang an davon ausgegangen bin, dass die Anzeigeebene ersetzt wird.
Joeri Sebrechts

20
Einverstanden. Wenn niemand das Rad neu erfinden würde, würden wir alle unsere Autos mit Holzreifen fahren.
Dr. Wily's Apprentice

6
Ich fühle mich immer wie Ihr 10% Beispiel, wenn ich einem C ++ - Projekt Boost hinzufüge. Ich brauche immer weniger als 10% davon, direkt, aber natürlich die Funktionen, die ich brauche, importieren andere Module, die andere Module importieren, die ...
Roman

3
+1: erst in dieser Woche habe ich das Rad neu erfunden (z. B. das aufgeblähte, aber beliebte JQuery-Plugin durch etwas zu ersetzen, das unseren Anforderungen entspricht, aber dennoch modular ist) und es hat zu enormen Leistungssteigerungen geführt. Es gibt auch Leute, die buchstäblich die Aufgabe haben, das Rad neu zu erfinden: Nehmen Sie zum Beispiel Michelin, sie betreiben Forschung und Entwicklung, um Reifen zu verbessern.
Wildpeaks

2
@DR. Wily, diese Räder wurden nicht neu erfunden, sie wurden überarbeitet!

78

"Unit Test Everything."

Ich habe oft gehört, dass jeder Code Unit-Tests haben sollte, ein Punkt, mit dem ich nicht einverstanden bin. Wenn Sie einen Test für eine Methode haben, muss jede Änderung an der Ausgabe oder Struktur dieser Methode zweimal vorgenommen werden (einmal im Code, einmal im Test).

Daher sollten Unit-Tests meiner Meinung nach proportional zur strukturellen Stabilität des Codes sein. Wenn ich ein geschichtetes System von Grund auf schreibe, wird meine Datenzugriffsebene das Wazoo testen. Meine Business-Logik-Ebene wird ziemlich gut getestet, meine Präsentations-Ebene wird einige Tests haben, und meine Ansichten werden kaum bis gar keine Tests haben.


7
Ich vermute, dass "Unit Test Everything" ein Klischee geworden ist, wie das Zitat "vorzeitige Optimierung". Ich stimme im Allgemeinen mit Ihren Proportionen überein und habe viele Beispiele von Entwicklern gesehen, die enorme Anstrengungen unternommen haben, um ein Objekt auf Anwendungsebene zu verspotten.
Robert Harvey

36
Wenn eine Änderung der Struktur einer Methode zu einer Änderung Ihrer Tests führt, führen Sie die Tests möglicherweise falsch aus. Unit-Tests sollten nicht die Implementierung verifizieren, sondern nur das Ergebnis.
Adam Lear

7
@Anna Lear: Ich denke, er sprach über Design- / Strukturänderungen (Refactoring). Da das Design nicht ausgereift genug ist, müssen Sie möglicherweise eine Menge Tests ändern, wenn Sie den besseren Weg finden, dies zu tun. Ich bin damit einverstanden, dass Sie, wenn Sie ein erfahrener Tester sind, leichter feststellen können, wo der Test eine schlechte Idee wäre (aus diesem Grund und aus anderen Gründen), aber wenn das Design nicht wirklich ausgereift ist, werden Sie höchstwahrscheinlich noch einige Tests im Test haben Weg.
n1ckp

13
Ich denke, das ist auch der Grund, warum die Idee "zuerst testen" nicht funktioniert. Um die Tests durchführen zu können, muss das Design stimmen. Aber um das richtige Design zu haben, müssen Sie Dinge ausprobieren und sehen, wie sie funktionieren, damit Sie sie verbessern können. Daher können Sie die Tests nicht wirklich durchführen, bevor Sie das Design erstellt haben. Um das richtige Design zu erhalten, müssen Sie programmieren und sehen, wie es funktioniert. Wenn Sie keinen wirklich überragenden Architekten haben, sehe ich nicht wirklich, wie diese Idee funktionieren wird.
n1ckp

13
@ n1ck TDD ist eigentlich keine Testaufgabe, sondern eine Entwurfsaufgabe. Die Idee ist, dass Sie Ihr Design durch Tests weiterentwickeln (da dies schnell eine vernünftige API für Ihre Inhalte verfügbar macht), anstatt die Tests an ein vorhandenes Design anzupassen (was möglicherweise schlecht oder unzureichend ist). Nein, Sie müssen nicht über das erforderliche Design verfügen, um die Tests zuerst durchführen zu können.
Adam Lear

57

Immer auf Schnittstellen programmieren.

Manchmal wird es nur eine Implementierung geben. Wenn wir den Vorgang des Extrahierens einer Schnittstelle bis zu dem Zeitpunkt verzögern, an dem wir den Bedarf erkennen, werden wir häufig feststellen, dass dies nicht erforderlich ist.


4
Einverstanden, programmieren Sie auf eine Schnittstelle, wenn Sie eine Schnittstelle benötigen (dh eine stabile API, von der aus Sie arbeiten können).
Robert Harvey

45
In meiner Lektüre geht es bei dieser Regel nicht um Schnittstellen als Sprachkonstrukte. Dies bedeutet, dass Sie beim Aufrufen der Methoden keine Annahmen über die Funktionsweise einer Klasse treffen und sich nur auf die API-Verträge verlassen sollten.
Zsolt Török

2
Ok, hier ist eine interessante Frage: Ich bin hauptsächlich ein .NET-Entwickler, daher sehen meine Schnittstellen für mich wie IBusinessManager oder IServiceContract aus. Für mich ist das extrem einfach zu navigieren (und ich behalte meine Schnittstellen im Allgemeinen in einem anderen Namespace [oder sogar in einem anderen Projekt]). Wenn ich Java verwendet habe, fand ich das tatsächlich verwirrend (im Allgemeinen sind Schnittstellenimplementierungen mit dem Suffix .impl versehen - und Schnittstellen haben keine Abgrenzung). Könnte dies also ein Problem mit den Codestandards sein? Natürlich lassen Interfaces in Java den Code unübersichtlich erscheinen - sie sehen auf den ersten Blick genauso aus wie normale Klassen.
Watson

5
@ Watson: Eine der Kosten ist, dass ich jedes Mal, wenn ich bei einem Methodenaufruf in Eclipse die Taste F3 ('Zur Deklaration springen') drücke, zur Schnittstelle und nicht zur einen Implementierung springe. Ich muss dann T (Abwärtspfeil) drücken und zurückkehren, um zur Implementierung zu gelangen. Außerdem werden einige automatische Refactorings blockiert. Sie können beispielsweise keine Methode über eine Schnittstellendefinition hinweg einbinden.
Tom Anderson

4
@Tom: Nun, Sir, ich würde Sie gerne in diesen Krieg verwickeln, Eclipse vs. Intellij - aber ich habe einen hervorragenden Moralkodex, der mich daran hindert, mit jemandem in physische Konfrontationen zu geraten, der ein offensichtliches Handicap hat. BOOM. Ich sage nicht, dass Eclipse schlecht ist, ich sage, wenn die Achsenmächte es benutzt hätten, um ihre Kriegsmaschinen zu bauen oder zu konstruieren, würde der Zweite Weltkrieg jetzt als "zweitägiges Kerfuffle" bezeichnet. Im Ernst, ich habe festgestellt, dass es an etwas Glanz mangelt, den ich in handelsüblichen IDEs (Intellij / VS + ReSharper) bekomme. Ich habe mehr als einmal dagegen gekämpft - das ist einer zu viel.
Watson

46

Verwenden Sie nichts Open-Source (oder Nicht-Microsoft für Sie .NET-Entwickler)

Wenn Microsoft es nicht entwickelt hat, verwenden wir es hier nicht. Möchten Sie ORM - EF verwenden, IOC - Unity verwenden, protokollieren - Anwendungsblock für die Unternehmensprotokollierung. Es gibt so viele bessere Bibliotheken - aber ich bin immer dabei, aus dem Dollar-Menü der Entwicklungswelt zu bestellen. Ich schwöre, jedes Mal, wenn ich Microsoft Best Practices höre, denke ich "McDonald's Nutritional Guidelines". Sicher, du wirst wahrscheinlich leben, wenn du ihnen folgst, aber du wirst auch unterernährt und übergewichtig sein.

  • Hinweis : Dies ist möglicherweise nicht Ihre beste Praxis, aber es ist ein allgemeiner fast überall folgte ich gearbeitet habe.

13
Klingt schrecklich ... = (Ich bin wahrscheinlich zu sehr auf der anderen Seite, aber ich vermeide M $ so weit wie möglich.
Lizzan

Das sollte nicht so sein. Eine Bibliothek sollte nach ihrem Wert ausgewählt werden, nicht nur nach dem, wer sie erstellt hat. Ich liebe EF, habe aber schlechte Erfahrungen mit Enterprise Library gemacht und bessere Tools für die Validierung und Protokollierung gefunden, z. B. FluentValidation, log4net und Elmah.
Matteo Mosca

4
Sie werden nicht für den Kauf von IBM ^ wMicrosoft
Christopher Mahan

17
Es gibt auch die Mirror-Image-Version, dh Niemals etwas von Microsoft oder nichts, wofür Sie bezahlen müssen.
Richard Gadsden

5
Ich habe das Glück, in einer Organisation zu arbeiten, in der dies kein weit verbreitetes Dogma ist, aber an den Orten, an denen wir kommerzielle Lösungen übernommen haben, ist das mit Sicherheit sehr schmerzhaft. Das Problem tritt auf, wenn ein Teil der kommerziellen Lösung nicht richtig funktioniert. Wenn es sich um Open Source handelt, können Sie sich die Quelle (die ultimative Dokumentation) ansehen und herausfinden, was falsch läuft. Bei Closed Source müssen Sie für das Privileg bezahlen, auf das Wissen des technischen Supports zuzugreifen, der noch weniger über das Produkt weiß, das Sie anbieten. Und das ist die einzige verfügbare "Lösung".
SingleNegationElimination

40

Objektorientierung

Es gibt die Annahme, nur weil Code "objektorientiert" ist, ist es magisch gut. Daher werden Funktionen in Klassen und Methoden eingeteilt, nur um objektorientiert zu sein.


7
Ich kann mir nicht vorstellen, ein Softwaresystem von bedeutender Größe zu erstellen, ohne die Vorteile der Objektorientierung zu nutzen.
Robert Harvey

18
Robert. Unix ist nicht objektorientiert und es eignet sich mit Sicherheit als Software-System von beträchtlicher Größe. Es scheint auch sehr beliebt zu sein (man denke an Mac OSX, iPhone, Android-Handys usw.)
Christopher Mahan

7
Was ich meinte ist, dass ich denke, wir sollten die am besten geeignete Methodik verwenden. Ich habe Leute gesehen, die Methoden und Klassen verwendeten, bei denen dies umständlich und nicht sehr sinnvoll war, nur weil es "objektorientiert" war. Das ist Ladungskult.
LennyProgrammers

8
Es gibt keine Silberkugel. Funktionale Programmierung (Haskell) ist sehr erfolgreich, ohne objektorientiert zu sein. Letztendlich haben Sie mehrere Tools und es ist Ihre Aufgabe, das beste Sortiment für die jeweilige Aufgabe auszuwählen.
Matthieu M.

9
Das Lustige ist, dass neben der Verwendung von Klassen, Polymorphismus und dergleichen der größte Teil des objektorientierten Codes tatsächlich prozeduraler Code ist.
Oliver Weiler

35

Der gesamte Code sollte kommentiert werden.

Nein, das sollte nicht sein. Manchmal haben Sie offensichtlichen Code, zum Beispiel sollten Setter erst kommentiert werden, wenn sie etwas Besonderes tun. Auch warum sollte ich das kommentieren:

/** hey you, if didn't get, it's logger. */
private static Logger logger = LoggerFactory.getLogger(MyClass.class);

13
Der gesamte Code sollte verständlich sein . Kommentare sind dabei ein wichtiges Instrument, aber bei weitem nicht das einzige.
Trevel

Absulut sollte Code verständlich sein. Es gibt jedoch keinen einzigen Grund, einen Kommentar zu verfassen, der beispielsweise dem Methodennamen nichts hinzufügt. Wenn du schreibst, /** sets rank. */ void setRank(int rank) { this.rank = rank; }nehme ich den Kommentar als dumm an. Warum steht es geschrieben?
Vladimir Ivanov

2
Generierte Dokumentation. Dafür steht das /** */Format anstelle des /* */Formatkommentars. Oder für .NET wäre es///
Berin Loritsch

10
Mit }//end if, }//end for, }//end whileist das beste Beispiel für Verschwendung kommentiert ich je erlebt habe. Ich habe dies oft gesehen, wo die öffnende Klammer nicht mehr als 2 Zeilen höher ist. IMHO , wenn Sie benötigen diese Kommentare dann Ihren Code Bedürfnisse Refactoring ... oder Sie müssen $ 20 Pony und ein IDE / Text - Editor die die Klammern Highlights entsprechen.
Scunliffe

7
Code sagen "wie". Kommentare müssen "warum" sagen.

32

Methoden, insbesondere Scrum. Ich kann kein ernstes Gesicht behalten, wenn Erwachsene den Satz "Scrum Master" verwenden. Ich habe es so satt, Entwickler zu hören, die protestieren, dass ein Aspekt von Methodology X nicht für ihr Unternehmen funktioniert, nur um von Guru So-and-So zu erfahren, dass es nicht funktioniert, weil sie in der Tat keine wahren Praktiker sind of Methodology X. "Scrum härter, mein Padawan Lerner!"

In agilen Methoden steckt ein Haufen Weisheit - viele von ihnen -, aber sie sind oft in so viel Mist eingelegt, dass ich meinen Würgereflex nicht bekämpfen kann. Nehmen Sie dieses Bit aus Wikipedia Scrum-Seite :

In Scrum sind eine Reihe von Rollen definiert. Alle Rollen fallen in zwei unterschiedliche Gruppen - Schweine und Hühner -, basierend auf der Art ihrer Beteiligung am Entwicklungsprozess.

"Ja wirklich?" Schweine und Hühner, sagst du? Faszinierend! Ich kann es kaum erwarten, meinem Chef das hier vorzustellen ...


Interessant. Ich stimme in gewissem Umfang zu. Mit dem letzten Teil: Nennen Sie sie, wie Sie wollen, sie sind Mnemonics, das ist alles.
Steven Evers

12
+1 ... du hast recht, es ist schwer, das ernst zu nehmen. <große dröhnende Stimme> * I AM THE SCRUMMASTER * </ voice>
GrandmasterB

2
Und die Gleichnisse. Es erinnert mich an Predigten in der Kirche oder an die Art von Anekdoten, für die Selbsthilfegurus (und Komiker) berühmt sind: "Nehmen Sie meinen Freund Steve. Steve stritt sich ständig mit seiner Frau Sheryl der Punkt, an dem ihre Ehe wirklich in Gefahr war. Dann, eines Tages ... "Diese Art von didaktischen Garnen stört mich in anderen Bereichen nicht, aber ich hasse es zu sehen, dass sie sich in den Ingenieurwissenschaften vermehren.
Evadeflow

2
Was ist mit den Scrum Ninjas?
Berin Loritsch

1
Ich bin mit dem Vergleich "Schwein und Huhn" nicht einverstanden ... er steht dem Agilen Manifest direkt gegenüber. Nämlich "Customer Collaboration over Contract Negotiation". Kunden sind am Erfolg des Projekts genauso interessiert (wenn nicht sogar mehr) wie das Projektteam. Das Nennen einiger Rollen Schweine und anderer Rollen Hühner stellt eine "Wir gegen Sie" -Mentalität auf, dass IMHO die größte Hürde für erfolgreiche Projekte ist.
Michael Brown

25

Objektrelationale Zuordnung ... http://en.wikipedia.org/wiki/Object-relational_mapping

Ich möchte nie von meinen Daten abgezogen werden, noch möchte ich diese präzise Kontrolle und Optimierung verlieren. Meine Erfahrung mit diesen Systemen war äußerst schlecht ... Die von diesen Abstraktionsebenen generierten Abfragen sind noch schlimmer als die, die ich vom Offshoring gesehen habe.


19
Vorzeitige Optimierung ist die Wurzel allen Übels. Langsamer Code ist im wirklichen Leben nur sehr selten ein Problem im Vergleich zu nicht wartbarem Code. Verwenden Sie ein ORM, und schneiden Sie die Abstraktion nur dort durch, wo Sie sie benötigen.
Fishtoaster

28
ORMs sind ein 80-20-Tool. Sie sollen die 80% CRUD bewältigen, die so mühsam wird, nach einer Weile den ganzen endlosen Code für die Installation zu schreiben. Die anderen 20% können auf "konventionellere" Art und Weise ausgeführt werden, beispielsweise mit gespeicherten Prozeduren und dem Schreiben gewöhnlicher SQL-Abfragen.
Robert Harvey

18
@Fishtoaster: Meinen Sie nicht, "Wir sollten in 97% der
Robert Harvey

5
@ Robert Harcey: Es gibt einen Grund, warum ich kein direktes Zitat verwendet habe. Ich denke, die meisten Programmierer konzentrieren sich viel zu sehr auf Effizienz - es ist ein Problem, das nur wenige von ihnen wirklich lösen müssen. Zugegeben, es gibt bestimmte Bereiche, in denen es wichtiger ist als in anderen, aber Wartbarkeit und Erweiterbarkeit sind überall ein Problem. Ein weiteres modifiziertes Zitat: „Machen Sie es funktioniert, es wartbar machen, es lesbar machen, ist es erweiterbar machen, es testbar machen, und dann , wenn Sie Zeit haben und es stellt sich heraus Sie es brauchen, es schnell machen.“
Fishtoaster

12
@Craig: Wie hast du die Ironie in deiner Aussage nicht erkannt? Es ist ein hervorragendes Argument gegen ORMs, ein Jahr zu brauchen, um zu lernen, wie man eine gute Leistung aus einem ORM herausholt, ebenso wie die Notwendigkeit, die von SQL erzeugten und gespeicherten Prozeduren zu "kontrollieren". Wenn Sie das Wissen dafür haben, haben Sie das Wissen, den ORM vollständig zu umgehen.
Nicholas Knight

22

Funktionsnamen so schreiben, als wären sie englische Sätze:

Draw_Foo()
Write_Foo()
Create_Foo()

usw. Das mag toll aussehen, aber es ist ein Schmerz, wenn Sie eine API lernen. Wie viel einfacher ist es, einen Index nach "Alles, was mit Foo beginnt" zu durchsuchen?

Foo_Draw()
Foo_Write()
Foo_Create()

usw.


2
Wahrscheinlich so einfach wie die Eingabe von Foo in die Funktionsliste von TM.
Josh K

68
Klingt so, als würdest du eigentlich wollen, dass es so ist Foo.Draw(), Foo.Write()und Foo.Create()so, dass du es tun Foo.methods.sortFoo.methods.grep([what I seek]).sort
könntest

7
Das Beginnen mit 'Get' ist ein weiteres Beispiel.
JeffO

1
Ich komme aus der Welt von Objective-C und vermisse sehr wörtliche Methodennamen und die Notation von Infixen, wenn ich Java (mein anderes Leben) mache. Seit die Code-Vervollständigung funktioniert hat, habe ich auch kein Problem mit der zusätzlichen Eingabe festgestellt.

2
@ Scott Whitlock: Nicht , dass für einige .NET - Entwickler veraltet, iirc, VS 2008 nicht getan. 2010 tut es aber und es ist fantastisch.
Steven Evers

22

MVC - Ich stelle oft fest, dass es bei vielen Webdesign-Problemen im MVC-Ansatz mehr darum geht, ein Framework (Schienen usw.) glücklich zu machen, als um Einfachheit oder Struktur. MVC ist ein Favorit von "Architektur-Astronauten", die offenbar übermäßiges Gerüst gegenüber Einfachheit schätzen. ymmv.

Klassenbasiertes OO - fördert meiner Meinung nach komplexe Strukturen des veränderlichen Zustands. Die einzigen überzeugenden Fälle, die ich im Laufe der Jahre für klassenbasierte OO gefunden habe, sind die kitschigen Beispiele für "Form-> Rechteck-> Quadrat", die Kapitel 1 jedes OO-Buches bilden


4
Ich habe die Webentwicklung in ASP.NET und ASP.NET MVC durchgeführt, und obwohl MVC als Gerüst betrachtet wird, bevorzuge ich es aus vielen Gründen gegenüber ASP.NET: Einfachheit, Wartbarkeit und äußerst feine Kontrolle über das Markup. Alles hat seinen Platz und obwohl sich alles ein bisschen zu wiederholen scheint, ist es eine Freude zu pflegen. Es ist vollständig anpassbar. Wenn Sie ein Verhalten nicht sofort mögen, können Sie es ändern.
Robert Harvey

1
Was OO betrifft, gibt es gute und schlechte Möglichkeiten, dies zu tun. Vererbung wird überbewertet und in der realen Welt sparsamer eingesetzt, als die meisten Bücher vermuten lassen. Selbst in der OO-Welt gibt es derzeit einen Trend zu einem funktionaleren, unveränderlichen Entwicklungsstil.
Robert Harvey

1
+1 für die Erwähnung von MVC. Während das Konzept von MVC (Trennung von Datenschichtlogik, Präsentationslogik und Hintergrundlogik) eine gute Idee ist, diese physisch in eine komplexe Ordnerhierarchie mit einem Durcheinander von Dateien zu trennen, die Code-Schnipsel enthalten, ist es dumm. Ich beschuldige das ganze Phänomen des fehlenden Namespace-Supports von PHP und der Neulinge, die jahrzehntealte Techniken als "das Neueste" verherrlichen. Es ist ganz einfach, einen Namespace für die Datenbankzugriffsberechtigten, die grafische Benutzeroberfläche und die Hintergrundlogik (und ggf. untergeordnete Namespaces) zu erstellen.
Evan Plaice

3
Was OO betrifft, werden Sie seine Vorteile erst dann wirklich erkennen, wenn Ihr Projekt eine Größe erreicht, bei der die Verwaltung der Komplexität wichtig wird. Befolgen Sie nach Möglichkeit das Prinzip der einheitlichen Verantwortung, und verbergen Sie, wenn Ihr Code öffentlich zugänglich ist (z. B. eine DLL), die interne Implementierung von Klassen / Methoden / Eigenschaften, wo immer dies möglich ist, um den Code sicherer zu machen und die API zu vereinfachen.
Evan Plaice

1
Ich persönlich finde das Beispiel Form-> Rechteck-> Quadrat eines der elegantesten Argumente gegen oop. zum Beispiel dazu reicht Square(10).Draw()es aus Rectangle(10, 10).Draw(). Das heißt also, Quadrat ist eine Unterklasse des Rechtecks. Aber es mySquare.setWidthHeight(5,10)ist Unsinn (IE, es misslingt das Liskov-Substitutionsprinzip), ein Quadrat kann keine unterschiedliche Höhe und Breite haben, obwohl ein Rechteck dies kann, was impliziert, dass das Rechteck eine Unterklasse des Quadrats ist. Dies wird in anderen Zusammenhängen als "Kreis-Ellipsen-Problem" bezeichnet
SingleNegationElimination

22

YAGNI

( Du wirst es nicht brauchen )

Dieser Ansatz hat mich Stunden und Stunden gekostet, als ich Funktionen auf einer vorhandenen Codebasis implementieren musste, wo sorgfältige Planung diese Funktionen zuvor einbezogen hätte.

Meine Ideen wurden oft wegen YAGNI abgelehnt, und meistens musste jemand später für diese Entscheidung bezahlen.

(Natürlich könnte man argumentieren, dass eine gut gestaltete Codebasis auch das spätere Hinzufügen von Funktionen ermöglichen würde, aber die Realität sieht anders aus.)


15
Ich stimme YAGNI zu, aber ich verstehe, worauf du hinaus willst. Der Sinn von YAGNI ist es, mit Menschen umzugehen, die alles bis ins kleinste Detail planen wollen . In neun von zehn Fällen wird dies jedoch als Ausrede dafür verwendet, unterentwickelten Code zu verwenden oder die Planung vollständig zu überspringen.
Jason Baker

12
P.Floyd, @Jason Baker: +1 Absolut richtig. Hier gilt das alte Sprichwort: "Monate im Labor können Stunden in der Bibliothek sparen"
Steven Evers

Eine Spezifikation wird (und sollte) oft den größten Teil der Implementierung und einen Teil der Schnittstelle offen lassen. Alles, was nicht direkt in der Spezifikation enthalten ist, aber für die Implementierung der Spezifikation erforderlich ist, ist auch eine indirekte Anforderung der Spezifikation, unabhängig davon, ob eine Implementierungsentscheidung, eine vom Benutzer sichtbare Schnittstelle oder etwas anderes vorliegt. Wenn ein Merkmal nicht in der Spezifikation enthalten ist und von der Spezifikation nicht impliziert wird, benötigen Sie es nicht. Wie kann das jemals verwirrend sein?
SingleNegationElimination

1
@TokenMacGuy der entscheidende Aspekt ist der durch die Spezifikation implizierte Teil. Da sind die Meinungen sehr unterschiedlich.
Sean Patrick Floyd

20

Für SQL

  1. Verwenden Sie keine Trigger
  2. Verstecken Sie Tabellen immer hinter Ansichten

In Ordnung:

  1. Sie sind ein Feature, das seinen Platz hat. Sie haben mehrere Aktualisierungspfade zu einer Tabelle oder müssen zu 100% überwacht werden?

  2. Warum nur? Ich würde, wenn ich umgestalten würde, um einen Vertrag beizubehalten, aber nicht, wenn ich gelesen habe, dass Leute die Ansicht ändern, um mit irgendwelchen Tabellenänderungen übereinzustimmen

Bearbeiten:

Nummer 3: Vermeiden Sie * mit EXISTEN. Versuchen Sie es mit 1/0. Es klappt. Die Spaltenliste wird nicht nach SQL-Standard ausgewertet. Seite 191


3
# 2 ist eine bewährte Methode?
Hogan


1
@Hogan: Eine Ansicht, die einfach eine Basistabelle spiegelt, bietet keine Sicherheit für die direkte Verwendung der Basistabelle. Wenn Sie einer Securityuser-Tabelle beitreten oder einige Spalten maskieren, ist dies fair genug. WÄHLEN Sie jedoch jede Spalte aus der Tabelle oder Ansicht aus: kein Unterschied. Persönlich verwende ich sowieso gespeicherte Procs.
27.

3
@Hogan: Ich weiß etwas über SQL Server :-) stackoverflow.com/users/27535/gbn Was ich meine ist GRANT SELECT auf dem Tisch ist nicht anders SELECT ON VIEW zu erteilen , wenn die Ansicht SELECT * FROM TABLE
gbn

1
@gbn: Ich stimme zu. Da gibt es keinen Unterschied. Ich denke, wir könnten dasselbe sagen. Mein ursprünglicher Kommentar ("# 2 ist eine bewährte Methode?") Basierte eher auf meiner persönlichen Erfahrung, dass Ansichten (wie Auslöser) häufiger missbraucht werden als richtig verwendet. Daher würde eine solche bewährte Methode nur zu Missbrauch und nicht zu einer Verbesserung führen. Wenn es sich um eine bewährte Methode handelt, haben Sie zu 100% Recht, es ist eine schlechte.
Hogan

20

Meist Design Patterns. Sie sind überstrapaziert und unterstrapaziert.


13
+1 Ich sehe immer noch nicht, wie Design Patterns schöne oder elegante Lösungen sind. Sie sind Workarounds für Sprachmängel, mehr nicht.
Oliver Weiler

2
Betrachten Sie es einfach als ein Bestreben, den Sprachgeruch mit der Sprache selbst zu beseitigen.
Filip Dupanović

15

Das Prinzip der Einzelverantwortung

("Jede Klasse sollte nur eine einzige Verantwortung haben. Mit anderen Worten, jede Klasse sollte einen und nur einen Grund haben, sich zu ändern.")

Ich stimme dir nicht zu. Ich denke, eine Methode sollte nur einen Grund haben, sich zu ändern, und alle Methoden in einer Klasse sollten eine logische Beziehung zueinander haben , aber die Klasse selbst könnte tatsächlich mehrere (verwandte) Dinge tun .

Nach meiner Erfahrung wird dieses Prinzip zu oft zu eifrig angewendet, und Sie haben am Ende viele winzige Ein-Methoden-Klassen. Beide agilen Shops, in denen ich gearbeitet habe, haben dies getan.

Stellen Sie sich vor, die Ersteller der .Net-API hätten diese Art von Mentalität: Anstelle von List.Sort (), List.Reverse (), List.Find () usw. hätten wir die Klassen ListSorter, ListReverser und ListSearcher!

Anstatt weiter gegen die SRP zu argumentieren (was theoretisch nicht schrecklich ist) , möchte ich einige meiner langwierigen anekdotischen Erfahrungen mitteilen:


An einer Stelle, an der ich gearbeitet habe, habe ich einen sehr einfachen Max-Flow-Löser geschrieben, der aus fünf Klassen bestand: einem Knoten, einem Diagramm, einem Diagrammersteller, einem Diagrammlöser und einer Klasse, um mit dem Diagrammersteller / -löser a zu lösen reales Problem. Keiner war besonders komplex oder lang (der Löser war mit ~ 150 Zeilen bei weitem der längste). Es wurde jedoch entschieden, dass die Klassen zu viele "Verantwortlichkeiten" hatten, also begannen meine Mitarbeiter mit der Umgestaltung des Codes. Als sie fertig waren, waren meine 5 Klassen auf 25 Klassen erweitert worden, deren gesamte Codezeilen mehr als das Dreifache dessen waren, was sie ursprünglich waren. Der Ablauf des Codes war nicht mehr offensichtlich, noch war der Zweck der neuen Unit-Tests; Es fiel mir jetzt schwer, herauszufinden, was mein eigener Code tat.


Am selben Ort hatte fast jede Klasse nur eine einzige Methode (ihre einzige "Verantwortung"). Es war fast unmöglich, dem Ablauf innerhalb des Programms zu folgen, und die meisten Unit-Tests bestanden darin, zu testen, ob diese Klasse Code aus einer anderen Klasse nannte , deren Zweck für mich gleichermaßen ein Rätsel war. Es gab buchstäblich Hunderte von Klassen, in denen es (IMO) nur Dutzende geben sollte. Jede Klasse hat nur eine "Sache" gemacht , aber selbst mit Namenskonventionen wie "AdminUserCreationAttemptorFactory" war es schwierig, die Beziehung zwischen Klassen zu bestimmen .


An einem anderen Ort (der auch die Mentalität hatte, nur eine Methode zu haben ) versuchten wir, eine Methode zu optimieren, die während einer bestimmten Operation 95% der Zeit in Anspruch nahm. Nachdem ich es (ziemlich dumm) ein wenig optimiert hatte, wandte ich mich der Frage zu, warum es eine Bajillion Mal genannt wurde. Es wurde in einer Schleife in einer Klasse aufgerufen ... deren Methode in einer Schleife in einer anderen Klasse aufgerufen wurde .. die auch in einer Schleife aufgerufen wurde ..

Insgesamt gab es fünf Ebenen von Schleifen, die (im Ernst) auf 13 Klassen verteilt waren. Es war unmöglich festzustellen, was eine Klasse tatsächlich tat, wenn man sie sich nur ansah - man musste ein mentales Diagramm darüber erstellen, welche Methoden sie nannte und welche Methoden diese Methoden nannten und so weiter. Wenn alles in eine Methode zusammengefasst worden wäre, wären es nur etwa 70 Zeilen gewesen, wenn unsere Problemmethode in fünf unmittelbar offensichtlichen Schleifenebenen verschachtelt gewesen wäre.

Meine Bitte, diese 13 Klassen in eine Klasse umzugestalten, wurde abgelehnt.


6
Klingt so, als hätte jemand bei diesem Job "Pattern Fever" oder in diesem Fall "Principle Fever". Die Listenklasse verletzt SRP nicht. Alle Funktionen dienen einem Zweck: Manipulieren einer Sammlung von Objekten. Nur eine Funktion in einer Klasse zu haben, klingt für mich übertrieben. Das Prinzip hinter SRP ist, dass eine Codeeinheit (ob Methode, Klasse oder Bibliothek) eine einzige Verantwortung haben sollte, die kurz und bündig angegeben werden kann.
Michael Brown

3
Ich habe angefangen, diese Art von Wahnsinn von Leuten zu sehen, denen es unmöglich ist, reinen funktionalen Code zu schreiben. Zu viel Aufklärung, dass jedes Problem auf der Welt aus einem Musterbuch gelöst werden kann. Nicht genug über Pragmatismus nachgedacht. Wie Sie habe ich einen klassenbasierten OO-Code gesehen, der so schrecklich ist, dass es völlig unmöglich ist, ihm zu folgen. Und es ist riesig und aufgebläht.
quick_now

3
2. Kommentar hier. Viele "Prinzipien" werden zu stark angewendet. Es gibt viele gute Ideen, bei denen es manchmal angebracht ist, genau das Gegenteil zu tun. GUTE Programmierer wissen, wann die Regeln brechen. Da es sich bei den Regeln nicht um "Regeln" handelt, handelt es sich meistens um Aussagen zu "bewährten Praktiken", es sei denn, dies ist eine wirklich blöde Idee.
quick_now

"Stellen Sie sich vor, die Ersteller der .Net - API hätten diese Art von Mentalität: Anstelle von List.Sort (), List.Reverse (), List.Find () usw. hätten wir die Klassen ListSorter, ListReverser und ListSearcher ! " Dies ist genau das, was in C ++ gemacht wird, und es ist wunderbar . Die Algorithmen sind von den Datenstrukturen getrennt. Wenn ich also meinen eigenen Container schreibe, funktionieren alle Algorithmen, die mit der Standardbibliothek funktionieren, nur mit meinem neuen Container. In .Net-Ländern muss es schrecklich sein, für jeden neuen Container, den Sie sortieren möchten, eine neue Sortierfunktion zu schreiben.
Mankarse

14

Nun, da Sie Clean Code erwähnt haben, obwohl es einige gute Ideen enthält, denke ich, dass seine Besessenheit, alle Methoden in Submethoden und jene in Submethoden usw. umzuwandeln, viel zu weit gegangen ist. Anstelle von ein paar Zehn-Zeilen-Methoden solltest du zwanzig (angeblich gut benannte) Einzeiler bevorzugen. Offensichtlich denkt jemand, dass es sauber ist, aber für mich scheint es viel schlimmer zu sein als die Originalversion.

Auch das Ersetzen einfacher elementarer Dinge wie

0 == memberArray.length

innerhalb einer Klasse mit einem Aufruf der klasseneigenen Methode wie

isEmpty()

ist eine fragwürdige "Verbesserung" IMHO. Zusatz: Der Unterschied besteht darin, dass die erste Prüfung genau das tut, was sie sagt: prüft, ob die Arraylänge 0 ist. Ok, isEmpty()prüft möglicherweise auch die Arraylänge. Es könnte aber auch so implementiert werden:

return null != memberArray ? 0 == memberArray.length : true;

Das heißt, es beinhaltet eine implizite Nullprüfung! Dies mag für eine öffentliche Methode ein gutes Verhalten sein - wenn das Array null ist, ist sicherlich etwas leer -, aber wenn es sich um Klasseninternale handelt, ist dies nicht so gut. Während die Kapselung nach außen ein Muss ist, müssen die Internen der Klasse genau wissen, was in der Klasse vor sich geht. Sie können die Klasse nicht in sich selbst einkapseln . Explizit ist besser als implizit.


Das soll nicht heißen, dass es nicht gut ist, lange Methoden oder logische Vergleiche aufzuschlüsseln. Natürlich ist es das, aber bis zu welchem ​​Grad - wo der Sweet Spot ist - ist offensichtlich eine Frage des Geschmacks. Das Aufbrechen einer langen Methode führt zu mehr Methoden, und das ist nicht kostenlos. Sie müssen im Quellcode herumspringen, um zu sehen, was wirklich los ist, wenn Sie es auf einen Blick sehen könnten, wenn all diese Dinge in einer einzigen Methode wären.

Ich würde sogar so weit gehen zu sagen, dass eine 1-Zeilen-Methode in einigen Fällen zu kurz ist , um eine Methode zu verdienen.


6
Ich sehe das selten als Problem. Meistens liegt das daran, dass ich in einer einzigen Methode zu viel sehe, nicht zu wenig. Nach einigen Studien weist eine sehr geringe Komplexität der Methoden jedoch auch eine geringfügig höhere Fehlerrate auf als eine mäßig niedrige Komplexität. enerjy.com/blog/?p=198
MIA

Ja, dies ist definitiv nur ein Problem in Clean Code. In der Praxis sind Methoden meist zu lang, wie Sie sagten. Aber es ist interessant, diese Kurve zu sehen! In der Tat sollten die Dinge so einfach wie möglich gemacht werden, aber nicht einfacher.
Joonas Pulakka

1
Ich finde Ihr zweites Beispiel überaus lesbarer, und dieses Formular (oder etwas Ähnliches, wie eine Length-Eigenschaft für die Klasse selbst) ist ein Muss, wenn Sie es veröffentlichen möchten.
Robert Harvey

@Robert Harvey: Das zweite Beispiel ist eine gute öffentliche Methode, aber das Aufrufen innerhalb der Klasse selbst ist fraglich, da Sie nicht genau wissen, was es tut, bevor Sie sich ansehen, wie es implementiert ist. Es könnte zum Beispiel nach null suchen. Siehe meinen Zusatz oben.
Joonas Pulakka

@Joonas: Fair genug.
Robert Harvey

13

"Seien Sie liberal mit Kommentaren"

Kommentare sind definitiv eine gute Sache, aber zu viele sind genauso schlecht, wenn nicht schlimmer als nicht genug. Warum? Leute neigen dazu, Kommentare auszuschalten, wenn sie zu viele unnötige Kommentare sehen. Ich sage nicht, dass Sie perfekt selbstdokumentierenden Code haben können, aber es ist besser, Code zu verwenden, der zur Erklärung Kommentare benötigt.


1
Selbstdokumentierender Code ist auf jeden Fall nett. Ich mag es jedoch, Kommentare neben einfachen Berechnungen zu haben (um auszudrücken, was der Rückgabetyp oder der Rückgabewert ist). Wenn Ihre Kommentare jedoch mehr Wörter als den Code selbst benötigen, ist es wahrscheinlich an der Zeit, den Code neu zu schreiben.
Sova

6
Ich muss der Art und Weise zustimmen, wie die Sova dies ausgedrückt hat. Sauberer Code ist Kommentaren vorzuziehen.
Riwalk

4
Du brauchst noch das "Warum"!

Ich hätte lieber Kommentare, in denen erklärt wird, warum. Das bedeutet, dass ich weniger an das Reverse Engineering der Codeabsicht denken muss, wenn ich es mir anschaue.
quick_now

12

GoTo als schädlich eingestuft

Wenn Sie eine Zustandsmaschine implementieren, kann eine GOTO-Anweisung sinnvoller sein (Lesbarkeit und effizienter Code) als ein Ansatz der "strukturierten Programmierung". Es hat einige Kollegen sehr beunruhigt, als das erste Stück Code, das ich in einem neuen Job geschrieben habe, nicht nur eine, sondern mehrere goto-Anweisungen enthielt. Zum Glück waren sie intelligent genug, um zu erkennen, dass dies in diesem speziellen Fall die beste Lösung war.

Jedes "Best Practice", das keine vernünftigen und dokumentierten Ausnahmen von seinen Regeln zulässt, ist einfach beängstigend.


16
Ich programmiere neun Jahre lang ohne eine einzige goto-Anweisung (einschließlich mehrerer Zustandsautomaten, wie Sie erwähnt haben). Erweitere deinen Geist um neue Ideen.
Riwalk

3
@ Mathieu M. - einverstanden - es ist nicht sinnvoll, GOTO mit strukturierten Steueranweisungen zu mischen. (Dies war reines C und es war kein Problem.
MZB

1
@ Stargazer2 - Bei einem einfachen FSM hängt es davon ab, ob das Ablegen des Status in eine Variable und die Verwendung als Index zum Aufrufen einer Prozedur (ist das nicht das Gleiche wie bei einem berechneten GOTO?) Einen klareren / schnelleren Code ergibt als die Verwendung des Programmzählers als der FSM Zustand. Ich befürworte dies nicht als die beste Lösung unter den meisten Umständen, sondern nur als die beste Lösung unter einigen Umständen. Erweitern Sie Ihren Geist auf alternative Ansätze.
MZB

5
@MZB, würden Sie nicht zustimmen, dass ein Funktionsaufruf auch nur ein berechnetes GOTO ist? Gleiches gilt unter anderem für / while / if / else / switch-Konstrukte. Sprachdesigner abstrahieren aus einem bestimmten Grund direkte Änderungen am Programmzähler. Verwenden Sie nicht gehe zu.
Riwalk

3
Die direkte Implementierung einer Statemachine ist wahrscheinlich ein Antimuster. Es gibt viele Möglichkeiten, eine Zustandsmaschine zu haben, ohne die Zustände und Übergänge wörtlich auszudrücken. Zum Beispielimport re
SingleNegationElimination

12

Die Opfer, die wir bringen, um Code testbar zu machen

Ich springe durch viele Rahmen, um meinen Code testbar zu machen, aber ich tue nicht so, als ob ich keine Wahl hätte. Ich höre jedoch oft Leute, die die Idee vertreten, dass dies "Best Practices" sind. Diese Praktiken beinhalten (in der Sprache von .Net geschrieben, aber auch für andere Sprachen) :

  • Erstellen einer Schnittstelle für jede Klasse. Dies verdoppelt die Anzahl der zu verarbeitenden Klassen (Dateien) und dupliziert den Code. Ja, die Schnittstellenprogrammierung ist gut, aber dafür sind die öffentlichen / privaten Spezifizierer gedacht.
  • Jede Klasse, die beim Start nicht instanziiert wird, benötigt eine Factory. Das ist natürlich new MyClass()viel einfacher als das Schreiben einer Factory, aber jetzt kann die Methode, mit der sie erstellt wird, nicht isoliert getestet werden. Ohne diese Tatsache würde ich nur 1/20 der Anzahl der Werksklassen machen, die ich jetzt mache.
  • Machen Sie jede Klasse öffentlich, was den Zweck zunichte macht, überhaupt über Zugriffsspezifizierer für Klassen zu verfügen. Auf nicht öffentliche Klassen kann jedoch nicht aus anderen Projekten zugegriffen (und somit getestet) werden. Die einzige andere Option besteht darin, den gesamten Testcode in dasselbe Projekt zu verschieben (und ihn daher mit dem Endprodukt freizugeben).
  • Abhängigkeitsspritze. Offensichtlich hat zu geben jede andere Klasse ich ein Feld und einen Konstruktor-Parameter verwenden , wird deutlich mehr Arbeit , als sie nur zu schaffen , wenn ich sie brauche; aber dann kann ich diese klasse nicht mehr isoliert testen.
  • Das Prinzip der Einzelverantwortung, das mir so viele Kopfschmerzen bereitet hat , hat mich zu einer eigenen Antwort bewegt .

Was können wir also tun, um das zu beheben? Wir brauchen eine drastische Änderung in der Spracharchitektur:

  • Wir brauchen die Fähigkeit, Klassen zu verspotten
  • Wir würden die Fähigkeit benötigen, private Methoden interner Klassen aus einem anderen Projekt heraus zu testen (dies mag wie eine Sicherheitslücke erscheinen, aber ich sehe kein Problem, wenn der Proband gezwungen ist, seine Testerklassen zu benennen) .
  • Die Abhängigkeitsinjektion (oder der Servicestandort) sowie etwas, das unserem bestehenden Fabrikmuster entspricht, müsste ein Kernbestandteil der Sprache sein.

Kurz gesagt, wir brauchen eine Sprache, die von Grund auf unter dem Gesichtspunkt der Testbarkeit entwickelt wurde .


Ich vermute, Sie haben noch nie von TypeMock gehört ? Es erlaubt das Verspotten von Klassen, Privaten, Statik (Fabrik), irgendetwas.
Allon Guralnek

@Allon: Das habe ich, aber es ist alles andere als kostenlos , sodass es für die meisten Menschen keine Option ist.
BlueRaja - Danny Pflughoeft

Wenn Sie viele Factory-Klassen schreiben müssen, dann machen Sie etwas falsch. Intelligente DI-Bibliotheken (z. B. Autofac für C #) können Func <T>, Lazy <T>, Delegates usw. für Fabriken verwenden, ohne selbst ein Boilerplate zu schreiben.
Gix

10

Teilen von Anwendungen in Ebenen; Datenschicht, Business-Schicht, UI-Schicht

Der Hauptgrund, warum ich das nicht mag, ist, dass die meisten Orte, die dieser Methode folgen, sehr spröde Frameworks verwenden, um dies zu erreichen. IE UI Layer ist handcodiert, um mit Business Layer-Objekten umzugehen. Business Layer-Objekte sind handcodiert, um mit Business Rules und Datenbanken umzugehen. Die Datenbank ist SQL und ist bereits ziemlich spröde und wird von der "DBA" -Gruppe verwaltet, die Änderungen nicht mag.

Warum ist das so schlimm? Die häufigste Verbesserungsanforderung lautet wahrscheinlich "Ich benötige ein Feld auf Bildschirm X mit Y." Knall! Sie haben nur eine neue Funktion, die sich auf jede einzelne Ebene auswirkt, und wenn Sie Ebenen mit verschiedenen Programmierern trennen, wurde dies für eine sehr einfache Änderung zu einem großen Problem, an dem mehrere Personen und Gruppen beteiligt waren.

Außerdem weiß ich nicht, wie oft ich in solchen Auseinandersetzungen gestritten habe. "Das Namensfeld ist auf eine maximale Länge von 30 begrenzt. Handelt es sich um eine Benutzeroberflächen- oder Geschäftsschicht- oder Datenschicht-Ausgabe?" Und es gibt hundert Argumente und keine richtige Antwort. Die Antwort ist die gleiche, sie wirkt sich auf alle Ebenen aus, Sie möchten die Benutzeroberfläche nicht dumm machen und müssen alle Ebenen durchgehen und in der Datenbank versagen, nur damit der Benutzer feststellt, dass seine Eingabe zu lang ist. Wenn Sie es ändern, wirkt es sich auf alle Ebenen usw. aus.

Die "Schichten" neigen ebenfalls zum Auslaufen; Wenn eine Ebene physisch durch Prozess- / Maschinengrenzen getrennt ist (IE-Webbenutzeroberfläche und Geschäfts-Backend-Logik), werden die Regeln dupliziert, damit alles einigermaßen gut funktioniert. Das heißt, einige Geschäftslogiken landen in der Benutzeroberfläche, obwohl es sich um eine "Geschäftsregel" handelt, da der Benutzer die Benutzeroberfläche benötigt, um darauf zu reagieren.

Wenn das verwendete Framework oder die verwendete Architektur gegenüber kleinen Änderungen und Leckagen, dh basierend auf Metadaten, unempfindlich ist und dynamisch über alle Ebenen angepasst wird, kann dies weniger schmerzhaft sein. Bei den meisten Frameworks ist dies jedoch ein großer Aufwand, der für jede kleine Änderung Änderungen an der Benutzeroberfläche, in der Geschäftsschicht und in der Datenbank erforderlich macht und mehr Arbeit und weniger Hilfe verursacht, als die Technik bewirken soll.

Ich werde wahrscheinlich dafür zugeschlagen werden, aber da ist es :)


+1, klingt wie mein letzter Arbeitsplatz bis ins kleinste Detail! Ich respektiere gestufte Anwendungen grundsätzlich, aber zu viele Leute behandeln sie wie eine Wunderwaffe, wenn sie keinen Sinn ergeben. Die meisten Unternehmenssoftware hat eine erstaunlich geringe Menge an Geschäftslogik und was es hat, ist relativ einfach. Dies kann Layering-Geschäftslogik zu einem Albtraum von Kesselcode machen. Oft können die Zeilen zwischen Datenzugriff und Geschäftslogik verschwimmen, da die Abfrage die Geschäftslogik ist.
maple_shaft

... und die meisten Shops können die Logik der Benutzeroberfläche oder der Präsentation überhaupt nicht erkennen. Da sie nicht verstehen, wie wenig Geschäftslogik in einer typischen CRUD-Anwendung vorhanden ist, haben sie das Gefühl, dass sie etwas falsch machen müssen, wenn sich der Großteil ihrer Logik in der Präsentationsebene als Präsentationslogik befindet. Es wird fälschlicherweise als Geschäftslogik identifiziert und dann für einen weiteren Serveraufruf an den Server weitergeleitet. Ein Thin Client kann und sollte Präsentationslogik haben, z. (Textfeld2 ausblenden, wenn Option1 in Dropdown3 ausgewählt ist).
maple_shaft


7

User Stories / Use Cases / Personas

 

Ich verstehe die Notwendigkeit für diese, wenn Sie für eine Branche programmieren, mit der Sie nicht vertraut sind, aber ich denke, wenn sie in vollem Umfang implementiert werden, werden sie zu unternehmerisch und zu einer Zeitverschwendung.


7

80 Zeichen / Zeilengrenzen sind dumm

Ich verstehe, dass einige Kompromisse gemacht werden müssen, um der Geschwindigkeit des langsamsten Läufers auf der GUI-Seite zu entsprechen (Einschränkungen der Bildschirmauflösung usw.), aber warum gilt diese Regel für die Code-Formatierung?

Es gab diese kleine Erfindung namens horizontale Bildlaufleiste, die erstellt wurde, um den virtuellen Bildschirmbereich außerhalb der am weitesten rechts liegenden Pixelgrenze zu verwalten. Warum nicht Entwickler, denen es gelungen ist, produktivitätssteigernde Tools wie Syntaxhervorhebung und automatische Vervollständigung zu erstellen?

Klar, es gibt CLI-Editoren, die von * nix-Dinosauriern religiös verwendet werden und den müden alten Einschränkungen ihrer VT220-Terminals folgen, aber warum halten wir uns an den gleichen Standard?

Ich sage, schraube die 80 Zeichen Grenze. Wenn die Dinosaurier episch genug sind, um den ganzen Tag über Emacs / Vim zu hacken, warum kann dann nicht eine Erweiterung erstellt werden, die automatisch Zeilen umbricht oder ihren CLI-IDEs horizontale Bildlauffunktionen verleiht?

Monitore mit 1920 x 1080 Pixeln werden irgendwann zur Norm und Entwickler auf der ganzen Welt leben immer noch unter den gleichen Einschränkungen, ohne dass es darauf ankommt, warum sie dies tun.

80-Zeichen-Limits sind keine Best Practice, sondern eine Nischenpraxis für eine sehr geringe Anzahl von Programmierern und sollten als solche behandelt werden.

Bearbeiten:

Es ist verständlich, dass viele Entwickler die horizontale Bildlaufleiste nicht mögen, weil sie eine Mausbewegung erfordert. Erhöhen Sie die Spaltenbreitenbeschränkung für diejenigen von uns, die moderne Bildschirme verwenden, auf eine höhere Zahl (als 80).

Als 800x600-Computermonitore für die meisten Benutzer zur Norm wurden, erhöhten Webentwickler ihre Website-Breite, um der Mehrheit gerecht zu werden ... Warum können Entwickler nicht dasselbe tun?


1
@Orbling Nice GWB Logik mit dem ___ ist böse Winkel. Sie hassen den hScroll, haben Sie einen triftigen Grund, warum die Spaltenbreite auf 80 Zeichen begrenzt werden sollte? Warum nicht 160 oder 256? Ich denke, wir können alle davon ausgehen, dass die meisten Entwickler ihre VT220-Terminals eingestellt und durch puTTY ersetzt haben, damit sie die Breite trotzdem programmgesteuert erweitern können.
Evan Plaice

4
Ich bevorzuge, dass wir uns an die 80 Zeichen-Grenze halten. Sobald Sie mir mehr horizontalen Raum geben, werde ich versuchen, weitere Dokumente nebeneinander zu öffnen. Ich würde es hassen, in vier Richtungen scrollen zu müssen. Außerdem habe ich oft bemerkt, dass ich gezwungen bin, lesbareren Code mit der 80-Zeichen-Kappe zu schreiben.
Filip Dupanović

2
Wie würden Sie es drucken?

5
Entschuldigung - muss in diesem Punkt nicht einverstanden sein. Ich hasse lange, lange Zeilen - es erfordert mehr Augenbewegungen, es erfordert Mausbewegungen, um darüber zu scrollen, und es ist schwieriger, subtile, kleine, baumelnde Dinge am Ende einer Zeile zu erkennen. In ungefähr 99% der Fälle gibt es saubere Methoden, um Dinge über mehrere (kürzere) Zeilen laufen zu lassen, was klarer und leichter zu lesen ist. 80 Zeichen mögen willkürlich sein und "weil es in Lochkartentagen so war", aber es ist immer noch ein vernünftiger Rahmen, um aus den oben genannten Gründen innerhalb der meisten Zeit zu arbeiten.
quick_now

3
Um 2 Leerzeichen einrücken. Und verwenden Sie einen Editor mit einem automatischen Einrückungs-Tracker. Ich habe es jahrelang so gemacht, keine große Sache. (Emacs mit den richtigen Modi hilft hier.)
schnell_now

5

Messen, Messen, Messen

Also gut, messe weg, aber um Leistungsfehler zu isolieren , funktioniert das Messen genauso gut wie die sukzessive Beseitigung. Hier ist die Methode, die ich benutze.

Ich habe versucht, die Quelle der Maßnahme-Maßnahme "Weisheit" aufzuspüren. Jemand mit einer Seifenkiste, die groß genug ist, hat es gesagt, und jetzt reist es.


5

Mein Lehrer verlangt, dass ich alle meine Bezeichner (ohne Konstanten) mit Kleinbuchstaben beginne, z myVariable.

Ich weiß, es scheint eine Kleinigkeit zu sein, aber viele Programmiersprachen erfordern Variablen, die mit Großbuchstaben beginnen. Ich schätze Konsistenz, deshalb ist es meine Gewohnheit, alles mit Großbuchstaben zu beginnen.


9
Ich hatte einen Lehrer, der camelCase benötigte, weil er darauf bestand, dass dies in der realen Welt verwendet wird ... Zur gleichen Zeit programmierte ich bei meiner Arbeit in zwei verschiedenen Gruppen - beide Gruppen bestanden auf under_scores. Was zählt, ist, was Ihre Gruppe verwendet. Er hätte sich als führender Programmierer definieren können und alles wäre in meinem Buch in Ordnung gewesen - wir folgen seinen Konventionen -, aber er gab immer seine Meinung als "die Art und Weise, wie Dinge in der realen Welt getan werden", als ob es keine andere gültige gäbe Weg.
30.

@xnine Ich habe noch nicht genug Repräsentanten auf dieser Website, um Ihren Kommentar zu bewerten. Ich antworte daher nur mit diesem Zustimmungskommentar.
Maxpm

5
Die Groß- und Kleinschreibung von Kamelen (Anfangsbuchstaben in Kleinbuchstaben) ist ebenso üblich wie die von Pascal (Anfangsbuchstaben aller großgeschriebenen Wörter). In den meisten Sprachen wird camelCase für private / interne Variablen verwendet, während PascalCase für Klassen, Methoden, Eigenschaften, Namespaces und öffentliche Variablen verwendet wird. Es ist keine schlechte Übung, sich daran zu gewöhnen, nur für Projekte bereit zu sein, die möglicherweise ein anderes Benennungsschema verwenden.
Evan Plaice

2
Nur ein FYI. Einige Sprachen schließen daraus ab, ob der erste Buchstabe einer Variablen ein Großbuchstabe ist oder nicht. In einer solchen Sprache wird die Variable als Konstante behandelt, wenn der erste Buchstabe ein Großbuchstabe ist. Jeder Versuch, sie zu ändern, führt zu einem Fehler.
Berin Loritsch

1
In Go beginnen öffentliche Methoden und Member in Klassen mit einem Großbuchstaben. private mit einem Kleinbuchstaben.
Jonathan Leffler

5

Verwenden Sie Singletons

Wenn Sie nur eine Instanz von etwas haben sollten. Ich kann nicht mehr widersprechen . Verwenden Sie niemals einen Singleton und weisen Sie ihn nur einmal zu und übergeben Sie den Zeiger / das Objekt / die Referenz nach Bedarf. Es gibt absolut keinen Grund, dies nicht zu tun.


2
Das ist eine ganze Reihe von Negativen, die mich in Bezug auf Ihre tatsächliche Haltung zu Singletons etwas verwirrt haben.
Paul Butcher

1
@ Paul Butcher: Ich hasse Singletons und es sollte nie benutzt werden

1
@rwong: Ich persönlich glaube nicht, dass irgendein Grund ein legitimer Grund ist. Schreiben Sie es einfach als normale Klasse. Wirklich, es gibt keinen Grund, einen anderen Singleton als Faulheit zu verwenden und schlechte Gewohnheiten oder schlechtes Design zu fördern.

6
Wer sagt, dass die Verwendung von Singeltons eine bewährte Methode ist?
Phil Mander

2
Singletons haben ihren Platz, insbesondere in Fällen, in denen eine Betriebsstruktur beim Start zugewiesen und gefüllt wird, und werden dann im Grunde genommen nur während der Laufzeit des Programms gelesen. In diesem Fall wird es jedoch nur zu einem Cache auf der anderen Seite eines Zeigers.
Tim Post

5

Verwenden von Int ohne Vorzeichen als Iterator

Wann werden sie erfahren, dass die Verwendung von signiertem Int viel sicherer und weniger fehleranfällig ist. Warum ist es so wichtig, dass der Array-Index nur eine positive Zahl sein kann, dass jeder froh ist, die Tatsache zu übersehen, dass 4 - 5 4294967295 ist?


Okay, jetzt bin ich neugierig - warum sagst du das? Ich fühle mich ein wenig dumm - können Sie einige Codebeispiele bereitstellen, um Ihre Aussagen zu stützen?
Paul Nathan

4
@Paul Nathan: Was den Fehler angeht, ist hier ein Beispiel: für (unsigned int i = 0; i <10; i ++) {int crash_here = my_array [max (i-1,0)];}
AareP

@AareP: Sicher - ich nehme an, Sie verweisen auf die Tatsache, dass Sie beim 0Dekrementieren eines vorzeichenlosen Int 1tatsächlich den maximalen positiven Wert erhalten , den ein vorzeichenloses Int speichern kann.
Adam Paynter

1
@ Adam Paynter: ja. Dies mag für C ++ - Programmierer normal erscheinen, aber seien wir ehrlich, "unsigned int" ist eine schlechte "Implementierung" von Nur-Positiv-Zahlen.
AareP

Keine gute Idee für kleine Embedded-Computer - häufig werden unsignierte Ints kleineren, schnelleren Code generieren. Hängt vom Compiler und Prozessor ab.
quick_now

4

Methoden sollten nicht länger als ein einzelner Bildschirm sein

Ich stimme dem Prinzip der Einzelverantwortung vollkommen zu, aber warum meinen die Leute, dass "eine Funktion / Methode auf der feinsten Ebene der logischen Granularität nur eine einzige Verantwortung haben kann"?

Die Idee ist einfach. Eine Funktion / Methode sollte eine Aufgabe erfüllen. Wenn ein Teil dieser Funktion / Methode anderweitig verwendet werden kann, teilen Sie ihn in eine eigene Funktion / Methode auf. Wenn es an anderer Stelle im Projekt verwendet werden kann, verschieben Sie es in eine eigene Klasse oder in eine Utility-Klasse und machen Sie es intern zugänglich.

Eine Klasse mit 27 Hilfsmethoden, die nur einmal im Code aufgerufen werden, ist dumm, eine Verschwendung von Speicherplatz, eine unnötige Erhöhung der Komplexität und eine massive Zeitersparnis. Es klingt eher nach einer guten Regel für Leute, die beschäftigt sein wollen, Code umzugestalten, aber nicht viel produzieren wollen.

Hier ist meine Regel ...

Schreiben Sie Funktionen / Methoden, um etwas zu erreichen

Wenn Sie dabei sind, Code zu kopieren oder einzufügen, fragen Sie sich, ob es besser ist, eine Funktion / Methode für diesen Code zu erstellen. Wenn eine Funktion / Methode nur einmal in einer anderen Funktion / Methode aufgerufen wird, ist es wirklich sinnvoll, sie an erster Stelle zu haben (wird sie in Zukunft häufiger aufgerufen). Ist es sinnvoll, während des Debuggens mehr Sprünge in / aus Funktionen / Methoden einzufügen (dh macht der hinzugefügte Sprung das Debuggen einfacher oder schwieriger)?

Ich stimme voll und ganz zu, dass Funktionen / Methoden mit mehr als 200 Zeilen überprüft werden müssen, aber einige Funktionen nur eine Aufgabe in so vielen Zeilen ausführen und keine nützlichen Teile enthalten, die für den Rest des Projekts abstrahiert / verwendet werden können.

Ich betrachte es aus der Perspektive eines API-Entwicklers ... Wenn sich ein neuer Benutzer das Klassendiagramm Ihres Codes ansehen würde, wie viele Teile dieses Diagramms wären innerhalb des gesamten Projekts sinnvoll und wie viele würden ausschließlich als existieren Helfer zu anderen Teilen innerhalb des Projekts.

Wenn ich zwischen zwei Programmierern wählen würde: Der erste hat die Tendenz, Funktionen / Methoden zu schreiben, die versuchen, zu viel zu tun; der zweite bricht jeden Teil jeder Funktion / Methode auf die feinste Granularitätsebene; Ich würde die ersten Hände runter wählen. Der erste würde mehr erreichen (dh mehr Fleisch von der Anwendung schreiben), sein Code wäre leichter zu debuggen (aufgrund weniger Sprünge in / aus Funktionen / Methoden während des Debuggens) und er würde weniger Zeit damit verschwenden, fleißige Arbeit zu vervollkommnen, wie Der Code sieht besser aus als zu perfektionieren, wie der Code funktioniert.

Begrenzen Sie unnötige Abstraktionen und verschmutzen Sie die automatische Vervollständigung nicht.


Diese. Ich habe einmal eine lange Funktion in mehrere überarbeitet, nur um zu erkennen, dass fast alle von ihnen fast alle Parameter des ursprünglichen Codes benötigten. Die Parameterbehandlung war so schmerzhaft, dass es einfacher war, einfach zum alten Code zurückzukehren.
l0b0

3
Ich denke, ein Gegenargument dazu ist, dass das Umgestalten von Teilen einer großen Methode in separate Aufrufe die größere Methode leichter lesbar machen kann. Auch wenn die Methode nur einmal aufgerufen wird.
Jeremy Heiler

1
@ Jeremy How? Wie ist es möglich, einen Codeabschnitt zu abstrahieren und ihn in einer eigenen Methode zu platzieren, damit er besser lesbar ist, als nur einen einzeiligen Kommentar über dem Code zu platzieren, der beschreibt, was er tut? Angenommen, dieser Codeblock wird in diesem Codeabschnitt nur einmal verwendet. Ist es für die meisten Programmierer wirklich so schwierig, die funktionierenden Teile des Codes zu zerlegen, während sie ihn lesen, und / oder ein paar einzeilige Kommentare zu platzieren, um sie daran zu erinnern, was er tut, wenn sie es nicht können?
Evan Plaice

4
@Evan: Durch das effektive Einfügen von Codeteilen in Funktionen erhalten sie einen Namen , der hoffentlich die Funktionsweise dieses Codeteils gut erklärt. Wo immer dieser Code aufgerufen wird, können Sie den Namen sehen, der erklärt, was der Code tut , anstatt den Algorithmus selbst analysieren und verstehen zu müssen . Wenn dies gut gemacht wird, kann dies das Lesen und Verstehen von Code enorm erleichtern.
sbi

1
+1 und ich würde mehr geben, wenn ich könnte. Mit einer Menge C-Code, die 1000 Zeilen in einer einzelnen Funktion enthält (z. B. ein Parser mit einem massiven Schalter ()), stimmt überhaupt nichts, vorausgesetzt, die Absicht ist klar und einfach. Wenn man all die kleinen Teile rausschmeißt und sie ruft, wird es schwieriger, das zu verstehen. Natürlich gibt es auch hier Grenzen ... vernünftiges Urteilsvermögen ist alles.
quick_now
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.