Seien Sie liberal in dem, was Sie akzeptieren ... oder nicht?


45

[Haftungsausschluss: Diese Frage ist subjektiv, aber ich würde es vorziehen, Antworten mit Fakten und / oder Überlegungen zu erhalten.]

Ich denke, jeder kennt das Robustheitsprinzip , das normalerweise durch das Postelsche Gesetz zusammengefasst wird:

Seien Sie konservativ in dem, was Sie senden. Sei liberal in dem, was du akzeptierst.

Ich stimme zu, dass dies für die Entwicklung eines weit verbreiteten Kommunikationsprotokolls sinnvoll sein kann (mit dem Ziel, eine einfache Erweiterung zu ermöglichen). Ich war jedoch immer der Meinung, dass die Anwendung auf HTML / CSS völlig fehlgeschlagen ist und jeder Browser seine eigene stille Optimierung implementiert Erkennung / Verhalten, was es nahezu unmöglich macht, ein konsistentes Rendering über mehrere Browser hinweg zu erzielen.

Ich stelle jedoch fest, dass der RFC des TCP-Protokolls "Silent Failure" als akzeptabel erachtet, sofern nicht anders angegeben ... was gelinde gesagt ein interessantes Verhalten ist.

Es gibt andere Beispiele für die Anwendung dieses Prinzips im gesamten Softwarehandel, die regelmäßig auftauchen, weil sie Entwickler von oben in den Kopf gebissen haben:

  • Javascript Semikolon einfügen
  • C (stille) eingebaute Konvertierungen (was nicht so schlimm wäre, wenn es nicht abgeschnitten würde ...)

und es gibt Tools, die bei der Implementierung von "intelligentem" Verhalten helfen:

Ich bin jedoch der Meinung, dass dieser Ansatz zwar hilfreich sein kann, wenn es um nicht technische Benutzer geht oder wenn es darum geht, Benutzer bei der Fehlerbehebung zu unterstützen, bei der Gestaltung der Benutzeroberfläche für Bibliotheken / Klassen jedoch einige Nachteile aufweist:

  • Es ist etwas subjektiv, ob der Algorithmus "richtig" vermutet, und daher kann er gegen das Prinzip des geringsten Erstaunens verstoßen
  • es erschwert die Implementierung und erhöht somit die Wahrscheinlichkeit, Fehler einzuführen (Verstoß gegen YAGNI ?)
  • es macht das Verhalten anfälliger für Änderungen, da jede Änderung der "Vermutungs" -Routine alte Programme beschädigen kann, was Refactoring-Möglichkeiten fast ausschließt ... von Anfang an!

Und das hat mich zu folgender Frage geführt:

Neigen Sie beim Entwerfen einer Schnittstelle (Bibliothek, Klasse, Nachricht) zum Robustheitsprinzip oder nicht?

Ich selbst neige dazu, ziemlich streng zu sein und eine umfangreiche Eingabevalidierung für meine Schnittstellen zu verwenden, und ich habe mich gefragt, ob ich vielleicht zu streng bin.


Ich frage mich, was der Unterschied zwischen HTML und allgemeinen Daten ist. Beim Robustheitsprinzip geht es um Kommunikation. Man schreibt - man liest. Warum unterscheidet sich die Netzwerkkommunikation von der visuellen oder API-Kommunikation? Ich habe ein API-Beispiel, in dem das Prinzip der Liberalität bei dem, was wir akzeptieren, das Leben der Benutzer vereinfacht , die Codegröße reduziert und daher die Leistung verbessert und Fehler beseitigt. Schauen Sie sich stackoverflow.com/questions/18576849
Val

@Val: Tatsächlich stimmt Ihr Beispiel nicht überein. "liberal in dem zu sein, was du akzeptierst" ist nicht nur eine Frage der Basis / der Ableitung, sondern geht darüber hinaus und akzeptiert (und interpretiert) auch leicht fehlerhafte Eingaben.
Matthieu M.

Wie zeigt ein Fall nicht diesen Fall?
Val

Antworten:


34

Ich würde Robustheit sagen, wenn dadurch keine Mehrdeutigkeiten entstehen .

Beispiel: Wenn Sie eine durch Kommas getrennte Liste analysieren, ändert sich die semantische Bedeutung nicht, wenn vor / nach dem Komma ein Leerzeichen steht.

Beim Parsen einer Zeichenfolgenführung sollte eine beliebige Anzahl der gängigen Formate akzeptiert werden (mit oder ohne Bindestriche, mit oder ohne umgebende geschweifte Klammern).

Die meisten Programmiersprachen sind robust mit Leerraumnutzung. Insbesondere überall dort, wo es keinen Einfluss auf die Bedeutung von Code hat. Sogar in Python, wo Leerzeichen relevant sind, ist es immer noch flexibel, wenn Sie sich in einer Liste oder Wörterbuchdeklaration befinden.

Ich stimme definitiv zu, dass, wenn etwas auf verschiedene Arten interpretiert werden kann oder wenn nicht 100% klar ist, was gemeint ist, zu viel Robustheit ein Schmerz sein kann, aber es gibt viel Raum für Robustheit, ohne mehrdeutig zu sein.


1
Ich stimme zu, Robustheit, wenn sie nicht viel kostet, ist es wert.
Matthieu M.

2
Sogar die durch Kommas getrennte Liste führt zu Problemen: Die Javascript-Engine von Chrome und Firefox scheint dies {"key": "value",}als gültig zu akzeptieren , der IE dagegen nicht. Ich bin oft auf dieses spezielle Problem gestoßen, bis ich meinen Build-Prozess mit JSlint verbessert habe.
Keppla

2
@keppla Das ist eher ein Problem mit der Implementierung als mit dem Design. Ich bin mir nicht sicher, ob dies durch die JavaScript-Spezifikation zulässig ist und der IE nicht folgt, oder ob dies eine "nette Funktion" ist, die FF und Chrome hinzugefügt haben, aber in Python ist angegeben, dass sie als solche gültig und implementiert sind. Wenn es als gültig angegeben ist und nicht funktioniert, handelt es sich um eine fehlerhafte Implementierung. Wenn es nicht spezifiziert ist, sollte man sich nicht wirklich auf es verlassen (obwohl es aus praktischen Gründen auch in der Spezifikation nicht berücksichtigt werden kann, wenn Sie den Benutzer nicht kontrollieren, wenn es in einem Hauptbrowser nicht funktioniert)
Davy8

7
@ Davy8: Nachgestelltes Komma scheint illegal zu sein ( stackoverflow.com/questions/5139205/… ). Darauf möchte ich mich nicht verlassen. Mein Punkt ist, wenn genügend Leute die Eingabe akzeptieren, wird sie de facto zum Standard (weil man nicht merkt, dass es sich um einen Fehler handelt), was zu etwas führt, auf das wir in HTML gestoßen sind: den Fehlern werden so alltäglich, dass Sie sie nicht mehr als schlechte Eingabe ignorieren können.
Keppla

1
@keppla, das sollte in Moz und Chrome scheitern. Als hauptsächlich von JS entwickelter Entwickler ärgert es mich, dass dies nicht der Fall ist (zumindest in Moz früher). Dies macht das Debuggen schwieriger und nicht einfacher. IE tut, was es tun soll. Fail @ bad Code. HTML ist eine Sache. Wir brauchen diesen Mist nicht in einer Skriptsprache. Es ist ein Beispiel für die schreckliche Anwendung des Robust-Prinzips, das Browser-Anbieter auszeichnen.
Erik Reppen

15

Definitiv nicht. Techniken wie das defensive Programmieren verschleiern Fehler, machen ihr Auftreten weniger wahrscheinlich und zufälliger, was die Erkennung erschwert und die Isolierung erschwert.

Das stark unterbewertete Writing Solid Code hat wiederholt die Notwendigkeit und die Techniken hervorgehoben, Fehler so schwierig wie möglich einzuführen oder zu verbergen. Durch Anwendung seiner Prinzipien wie "Eliminiere zufälliges Verhalten. Erzwinge, dass Fehler reproduzierbar sind." und "Achten Sie immer auf Fehler in Ihren Schnittstellen und beseitigen Sie diese." Entwickler werden die Qualität ihrer Software erheblich verbessern, indem sie die Mehrdeutigkeit und die unkontrollierten Nebenwirkungen beseitigen, die für eine große Menge von Fehlern verantwortlich sind.


9

Übermäßige Anwendung von Robustness führt dazu, dass Sie erraten, was der Benutzer wollte. Dies ist in Ordnung, bis Sie es falsch verstehen. Es setzt auch den völlig falschen Glauben voraus, dass Ihre Kunden Ihr Vertrauen nicht missbrauchen und zufälliges Kauderwelsch erzeugen, das zufällig funktioniert, das Sie jedoch in Version 2 nicht unterstützen können.

Übermäßige Anwendung von Korrektheit führt dazu, dass Sie Ihren Kunden das Recht verweigern, geringfügige Fehler zu machen. Dies ist in Ordnung, bis sie sich darüber beklagen, dass ihre Produkte mit dem Produkt Ihres Mitbewerbers einwandfrei funktionieren, und Ihnen mitteilen, was Sie mit Ihrem 5.000-Seiten-Standard tun können, der das Wort hat "ENTWURF" ist immer noch mit Kreide auf dem Cover vermerkt, und mindestens drei Experten behaupten, er sei grundlegend fehlerhaft, und 200 ehrlichere Experten geben an, dass sie das nicht vollständig verstehen.

Meine persönliche Lösung war schon immer die Abwertung. Sie unterstützen sie, sagen ihnen aber, dass sie etwas falsch machen, und (wenn möglich) den einfachsten Weg zur Korrektheit. Auf diese Weise haben Sie, wenn Sie die Bug-Funktion 10 Jahre später ausschalten, zumindest die Möglichkeit, anzugeben, dass "wir Sie gewarnt haben, dass dies passieren könnte".


+1 für die Abwertung , es ist in der Tat ein wichtiges Konzept und ich bin überrascht, dass es bisher übersehen wurde.
Matthieu M.

9

Leider führt das sogenannte "Robustheitsprinzip" nicht zu Robustheit. Nehmen Sie als Beispiel HTML. Viel Ärger, Tränen, Zeit- und Energieverschwendung hätten vermieden werden können, wenn Browser HTML von Anfang an streng analysiert hätten, anstatt zu versuchen, die Bedeutung von fehlerhaften Inhalten zu erraten.

Der Browser sollte einfach eine Fehlermeldung angezeigt haben, anstatt zu versuchen, sie unter der Decke zu beheben. Das hätte alle Mistkerle gezwungen, ihr Durcheinander zu reparieren.


Ich zitiere mich selbst (muss in die Jahre gekommen sein): "Ich habe jedoch immer gedacht, dass seine Anwendung auf HTML / CSS ein völliger Misserfolg war"
Matthieu M.,

3
Richtig, aber die gleiche Fehlertoleranz hat auch dazu beigetragen, dass das Web so populär wurde.
15.

Die Browser-Anbieter sind bei diesem fehlgeschlagen. Mit Doctypes hatten wir die Möglichkeit, in dieser Hinsicht unsere eigene Wahl zu treffen, aber am Ende verhielt sich alles so, wie Sie es getan haben, solange Sie einen Doctyp deklariert hatten. Jetzt denken sie, dass ein hyperkomplexes Regelwerk, das eingehalten werden muss, um mit Fehlern umzugehen, die Lösung ist? Ich denke, sie können das Problem nicht identifizieren.
Erik Reppen

Sie sagen, dass Fail-Fast, das Gegenteil von "robust", effizienter ist.
Val

@ MaR: Ist das so? Sehr umstritten, viel wahrscheinlicher waren die Merkmale wichtig.
Deduplizierer

6

Ich teile Interfaces in mehrere Gruppen ein (füge mehr hinzu, wenn du möchtest):

  1. diejenigen, die unter Ihrer Kontrolle stehen, sollten streng sein (Klassen normalerweise)
  2. Bibliotheks-APIs, die ebenfalls streng sein sollten, aber eine zusätzliche Validierung wird empfohlen
  3. öffentliche Schnittstellen, die jede Art von Missbrauch behandeln müssen (normalerweise Protokolle, Benutzereingaben usw.). Hier zahlt sich die Robustheit der Eingabe wirklich aus. Man kann nicht erwarten, dass jeder seine Probleme beheben wird. Und denken Sie daran, dass es Ihre Schuld ist, wenn die Anwendung nicht funktioniert, nicht die Partei, die einen schlecht formatierten Mist gesendet hat.

Die Ausgabe muss immer streng sein.


5

Ich denke, HTML und das World Wide Web haben das Robustness-Prinzip in der Praxis umfassend getestet und gezeigt, dass es ein schwerwiegender Fehler ist. Es ist direkt verantwortlich für das verwirrende Durcheinander konkurrierender HTML-Fast-Standards, das das Leben der Webentwickler (und ihrer Benutzer) miserabel macht und mit jeder neuen Version von Internet Explorer schlimmer wird.

Wir wissen seit den 1950er Jahren, wie man Code richtig überprüft. Führen Sie es durch einen strengen Parser und wenn etwas syntaktisch nicht korrekt ist, werfen Sie einen Fehler und brechen Sie ab. Gehen Sie nicht vorbei, sammeln Sie keine 200 Dollar und lassen Sie aus Liebe zu allem, was binär ist , kein Computerprogramm versuchen, die Gedanken des Programmierers zu lesen, wenn er einen Fehler gemacht hat!

HTML und JavaScript haben uns genau gezeigt, was passiert, wenn diese Prinzipien ignoriert werden. Die beste Vorgehensweise ist, aus ihren Fehlern zu lernen und sie nicht zu wiederholen.


4
@ChaosPandion: Ich denke, das Problem liegt nicht beim Internet Explorer selbst, sondern bei all den nicht standardmäßigen Webseiten, die von früheren Versionen akzeptiert wurden und mit denen jetzt jeder leben muss ... und versuchen, mehr oder weniger erfolgreich zu leben.
Matthieu M.

5
Ich denke tatsächlich, das IE-Team ist in der schlechtesten Position aller Browser-Entwickler. Joel fasst meine Gedanken ziemlich gut zusammen .
Dean Harding

3
Es mag Entwicklern und Designern das Leben miserabel gemacht haben, aber dann würden wir an einem sich sehr langsam entwickelnden und statischen Standard festhalten - ich bezweifle, dass das Web so aussehen würde, wie es jetzt gegeben ist. Die wirklichen Gewinner waren die Leute, die im Internet surften und am Ende des Tages waren es die Leute, die zählten.
FinnNk

4
Auch wenn das Robustness-Prinzip den Web-Entwicklern das Leben schwer machen mag, ist es schwierig, das World Wide Web (das mittlerweile ein wesentlicher Bestandteil fast aller wichtigen Institutionen auf dem Planeten ist) als massiven AUSFALL zu bezeichnen .
Deworde

3
"Wir wissen seit den 1950er Jahren, wie man Code richtig validiert. Führen Sie ihn durch einen strengen Parser und wenn etwas syntaktisch nicht korrekt ist, werfen Sie einen Fehler und brechen Sie ab." So wenden Sie dies auf ein Szenario in der realen Welt an: Wenn ich ein einzelnes Symbol ganz rechts auf meiner Seite direkt unterhalb des Schnitts verkorkst habe, ist das Aufgeben der gesamten Seite eine sehr gute Möglichkeit, jemanden aufgrund eines Fehlers an einen anderen Ort zu schicken Problem, das sie nicht einmal bemerkt hätten. Ja, Sie können argumentieren, ich hätte den Fehler nicht machen sollen. Aber das setzt eher voraus, dass ich noch nicht zu Ihrem stärkeren Konkurrenten gegangen bin und Ihre Anrufe nicht mehr annehme.
Deworde

3

Als Kontrapunkt zu Masons Beispiel war meine Erfahrung mit dem Session Initiation Protocol, dass, während verschiedene Stacks die relevanten RFCs unterschiedlich interpretieren würden (und ich vermute, dass dies mit jedem jemals geschriebenen Standard passiert ), (mäßig) liberal in dem ist, was Sie akzeptieren, was Sie bedeuten kann tatsächlich zwischen zwei Geräten telefonieren. Da es sich bei diesen Geräten im Gegensatz zu Softwarekomponenten auf einem Desktop um übliche physische Dinge handelt, müssen Sie einfach liberal sein, was Sie akzeptieren, oder Ihr Telefon kann kein anderes Telefon einer bestimmten Marke anrufen. Das macht dein Handy nicht gut!

Wenn Sie jedoch eine Bibliothek schreiben, haben Sie wahrscheinlich nicht das Problem, dass mehrere Parteien einen gemeinsamen Standard auf inkompatible Weise interpretieren. In diesem Fall würde ich streng sein, was Sie akzeptieren, weil es Unklarheiten beseitigt.

Die Jargon-Datei enthält auch eine Horrorgeschichte über das "Erraten" der Absicht eines Benutzers.


Sehr amüsante Geschichte :) Mir ist klar, dass Sie möglicherweise mehr Spielraum benötigen, wenn Sie versuchen, mit vorhandenen Systemen zu interagieren, denn wenn es nicht funktioniert, werden Sie dafür verantwortlich gemacht.
Matthieu M.

Wenn Ihr Telefon mit den meisten anderen Telefonen nicht funktioniert, ist Ihr Telefon in der Tat schlecht .
SamB

1
@SamB: Ersetze schlecht durch kaputt .
Deworde

3

Sie haben Recht, die Regel gilt für Protokolle und nicht für die Programmierung. Wenn Sie beim Programmieren einen Tippfehler machen, erhalten Sie beim Kompilieren eine Fehlermeldung (oder beim Ausführen, wenn Sie einer dieser dynamischen Typen sind). Es gibt nichts zu gewinnen, wenn man den Computer für Sie raten lässt. Im Gegensatz zu den gewöhnlichen Leuten sind wir Ingenieure und in der Lage, genau das zu sagen, was ich meine. ;)

Wenn ich eine API entwerfe, würde ich sagen, dass ich nicht dem Robustheitsprinzip folge. Wenn der Entwickler einen Fehler macht, sollte er das sofort herausfinden. Wenn Ihre API Daten aus einer externen Quelle wie einer Datei verwendet, sollten Sie natürlich nachsichtig sein. Der Benutzer Ihrer Bibliothek sollte sich über seine / ihre eigenen Fehler informieren, aber nicht über die anderer.

Abgesehen davon würde ich vermuten, dass "Silent Failure" im TCP-Protokoll zulässig ist, da Sie andernfalls mit Fehlermeldungen bombardiert würden, wenn Leute fehlerhafte Pakete auf Sie werfen würden. Genau dort ist das einfacher DoS-Schutz.


1
"Wenn Sie während des Programmierens einen Tippfehler machen, erhalten Sie eine Fehlermeldung, sobald Sie kompilieren." Ich präsentiere Ihnen die Millionen von Compiler-WARNUNGEN, die ein Standard-Compiler ausspucken wird, während er immer noch perfekt ausführbare Aufgaben erzeugt.
Deworde

1

IMO, Robustheit ist eine Seite eines Designkompromisses und kein "bevorzugtes" Prinzip. Wie viele darauf hingewiesen haben, stinkt nichts so sehr, als vier Stunden lang zu blasen, um herauszufinden, wo Ihr JS schief gelaufen ist. Nur ein einziger Browser hat mit XHTML Strict das Richtige getan. Sie hat die Seite in Stücke gerissen, als ein Teil des bereitgestellten HTML-Codes eine völlige Katastrophe war.

Auf der anderen Seite, wer möchte die Dokumentation für eine Methode nachschlagen, die 20 Argumente verwendet und darauf besteht, dass sie genau in derselben Reihenfolge mit leeren oder Null-Wert-Platzhaltern für die, die Sie überspringen möchten, vorliegen? Die ebenso furchtbare robuste Art, mit dieser Methode umzugehen, wäre, jedes Argument zu überprüfen und zu erraten, welches für was war, basierend auf relativen Positionen und Typen und dann stillschweigend zu scheitern oder zu versuchen, mit bedeutungslosen Argumenten "auszukommen".

Oder Sie können Flexibilität in den Prozess einbauen, indem Sie eine Objekt-Literal / Wörterbuch / Schlüssel-Wert-Paar-Liste übergeben und die Existenz jedes Arguments so behandeln, wie Sie es erreichen. Für den ganz kleinen Perfomance-Kompromiss ist das ein Kuchenszenario und es auch zu essen.

Das Überladen von Args auf intelligente und schnittstellenkonsistente Weise ist eine clevere Art, robust gegenüber Dingen zu sein. Das Gleiche gilt für das Backen von Redundanz in ein System, bei dem angenommen wird, dass die Paketzustellung regelmäßig nicht in einem äußerst komplizierten Netzwerk erfolgt, das sich in einem aufstrebenden Technologiefeld mit einer Vielzahl potenzieller Übertragungsmittel im Besitz und von jedem befindet.

Es ist jedoch niemals ein guter Kompromiss, ein böses Versagen zu tolerieren, insbesondere in einem von Ihnen kontrollierten System. Zum Beispiel musste ich eine Verschnaufpause einlegen, um zu vermeiden, dass ich bei einer anderen Frage, ob JS am oberen oder unteren Rand der Seite platziert werden soll, einen zischenden Anfall bekomme. Einige Leute bestanden darauf, dass es besser sei, JS an die Spitze zu setzen, denn wenn die Seite dann nicht vollständig geladen werden könne, hätten Sie möglicherweise noch einige Funktionen. Halbnutzenseiten sind schlimmer als komplette Büsten. Bestenfalls führen sie zu mehr Besuchern Ihrer Website, wenn Sie zu Recht davon ausgehen, dass Sie inkompetent sind, bevor Sie davon erfahren, als wenn die kaputte Seite einfach auf eine Fehlerseite weitergeleitet wird, wenn die eigene Validierungsprüfung fehlschlägt, gefolgt von einer automatisierten E-Mail an jemand, der etwas dagegen tun kann.

Der Versuch, die 2010-Funktionalität in einem 1999-Browser bereitzustellen, wenn Sie nur eine Seite mit niedrigerer Technologie bereitstellen könnten, ist ein weiteres Beispiel für einen tollkühnen Design-Kompromiss. Die Chancen und das Geld, das ich für die Zeit der Entwickler verschwendet habe, die ich für Fehlerumgehungen aufgewendet habe, nur um abgerundete Ecken für ein Element zu erhalten, das zum Beispiel über einem! @ # $ Ing-Hintergrund mit Farbverlauf schwebt, haben mich völlig umgehauen. Und wofür? Bereitstellung von High-Tech-Seiten mit schlechter Leistung für erprobte Technophobiker, wobei Sie die Auswahlmöglichkeiten für High-End-Browser einschränken.

Damit es die richtige Wahl ist, sollte die Wahl, die Eingabe auf robuste Weise zu handhaben, auf beiden Seiten des Problems kurz- und langfristig das Leben erleichtern.


4
"Für eine Methode, die 20 Argumente benötigt"> muss nicht weiter nachgesehen werden, nach 5/6 ist die Methode falsch . Vielen Dank für die Antwort :)
Matthieu M.

1

Versage niemals leise . Abgesehen davon klingt es nicht nach einer schlechten Idee, zu erraten, was der Benutzer einer API / Bibliothek wollte. Ich würde es aber nicht folgen; Eine strenge Anforderung kann Fehler im aufrufenden Code und / oder Fehlinterpretationen Ihrer API / Bibliothek aufdecken.

Darüber hinaus kommt es, wie bereits erwähnt, darauf an, wie schwer es ist, zu erraten, was der Benutzer erwartet. Wenn es sehr einfach ist, haben Sie zwei Fälle:

  1. Ihre Bibliothek sollte etwas anders gestaltet sein (benennen Sie eine Funktion um oder teilen Sie sie in zwei Teile), damit der Benutzer erwarten kann, was Sie tatsächlich bereitstellen.
  2. Wenn Sie der Meinung sind, dass Ihre Bibliothek ordnungsgemäß entworfen wurde und eine eindeutige Benennung bedeutet, können Sie versuchen, auf die Absicht des Benutzers zu schließen.

In jedem Fall, wenn es nicht 100% offensichtlich und deterministisch ist, dass eine Eingabe in eine andere konvertiert werden sollte, sollten Sie die Konvertierungen aus einer Reihe von bereits erwähnten Gründen nicht durchführen (Verstoß gegen die Kompatibilität beim Refactoring, geringstes Erstaunen der Benutzer).

Im Umgang mit einem Endbenutzer ist der Versuch, seine Eingaben / Vermutungen zu korrigieren, sehr willkommen. Es wird erwartet , dass er ungültige Informationen eingibt. Dieser Fall ist völlig unüblich. Ein anderer Entwickler ist jedoch kein einfacher, nicht technischer Benutzer. Er hat das Fachwissen, um einen Fehler zu verstehen, und der Fehler kann für ihn von Bedeutung sein. Daher stimme ich Ihnen beim Entwerfen strenger APIs zu, während Strenge natürlich mit Klarheit und Einfachheit einhergeht.

Ich würde empfehlen, dass Sie diese Frage von mir lesen , von einem ähnlichen Fall.

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.