Softwaredesign in C++ im Vergleich zu Softwaredesign in Java/C#



  • softwaredesign schrieb:

    Wie immer gehst du auf nichts fachlich großartig ein sondern verbreitest recht spöttisch weiterhin irgendwelche Pauschalisierungen. Es scheint, als könntest du aus der eigenen Weltanschauung nur schwer ausbrechen und reagierst dementsprechend spottend oder belächelnd, wenn du mit etwas konfrontiert wirst, was du nicht kennst oder noch nicht verwendet hast...

    Du bist nicht der erste (üblicherweise unregistrierte) Pinscher, der glaubt, sich beweisen zu müssen, indem er versucht, mir an Bein zu pinkeln.



  • Vielleicht nimmst du das mal zum Anlass darüber nachzudenken, ob deine Pauschalisierungen immer so treffend sind. 🙂



  • Eisflamme schrieb:

    Wenn die Abstraktion die Komplexität erhöht, dann hat man was falsch gemacht. Abstraktion dient dazu, die Komplexität zu reduzieren.

    Dann ist für mich so gut wie jede Factory in Java ein praktisches Gegenbeispiel.

    Die Factory dient in der Regel dazu, die konkrete Instantiierung zu abstrahieren. Die Applikation sagt dann nur noch "gib mir das Objekt" statt "ich erzeuge das Objekt indem ich diese und jene Schritte mache".

    Die Factory kann solche komplexen Sachen wie Pooling oder andere Sachen hinter einer einfachen Funktion verbergen und dadurch die Applikation selbst vereinfachen.



  • Betonung auf kann.



  • tntnet schrieb:

    Die Factory kann solche komplexen Sachen wie Pooling oder andere Sachen hinter einer einfachen Funktion verbergen und dadurch die Applikation selbst vereinfachen.

    👍
    Deshalb verstecke ich präventiv alle Konstruktoren hinter Factories. Oft wird die Factory sogar zum Singleton.



  • In C++ habe ich noch keine Factory verwendet und Singletons kommen seit langem nicht mehr vor. Und wenn ich Klassen als *Manager benennen wuerde, dann denke ich nochmals ueber mein Design nach, um das zu vermeiden.

    PS: Hier wird mir zu viel im Konjunktiv argumentiert.



  • Bitte ein Bit schrieb:

    Dann ist für mich so gut wie jede Factory in Java ein praktisches Gegenbeispiel.

    Fehler: Nur weil jemand ein Design-Pattern falsch angewendet hat, bedeutet dies nicht dass das Pattern falsch ist.

    Darum schrieb ich praktisch. Theoretisch kann man das, wie auch gesagt wurde, schön hinter einer Funktion verbergen, aber bei einer Abstract Factory auch das nicht.

    Würde man die Erstellung einer Klasse nicht auslagern und folglich auch die Erstellung nicht abstrahieren, so hätten wir eine Klasse weniger (freie Funktion oder statische Methode ist zumindest nach Gang of Four keine Factory und auch keine Factory Method). Im Falle der Factory haben wir aber eben die eine Klasse mehr und auch eine Datei mehr. Wie definiert ihr denn Komplexität? Klar, würde man die Factory durch eine Alternative ersetzen, würde das Pattern die Komplexität nicht erhöhen. Aber ich sah auch schon Projekte, wo einfach Mal eine Factory eingesetzt wurde, um "Erweiterbarkeit" einzupflanzen, die nie genutzt wurde. Dann sorgt (falsch eingesetzte, leicht gesagt, schwer zu definieren ex ante) Abstraktion für Komplexitätssteigerung, solange man die Abstraktion nicht nur für einen Zweck nutzt und das passiert imo durchaus oft.

    Somit finde ich schon, dass die Komplexität zumindest im Sinne von Anzahl der Dateien, Anzahl der Klassen und meist auch LOCs steigt. Die Sache ist aber einfach, dass ich das jederzeit in Kauf nehmen würde. Wiederverwendbarkeit... kann man drüber streiten. Aber Änderbarkeit und v.a. Erweiterbarkeit profitieren meiner Meinung nach einfach enorm davon. Dann lieber eine Klasse oder ein paar Abstraktions-Ebenen (!= tiefere Klassenhierarchie) mehr.



  • Wie schon angedeutet, sollte man nicht mit Spatzen auf Kanonen schießen. Das ist meines Erachtens genauso falsch wie die präventive Nutzung eines Design Patterns.

    Aber mich stört die Verallgemeinerung das Abstraktion etwas potenziell Böses ist. Ich habe diesbezüglich aber vermutlich schon zu viele Extreme erlebt. 😉

    Ich bekomme beispielsweise regelmäßig die Krätze wenn ich ein Algorithmus X-fach implementieren muss, nur weil Templates böse sind.



  • http://discuss.joelonsoftware.com/?joel.3.219431.12

    Ist schon in die Jahre gekommen, aber wer es noch nicht kennt: unbedingt lesen.



  • tntnet schrieb:

    Wenn ich eine relativ komplexe Schnittstelle habe und diese abstrahiere, um sie einfacher bedienbar zu machen, dann reduziert das die Komplexität.

    Nein, die Komplxität wird immer erhöht. Es kann sein, dass die gefühlte Komplexität in einem bestimmten Anwendungsfall geringer wird, aber die Komplexität über das Gesamte Programm steigt an:

    Mehr Interfaces
    Mehr Klassen
    Mehr unterschiedliche Anwendungsmuster
    Mehr Dinge zu lernen
    Mehr mögliche Fehlerquellen

    Eine gute Abstraktion kann lokal Komplexität verstecken, diese geht dann aber nicht gelangweilt weg, sondern wartet hinter der nächsten Ecke um zuzuschlagen: Leaky Abstraction Theorem eben.



  • Shade Of Mine schrieb:

    http://discuss.joelonsoftware.com/?joel.3.219431.12

    Ist schon in die Jahre gekommen, aber wer es noch nicht kennt: unbedingt lesen.

    Das ist ja schön und wahr, aber wenn ich in erster Linie gigantische Staudämme statt Gewürzregale baue dann kann sich der Mehraufwand der Factory schon auszahlen. Bei Gewürzregalen hat es wohl auch wenig Sinn da viel Aufwand in Softwaredesign zu stecken, da zählt wohl nur der schnelle Erfolg.

    MfG SideWinder



  • SideWinder schrieb:

    Shade Of Mine schrieb:

    http://discuss.joelonsoftware.com/?joel.3.219431.12

    Ist schon in die Jahre gekommen, aber wer es noch nicht kennt: unbedingt lesen.

    Das ist ja schön und wahr, aber wenn ich in erster Linie gigantische Staudämme statt Gewürzregale baue dann kann sich der Mehraufwand der Factory schon auszahlen. Bei Gewürzregalen hat es wohl auch wenig Sinn da viel Aufwand in Softwaredesign zu stecken, da zählt wohl nur der schnelle Erfolg.

    MfG SideWinder

    so viele staudämme gibt es nun auch wieder nicht... aber wir haben ja alle ein +20cm gehänge 😉



  • otze schrieb:

    Es kann sein, dass die gefühlte Komplexität in einem bestimmten Anwendungsfall geringer wird, aber die Komplexität über das Gesamte Programm steigt an:

    Nicht in meinem Verständnis vom Artikel.

    Programmkomplexität = Aufgabenkomplexität - (1-Leakyness)*Abstraktion

    Leakyness ist zwischen 0% (triviale Abstraktion), 20% (Normalfall), 50% (gutes grösseres Projekt) und >100% (absoluter Design-Fail).

    Ich möchte kein Programm ohne Abstraktion (=strukturloser Assemblercode) schreiben, auch kein kleines.

    Abstraktion:

    Mehr Interfaces
    Mehr Klassen
    Weniger Code
    Weniger Dinge zu lernen
    Weniger mögliche Fehlerquellen



  • otze schrieb:

    tntnet schrieb:

    Wenn ich eine relativ komplexe Schnittstelle habe und diese abstrahiere, um sie einfacher bedienbar zu machen, dann reduziert das die Komplexität.

    Nein, die Komplxität wird immer erhöht. Es kann sein, dass die gefühlte Komplexität in einem bestimmten Anwendungsfall geringer wird, aber die Komplexität über das Gesamte Programm steigt an:

    Mehr Interfaces
    Mehr Klassen
    Mehr unterschiedliche Anwendungsmuster
    Mehr Dinge zu lernen
    Mehr mögliche Fehlerquellen

    Eine gute Abstraktion kann lokal Komplexität verstecken, diese geht dann aber nicht gelangweilt weg, sondern wartet hinter der nächsten Ecke um zuzuschlagen: Leaky Abstraction Theorem eben.

    Ich nenne einfach mal ein paar Beispiele aus meine eigenen Praxis:

    Beispiel: Lesen von Daten vom Socket. Manche Programme verwenden direkt den Systemaufruf read. Dabei wird zumindest mal vergessen, SIGINTR abzufangen. Eventuell sogar ganz auf Fehlerbehandlung verzichtet, weil es ja eigentlich nicht passieren darf. Packe ich das in eine Abstraktionsschicht, die alles implementiert und im Fehlerfall eine Exception wirft, eventuell sogar mit Timeoutüberwachung, dann habe ich eine einfache und robuste read-Funktion. Meine Applikation wird weniger Komplex, da ich nicht überall all die unschönen Systemsachen beachten muss.

    Ein anderes Beispiel ist die Verwendung von OCI (=Oracle Call Interface) beim Zugriff auf Oracle Datenbanken. Das ist eine sehr komplexe und umfangreiche Schnittstelle, die auch sehr fehleranfällig ist. Ein mal in einen netten Wrapper (=Abstraktion) gepackt und ich kann einfach so SQL-Statements aus meiner Applikation abschicken. Eventuell sogar mit einem Treiberinterface, wo ich Oracle durch eine andere Datenbank austauschen kann. Kannst von mir aus OCI mit der C-API von Postgresql oder Mysql austauschen.

    Ich muss nur in meine eigene Toolbox rein schauen, was ich da schon alles abstrahiert habe und mein Leben einfacher macht, da meine Applikationen einfacher, robuster und weniger komplex werden. Da habe ich noch wesentlich mehr mehr oder weniger komplexe Sachen, die dort einfach hinter einem einfachen Interface versteckt sind.



  • Die gute alte Zwiebel... Damit kann man es aber auch leicht übertreiben.



  • Wer sagt, dass Abstraktion schlecht ist? Trotzdem folge ich nicht dem Java-Stil. Natuerlich habe ich eine Socketklasse, eine fuer RS232 und ... trotzdem erben sie nicht von einem Interface obwohl sie alle ein wait_for_event() und read(...) haben. Warten bis Daten verfuegbar sind und dann lesen, natuerlich mit timeout.



  • knivil schrieb:

    In C++ habe ich noch keine Factory verwendet und Singletons kommen seit langem nicht mehr vor. Und wenn ich Klassen als *Manager benennen wuerde, dann denke ich nochmals ueber mein Design nach, um das zu vermeiden.

    kommt es mir nur so vor oder wird das was einige machen (einer macht) einfach mal als die Art wie man in C++ programmiert definiert.



  • volkard schrieb:

    softwaredesign schrieb:

    Wie immer gehst du auf nichts fachlich großartig ein sondern verbreitest recht spöttisch weiterhin irgendwelche Pauschalisierungen. Es scheint, als könntest du aus der eigenen Weltanschauung nur schwer ausbrechen und reagierst dementsprechend spottend oder belächelnd, wenn du mit etwas konfrontiert wirst, was du nicht kennst oder noch nicht verwendet hast...

    Du bist nicht der erste (üblicherweise unregistrierte) Pinscher, der glaubt, sich beweisen zu müssen, indem er versucht, mir an Bein zu pinkeln.

    Auf die Idee, dass du auch mal was falsches sagst, kommst du wohl garnicht.

    volkard schrieb:

    Man zerlegt nicht für die Wiederverwendung, sondern um den Überblick zu behalten.

    Ist natürlich falsch. Man zerlegt für beides.



  • tntnet schrieb:

    Beispiel: Lesen von Daten vom Socket. Manche Programme verwenden direkt den Systemaufruf read. Dabei wird zumindest mal vergessen, SIGINTR abzufangen. Eventuell sogar ganz auf Fehlerbehandlung verzichtet, weil es ja eigentlich nicht passieren darf. Packe ich das in eine Abstraktionsschicht, die alles implementiert und im Fehlerfall eine Exception wirft, eventuell sogar mit Timeoutüberwachung, dann habe ich eine einfache und robuste read-Funktion.

    Das ist keine Abstraktion. Du transformierst den Fehler nur. Aus einem return value machst du ein Exception. Daran ist exakt gar nichts abstrakt. Nur deine Time-out Überwachung würde was bringen. Aber das ist keine Abstraktion, das ist eine Time-out Überwachung.

    Ein mal in einen netten Wrapper (=Abstraktion)

    Quatsch. Der Wrapper ist kein Abstraktion, sondern die abstrakten Konzepte die du mithilfe des Wrappers ausdrücken kannst. Eine 1:1 Darstellung eines C-Interfaces durch einen Wrapper ist keine Abstraktion. Ein fehlerhaftes Interface durch ein besseres auszutauschen ist die Korrektur eines Designfehlers, aber keine Abstraktion.

    Wikipedia:
    "'An abstraction' - a concept that acts as a super-categorical noun for all subordinate concepts, and connects any related concepts as a group, field, or category."

    Eventuell sogar mit einem Treiberinterface, wo ich Oracle durch eine andere Datenbank austauschen kann.

    Nun reden wir von Abstraktion. Aber dein "eventuell" besagt, dass du das eventuell gar nicht implementiert hast?

    Bislang sehe ich kein Beispiel dafür, wo du eine Gruppe von Dingen vereinheitlicht hast, sodass sich die Gesamtkomplexität verringert hat. Das geht auch nicht. Wenn du abstrahierst, musst du nicht nur die Objekte verstehen, die unter dieser Abstraktion zusammengefasst werden, sondern zusätzlich die Abstraktion selbst. Natürlich sorgt eine gute Abstraktion dafür, dass in einm konkreten Kontext die wahrgenommenee Komplexität verringert wird. Aber wenn sich jemand in das Projekt einarbeiten muss, muss er trotzdem die Abstraktion verstehen.

    @wikileaks
    Ich will auch kein Programm in Assembler schreiben. Es ändert aber nichts daran, dass ich wissen muss, welchen Code der compiler erzeugt, ob ich den prozssorcache ordentlich ausnutze(und überhaupt dass es einen gibt und was er macht) und ob der Code vektorisiert wird.



  • otze schrieb:

    @wikileaks
    Ich will auch kein Programm in Assembler schreiben. Es ändert aber nichts daran, dass ich wissen muss, welchen Code der compiler erzeugt, ob ich den prozssorcache ordentlich ausnutze(und überhaupt dass es einen gibt und was er macht) und ob der Code vektorisiert wird.

    Das trifft ja mal wohl für 90% der Softwareentwickler nicht zu. Also klingt mir der Absatz stark nach verallgemeinertem Quatsch.

    MfG SideWinder


Anmelden zum Antworten