Bitte um Kritik zu einer meiner C++ Library
-
@_ro_ro sagte in Bitte um Kritik zu einer meiner C++ Library:
Dann erkläre mir doch einmal bitte was ein professioneller Entwickler erwartet wenn er willkürlich die Eigenschaft einer Klasseninstanz ändert.
Geht es darum:
s.day = -7;
?
Meiner Erfahrung nach passieren die wenigsten Fehler beim Erstellen neuer Funktionen, sondern beim Erweitern von (Fremd-) Code.
Hier könnte z.B. sowas passieren://Version 1.0.0: Setze Datum int day = 4; s.day = day; // Version 1.0.1: Gaaanz viel weiterer Krams int day = 4; // ...Krams s.day = day; // Version 1.0.2: Day muss vom Benutzer eingegeben werden int day; cin << day; // ...Krams der verdeckt, dass die Lib offenbar keine Lust hat Fehler abzufangen s.day = day;
Die Entwickler waren vielleicht nicht sehr gewissenhaft, aber boshaft war keiner. Trotzdem ist der Code Schrott und der Projektleiter entschuldigt sich, dass er eine Lib vorgeschlagen hat, die noch nicht mal versucht fehlerhafte Handhabung abzufangen.
-
@_ro_ro sagte in Bitte um Kritik zu einer meiner C++ Library:
Haben Sie denn versucht, meine Antworten zu verstehen? Warum ich z.B. eine string-Exception werfe?
Und ja, ich denke schon daß day, mon, und year selbstsprechende Variablen sind.
MFG
@_ro_ro Wenn man nach einem Review fragt und Hilfe haben möchte, dann muss man auch mit kritischen Antworten zurechtkommen... Du bist doch nicht aus Zucker, und es ist auch noch kein Meister vom Himmel gefallen.
mon für Monat ist denkbar schlecht gewählt und dein err-Handling auch.
-
@firefly sagte in Bitte um Kritik zu einer meiner C++ Library:
@_ro_ro sagte in Bitte um Kritik zu einer meiner C++ Library:
Haben Sie denn versucht, meine Antworten zu verstehen? Warum ich z.B. eine string-Exception werfe?
MFG
Und du solltest dich mal mit std::exception selbst und von dieser abgeleiteten klassen von std::exception beschäftigen.
Alle direkt von std::exception abgeleitete klassen haben alle einen konstructor der einen string als parameter nimmtUnd was ist dann besser, als ein einfaches
throw string("Datum ungültig")
?
-
@omggg sagte in Bitte um Kritik zu einer meiner C++ Library:
@_ro_ro sagte in Bitte um Kritik zu einer meiner C++ Library:
Haben Sie denn versucht, meine Antworten zu verstehen? Warum ich z.B. eine string-Exception werfe?
Und ja, ich denke schon daß day, mon, und year selbstsprechende Variablen sind.
MFG
@_ro_ro Wenn man nach einem Review fragt und Hilfe haben möchte, dann muss man auch mit kritischen Antworten zurechtkommen... Du bist doch nicht aus Zucker, und es ist auch noch kein Meister vom Himmel gefallen.
mon für Monat ist denkbar schlecht gewählt und dein err-Handling auch.
Warum ist das err-Handling schlecht?
-
meine Frage war, was ein Entwickler erwartet wenn er versucht, Eigenschaften von Objekten willkürlich zu ändern. Daß es möglich ist war nicht die Frage.
MFG
-
@_ro_ro sagte in Bitte um Kritik zu einer meiner C++ Library:
@firefly sagte in Bitte um Kritik zu einer meiner C++ Library:
@_ro_ro sagte in Bitte um Kritik zu einer meiner C++ Library:
Haben Sie denn versucht, meine Antworten zu verstehen? Warum ich z.B. eine string-Exception werfe?
MFG
Und du solltest dich mal mit std::exception selbst und von dieser abgeleiteten klassen von std::exception beschäftigen.
Alle direkt von std::exception abgeleitete klassen haben alle einen konstructor der einen string als parameter nimmtUnd was ist dann besser, als ein einfaches
throw string("Datum ungültig")
?Zum einen weil für const char strings, wie in deinem Beispiel, memory allokiert wird. (Und Memory allokation können auch exception schmeißen wenn die aktion fehlschlägt)
Zusätzlich kann man eine generischen catch clause nutzen für alle std::exception varianten mit der man auch die Meldung ausgeben kann.
Besonders wenn dann unter umständen auch die c++ runtime oder STL methoden exception schmeißen!void test_function(int day) { if (day < 0) throw std::logic_error("Datum ungültig"); std::string("abc").substr(10); // throws std::out_of_range } try { test_function(); } catch (const std::exception& e) { std::cout << e.what() << '\n'; }
-
Na. Das ist doch mal ne Antwort. Und gleich noch eine Rückfrage, weil das auch bemängelt wurde:
Warum in C++ keine Casts im legacy C-Style?
MFG
-
Ich zeige Ihnen hier mal die Anwendung, damit Sie besser verstehen, warum ich bestimmte Dinge ebenso umgesetzt habe:
#include "Scaliger.cpp" // split am Leerzeichen void split_date(int dmy[], const string &date){ istringstream ss(date); string token; int i = 0; while (ss >> token){ dmy[i] = my::atoi(token); i++; } } void DateCalc(Response &r){ // initial CGI cgi; Scaliger sca; // Systemdatum r.stash("datediff","0"); r.stash("date1", sca.Tag()+" "+sca.Monat()+" "+sca.Jahr() ); r.stash("date2", sca.Tag()+" "+sca.Monat()+" "+sca.Jahr() ); r.stash("datediff","0"); r.stash("wotag1", sca.Tagname()); r.stash("wotag2", sca.Tagname()); int dmy_1[3] = {0,0,0}; int dmy_2[3] = {0,0,0}; if( cgi.param("ccdiff").length() ){ string date1 = cgi.param("date1"); string date2 = cgi.param("date2"); split_date(dmy_1, date1); Scaliger sca1(dmy_1[0], dmy_1[1], dmy_1[2]); split_date(dmy_2, date2); Scaliger sca2(dmy_2[0], dmy_2[1], dmy_2[2]); r.stash("date1", sca1.Tag()+" "+sca1.Monat()+" "+sca1.Jahr() ); r.stash("date2", sca2.Tag()+" "+sca2.Monat()+" "+sca2.Jahr() ); r.stash("datediff", to_string( sca1.datediff(sca1, sca2) )); r.stash("wotag1", sca1.Tagname()); r.stash("wotag2", sca2.Tagname()); } else if( cgi.param("jdadd").length() ){ string date2 = cgi.param("date2"); split_date(dmy_2, date2); string jd_input = cgi.param("datediff"); Scaliger sca2(dmy_2[0], dmy_2[1], dmy_2[2]); Scaliger sca1 = sca2.AddiereTage( my::atoi(jd_input) ); r.stash("date1", sca1.Tag()+" "+sca1.Monat()+" "+sca1.Jahr() ); r.stash("date2", sca2.Tag()+" "+sca2.Monat()+" "+sca2.Jahr() ); r.stash("datediff", cgi.param("datediff")); r.stash("wotag1", sca1.Tagname()); r.stash("wotag2", sca2.Tagname()); } }
Es ist eine Anwendung die Benutzereingaben verarbeitet. Wie Sie sehen, obenstehender Code hat keine Fehlerbehandlung weil diese an einer anderen Stelle über die Response-Erstellung erfolgt.
Anm: Die Response-stash-Methode setzt nur die Platzhalter im HTML-Template.
MFG
-
@_ro_ro
Du verstehst nicht wovon wir hier reden.Deine Ansicht:
Ich habe hier eine Klasse, die für meine Eingaben die richtigen Ergebnisse liefert, bitte Kritik und Verbesserungsvorschläge.Ansicht DocShoe
Die Umsetzung verletzt so ziemlich alle OOP Prinzipien, das ist Murks.Darauf antwortest du:
Deine Einwände sind egal, die Klasse wird sowieso nur intern benutzt. Plausibilitätsprüfungen muss ich nicht machen, das macht das aufrufende Framework schon für mich.Daraus schließe ich:
Du bist nicht an Kritik und Verbesserungsvorschläge interessiert. Dinge wie Wiederverwendbarkeit und Datenkonsistenz spielen hier keine Rolle. Darum spielen Kritik und Verbesserungsvorschläge auch keine Rolle, denn die Klasse tut ja das, was sie soll und liefert die richtigen Ergebnisse. Du argumentierst mit Ergebnissen, ich mit Codequalität, und das verstehst du nicht. Das unterscheidet Frickler und Softwareentwickler. Und damit haben wir beide keine Grundlage, auf der wir über deinen Code diskutieren können.
-
ich kann Sie doch genausogut fragen warum Sie hier im Forum sind. Und was bitte soll daran schlecht sein wenn ich stolz auf das Erreichte bin?
Ansonsten sind hier ja immer noch ein paar Fragen offen. Denn ich will ja auf jedem Fall was lernen, was mir besser gelingen würde wenn die Antworten verständlicher wären.
mfg
-
und noch etwas,
da http://www.willemer.de/informatik/cpp/timelib.htm
Die Zeitfunktionen gehören nicht zu den C++-Bibliotheken, sondern sind ein Erbstück von C.
Meine Frage ist, wenn ich mit
tm *nun;
einen Pointer erstelle, bleibt da nicht ein Speicherleck? Denn die gezeigten Beispiele beinhalten keinfree
oderdelete
MFG
-
@_ro_ro sagte in Bitte um Kritik zu einer meiner C++ Library:
ich kann Sie doch genausogut fragen warum Sie hier im Forum sind.
Was tut das zur Sache? Aber na gut: Weil ich von Leuten, die von Softwareentwicklung/C++ mehr Ahnungen haben als ich, Hilfe wollte. Und mit deren Hilfe habe ich viel dazugelernt.
Und was bitte soll daran schlecht sein wenn ich stolz auf das Erreichte bin?
Weil es dich blind macht gegenüber Verbesserungen. Du bist so stolz, dass du Kritik nicht akzeptieren kannst, weil es deine Leistung herabwürdigt und wir das Ergebnis nicht so honorieren, wie du es erwartest.
Ansonsten sind hier ja immer noch ein paar Fragen offen. Denn ich will ja auf jedem Fall was lernen, was mir besser gelingen würde wenn die Antworten verständlicher wären.
Da ist Eigeninitiative gefragt. Ich habe dir Stichpunkte genannt, nach denen man mit <Suchmaschine deiner Wahl> suchen könnte.
-
@_ro_ro sagte in Bitte um Kritik zu einer meiner C++ Library:
meine Frage war, was ein Entwickler erwartet wenn er versucht, Eigenschaften von Objekten willkürlich zu ändern. Daß es möglich ist war nicht die Frage.
MFG
Hallo,
wenn du einen 2-Zeiler hast und ein Entwickler in den 2 Zeilen bewusst Blödsinn macht, dann kannst du natürlich die rhetorische Frage stellen, was der Entwickler dann erwartet.
Ich habe versucht an einem Beispiel zu zeigen, warum das aber im Verlauf der Softwareentwicklung vom 2-Zeiler zu einem nicht mehr so offensichtlichen Fehler werden kann und es deshalb wichtig ist, dass man sich auf die libs die man verwendet verlassen können muss.
Und ansonsten schließe ich mich @DocShoe an: Worüber reden wir hier? Ob diese lib die du im stillen Kämmerlein nutzt für dich gut ist oder ob man generell eine Lib so aufbauen würde? Ersteres weißt du selber besser als wir, letzteres wurde zurecht kritisiert (was du doch auch haben wolltest!?).
-
@DocShoe sagte in Bitte um Kritik zu einer meiner C++ Library:
Weil es dich blind macht gegenüber Verbesserungen. Du bist so stolz, dass du Kritik nicht akzeptieren kannst,
Unsinn. Die Kritik habe ich längst umgesetzt. Das zeigt die Anwendungsklasse die ich hier auch gepostet habe: Sämtliche Instanz-Eigenschaften sind private und nur über Gettermethoden zugänglich.
MFG
-
@_ro_ro Puh, ist einiges dazu gekommen hier.
Was ich von einer Klasse erwarte: Ein ordentlich dokumentiertes, möglicht kleines, public Interface, verifiziert durch Unittests. Die Klasse stellt sicher, das sie sich immer in einem wohldefinierten Zustand befindet. (z.B. durch die Überprüfung von User Eingaben (Entwickler = User)) und es treten durch die Verwendung der Klasse keine Seiteneffekte auf. Eine falsche Verwendung der Klasse führt zu Fehlern, entweder als Exception oder Fehlermeldung zur Laufzeit, noch etwas besser, wenn möglich, als Fehler zur Compilezeit.
Warum das ganze, also Trennung von Interface und Implementierung, public / private, const non-const etc:
- Es dokumentiert direkt im Code die vom Entwickler erwartete Nutzung
- Im Fehlerfall sind die Schnittstellen zu anderen Programmteilen an wenigen definierten Orten, an denen man überprüfen kann, auf welcher Seite der Fehler passiert (vor oder in der Library).
- Gerade für den Fehlerfall ist auch const-correctness wichtig; man kann direkt sehen, wo sich überhaupt Dinge ändern können.
- Im Falle von Änderungen an den Interna der Library funktioniert Code, der die Library verwendet einfach weiter.
- Wenn jemand anderes den Code erweitert (oder man selbst nach einiger Zeit) ist direkt klar, was wie gemeint ist und Änderungen führen nicht zu unerwünschten Seiteneffekten an anderen Stellen.
Unittests sind im ürbigen auch eine gute Möglichkeit als Entwickler zu dokumentieren, wie man sich die Nutzung einer Bibliothek vorstellt.
In der Entwicklung mit modernem C++ als multiparadigmen Sprache führen viele Wege nach Rom. Aber es gibt ein paar Dinge, die sich als Best Practise durchgesetzt haben. Neben dem Punkt, dass es für die Dinge in der Regel gute Gründe gibt, führt die Einhaltung von Best Practice dazu, das andere Entwickler den Code besser und schneller verstehen.
Eine erste Anlaufstelle um sich mit Best Practise im Bereich C++ auseinanderzusetzen sind sicherlich die C++ Core Guidelines
Zum Thema Exception vs "throw string" ist ja schon einiges gesagt worden. Ich würde noch zusätzlich ergänzen wollen, nutze
std::exception
weil das erwartet wird. Wenn andere deine Library verwenden und die Excpetions werfen kann, werden die Anwender irgendwo Excpetions gefangen, z.b. mitcatch(std::exception& ex)
und dann weiterverarbeiten. Niemand versuchtcatch(std::string& err)
und das Programm fliegt einem im Fehlerfall um die Ohren, bzw, wenn es gut läuft, gibt es noch eincatch(...)
wo dann aber nicht mehr klar ist, von wo die Exception kommt.P.S. Von
std::exception
kann man ableiten, wenn man eine eigene Exception haben möchte.
-
auf Ihre ausführliche Darstellung antworte ich gerne. Natürlich bin ich mit den Grundsätzen vertraut die Sie hier erneut auflisten. Was den Umgang mit Exceptions betrifft: Als Entwickler von Webanwendungen nutze ich Exceptions in erster Linie dazu, dem Anwender eine aussagekräftige und verständliche Meldung zu hinterlassen wenn er beispielsweise ein ungültiges Datum eingibt. Dabei geht es mir um ein bischen mehr als einfach nur eine Exception aufzufangen und eine Ausgabe in Plaintext. Das heißt, daß alle bisherigen Benutzereingaben im Webformular verbleiben, nur daß das Formular um die Fehlermeldung ergänzt wird, idealerweise über einen Platzhalter nahe der Stelle wo's passiert ist (Edit: Auf der Beispielseite bereits umgesetzt).
Im Sinne von Laufzeitfehlern, höhere Gewalt oder sonstigen Unverhersehbarem spielen Exceptions natürlich auch eine Rolle, in solchen Fällen würde eine Fehlerseite in Plaintext völlig reichen, denn wenn beispielsweise der MySQL-Server nicht erreichbar ist, macht jede weitere Eingabe keinen Sinn.
Und dann gäbe es natürlich auch eine dritte Art von Exceptions die zu werfen sind wenn ein Anwender versucht vorsätzlich Schäden anzurichten (dieses Thema hatte ich hier auch schon angesprochen).
Danke nochmal und viele Grüße!
-
@_ro_ro Ich glaube, jetzt hast du den Dreh raus.
-
@DocShoe sagte in Bitte um Kritik zu einer meiner C++ Library:
- warum ist das Ganze überhaupt eine Klasse? Das kann man auch als freie Funktion implementieren, die eine Struktur mit Datumsinformationen zurückgibt.
Um auf diese Frage einmal etwas ausführlicher einzugehen: Ein Tag ist mehr als nur ein Datum. Das Datum ist nur eine Eigenschaft, weitere Eigenschaften wären:
- Numerischer Tag (lange Zählung),
- Der Name des Wochentages,
- Der Name des Monats,
- Kalenderwoche,
- Der Name des Kalenders (Julianisch, Gregorianisch ...),
- Schaltjahr,
- usw.
Und insofern ist das schonmal mehr als nur eine Datenstruktur, also ein Objekt, eine Instanz einer Klasse. Wobei die Klasse Methoden definiert welche die Instanz ausführen kann um z.B. Tage zu addieren, inkrementieren, Differenzen berechnen und natürlich Datumsumrechnungen in einen anderen Kalender (Maya, Julianisch, Gregorianisch).
Sie sehen also, es gibt mehr als nur einen Gund, Tage zu Instanzen einer Klasse zu machen. Mit einer herkömmlichen Herangehensweise wird das nämlich sehr schnell unübersichtlich. Ebenso vereinfacht sich mit OOP die Art und Weise der Fehlerbehandlung von Benutzereingaben. Bspw. wird die Instanz gar nicht erst erstellt wenn ein ungültiges Datum eingegeben wurde.
Und was das Systemdatum anbetrift: Dieses uralte C-tm-Vehikel brauchen wir gar nicht. Es genügt der Aufruf der Funktion
std::time(nullptr)
das gibt dann die Anzahl der Tage, fertig.Welche Exceptionklasse schlagen Sie denn vor für den Fall fehlerhafter Benutzereingaben?
MFG
-
ein tag ist weder ein schaltjahr, noch interessiert es ihn welcher kalender grade genutzt wird.
alles was du aufgezaehlt hast, laesst sich anhand des datums berechnen, sofern bekannt welcher kalender es denn nun ist.dein grundsaetzlicher datensatz ist also ein datum...
-
@_ro_ro Ich halte das so: Exceptions nur für wirkliche Ausnahmen. Eine fehlerhafte Nutzereingabe, wenn der Nutzer, der Nutzer der GUI (in deinem Fall der Internetseite) ist, würde ich überhaupt nicht über Exceptions lösen, sondern als einen von vielen normalen Fällen behandeln, Fehler ausgeben und weiter machen.
Wenn es darum geht, das ein Entwickler die Library falsch nutzt, schon eher. Bei Exceptions muss man auch ein bisschen aufpassen, damit alles in einem wohldefiniertem Zustand bleibt. Stichwort: Exception Safety.