Softwaredesign in C++ im Vergleich zu Softwaredesign in Java/C#
-
asc schrieb:
Man kann den Grad der Wiederverwendbarkeit erhöhen, wenn man gleichzeitig die Komplexität erhöht. Um eine Komponente wiederverwendbar zu machen, muss diese in der Regel stärker abstrahiert werden, als es im konkreten Projekt nötig (und häufig auch sinnvoll) ist.
Du sagst also, dass es im Prinzip gar nicht wirklich notwendig ist, diesem Wiederverwendbarkeits-Stil zu folgen?
Dass es also nur ein Goodie ist, aber man in der Praxis viel direkter und problembezogener implementiert?
-
Manches lässt sich Wiederverwenden, aber nach meiner Erfahrung ist dies insgesamt der kleinste Teil. Spätestens wenn konkrete Daten ins Spiel kommen, wird dies stark eingeschränkt. Bei typischen Businessanwendungen tendiert die Wiederverwendbarkeit gegen 0 (Heißt nicht das sie 0 beträgt).
Vor solchen Äußerungen habe ich richtig schiss...
Ich habe es schon erlebt dass solche Äußerungen zu einem Copy-Paste-Clone-Modify Vorgehensmodell mündete, s.d. der ein und selbe Fehler in X Projekten gefixt werden musste anstatt an einer zentralen Stelle. Nun schwiren halt so einige doppelte Definitionen in der Projektmappe rum...
Kann man an solchen Projekten wirklich nicht genug abstrahieren bzw. parametrisieren als dass man immer diesen anwendungsspezifischen Code schreiben könnte?
-
Sone schrieb:
Du sagst also, dass es im Prinzip gar nicht wirklich notwendig ist, diesem Wiederverwendbarkeits-Stil zu folgen?
Dass es also nur ein Goodie ist, aber man in der Praxis viel direkter und problembezogener implementiert?Ich sage das in der Praxis dies in der Regel noch nicht einmal ein "Goodie", sondern ein Hindernis ist. Wenn man nicht gerade aus anderen Gründen (wie TDD/IoC etc.) ohnehin eine hohe Abstraktion hat kostet es mehr als es nützt. Dies bedeutet gleichzeitig das es in der Regel kaum Wiederverwendbarkeit im Praxiseinsatz gibt.
softwaredesign schrieb:
danke für dein relativierendes Posting.
Wir betreiben halt hauptsächlich C# Entwicklung.In C# wird eine andere Form der Entwicklung betrieben, dies ist auch der Sprache geschuldet, die am Design ungeachtet aller Theorie doch entscheidenden Einfluss nimmt.
In C# greift man wesentlich eher zu Unit-Tests, diese wiederum haben massiven Einfluss auf das Design. Gleichzeitig ergänzt sich IoC und Unit-Tests durch die Abstraktion, so das man hier häufig beides findet oder zumindest das Design sich gegenseitig begünstigt.
-
softwaredesign schrieb:
Falsch!
In C# ist es zum Beispiel üblich, gewisse Klassen aus den einzelnen Schichten einer Software herauszuziehen, um sie dann in einem WCF-Dienst auf beiden Seiten gemeinsam verwenden zu können. Das hat nichts mit Übersicht zu tun sondern man möchte schlicht erreichen, dass Änderungen an Klassen der Domäne sofort auf beiden Seiten der Kommunikation greifen.Das ist ein Beispiel von vielen.
Hört sich aus ein wenig Abstand so an, als würdest Du normalerweise Gott-Klassen bauen und sie nur ganz selten mal schweren Herzens ein Bißchen zerlegen, weil ein Framework Dich dazu zwingt.
-
Wieviel sich wiederverwerten läßt, hängt auch vom Unternehmen ab. Wenn es tagein tagaus Verwaltungssoftware für Golfclubs trauspustet, läßt sich naturgemäß recht viel wiederverwerten.
-
Bitte ein Bit schrieb:
Kann man an solchen Projekten wirklich nicht genug abstrahieren bzw. parametrisieren als dass man immer diesen anwendungsspezifischen Code schreiben könnte?
Die Frage ist: Was ist das Projektziel, und wie sehen die Vorgaben aus. Ich habe kaum Projekte erlebt, in denen zu den Vorgaben Maßnahmen gehörten, die das Abstrahieren begünstigen (wie TDD oder IoC die selbiges gar erfordern) und damit auch die "Kosten" aufgewogen haben.
Abstraktion kostet aber nicht nur Zeit, sondern erhöht neben gewonnenen Freiheiten auch den Komplexitätsgrad einer Anwendung. Dies macht die Einarbeitung meist aufwendiger und treibt auch die kosten hoch. In einigen Fällen werden die Kosten mit der Zeit aufgefangen und können sogar sinken (gerade in langlebigen Projekten mit mehreren Kunden bei denen sich einzelne Detailabläufe unterscheiden, hier rentieren sich auch Unit-Tests am meisten).
Daher: Selten, zumindest wenn man möglichst stark auf das Ziel hin arbeiten soll. Selbst bei recht ähnlichen Projekten unterscheidet sich der benötigte Detaillierungsgrad meist erheblich, und die Abstraktion ist gleichzeitig nicht erwünscht.
-
asc schrieb:
Abstraktion kostet aber nicht nur Zeit, sondern erhöht neben gewonnenen Freiheiten auch den Komplexitätsgrad einer Anwendung.
Kommt auf die Art der Abstraktion an.
Eine Anwendung, die ich gesehen habe, unterscheidet plattformabhängigen Code mit #ifdefs (bei 5 supporteten Plattformen) und das jedesmal auf tiefster Ebene im Code. Etwas Abstraktion in Form einer Library hätte hier nicht geschadet.
Auch in bezug auf Kapselung ist Abstraktion ganz gut. Richtig abstrahiert reicht mir eine Codestelle um sie zu verstehen. Falsch abstrahiert muss ich mir die 200 Includes durchlesen bevor ich weiss, was da überhaupt passiert.
Das ist ein Unterschied zwischen C#/Java und C++: In C# ist eine tiefe Klassenhierarchie die Krone der Abstraktion (10 Level ist in WPF so der Standard), in C++ ist es eine freistehende Funktion, idealerweise ein Funktions-Template.
-
asc schrieb:
Abstraktion kostet aber nicht nur Zeit, sondern erhöht neben gewonnenen Freiheiten auch den Komplexitätsgrad einer Anwendung.
Wenn die Abstraktion die Komplexität erhöht, dann hat man was falsch gemacht. Abstraktion dient dazu, die Komplexität zu reduzieren.
In der Praxis sehe ich tatsächlich viel schlecht gemachte Abstraktion, die dazu führt, dass man den Code nicht mehr versteht, da er zu komplex ist. Das bedeutet aber nicht, dass man es auch gut machen kann.
Wenn ich eine relativ komplexe Schnittstelle habe und diese abstrahiere, um sie einfacher bedienbar zu machen, dann reduziert das die Komplexität.
-
volkard schrieb:
Wieviel sich wiederverwerten läßt, hängt auch vom Unternehmen ab. Wenn es tagein tagaus Verwaltungssoftware für Golfclubs trauspustet, läßt sich naturgemäß recht viel wiederverwerten.
(Logistikbranche.)
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...
-
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.
-
volkard schrieb:
softwaredesign schrieb:
Falsch!
In C# ist es zum Beispiel üblich, gewisse Klassen aus den einzelnen Schichten einer Software herauszuziehen, um sie dann in einem WCF-Dienst auf beiden Seiten gemeinsam verwenden zu können. Das hat nichts mit Übersicht zu tun sondern man möchte schlicht erreichen, dass Änderungen an Klassen der Domäne sofort auf beiden Seiten der Kommunikation greifen.Das ist ein Beispiel von vielen.
Hört sich aus ein wenig Abstand so an, als würdest Du normalerweise Gott-Klassen bauen und sie nur ganz selten mal schweren Herzens ein Bißchen zerlegen, weil ein Framework Dich dazu zwingt.
Mhm nein ist eher das Gegenteil von dem, was ich tu... hab nur versucht, einen anschaulichen Fall zu isolieren.
-
widder schrieb:
Auch in bezug auf Kapselung ist Abstraktion ganz gut. Richtig abstrahiert reicht mir eine Codestelle um sie zu verstehen. Falsch abstrahiert muss ich mir die 200 Includes durchlesen bevor ich weiss, was da überhaupt passiert.
Richtig, hier hast du aber schon eine Abstraktion in beiden Fällen. Hier ist das Problem auch nicht Abstraktion sondern sauberes Design (bzw. falsche Abstraktion).
Ich bin bislang vor allem auf den Zusammenhang mit der Wiederverwertung eingegangen. Und da stellt sich häufig aber eine gänzlich andere Frage: Wenn in einem konkreten Projekt genau ein Fall existiert, kostet eine Abstraktion der Wiederverwertung willen etwas. Es erhöht bezogen auf das Projekt unnötig die Komplexität.
Beispiel: In einem Projekt gibt es nur eine Formel um Rechnungsbeträge zu bilden, in einem anderen würde diese Formel aber nicht passen. Um den Code Wiederverwerten zu können müsste man diese Formel zusätzlich austauschbar machen (z.B. mittels Strategiemuster). Das bedeutet aber für das Projekt wieder unnötige Komplexität. Und diese Entscheidung stellt sich sehr häufig, und nicht nur an solch sehr überschaubaren Abläufen.
widder schrieb:
Das ist ein Unterschied zwischen C#/Java und C++: In C# ist eine tiefe Klassenhierarchie die Krone der Abstraktion (10 Level ist in WPF so der Standard), in C++ ist es eine freistehende Funktion, idealerweise ein Funktions-Template.
Verwechsle bitte nicht tiefe Klassenhierarchien mit Abstraktion. Ich würde sogar behaupten das eben solche häufig dem Nutzen der Abstraktion entgegen stehen, und zumeist (egal in welcher Sprache) ein Fehldesign sind.
Vererbung bedeutet eine der starrsten Bindungen die man überhaupt eingehen kann und auch wenn es im ersten Moment erscheint das man hier eine Abstraktion erhält, ist nicht selten genau das Gegenteil der Fall. Man kann nicht einfach zwei Klassen miteinander koppeln (wie man es im Gegenzug mittels Komposition erreichen kann), man erhält manchmal wesentlich mehr als man wirklich braucht, und büßt des weiteren viele Freiheiten ein.
Vererbung macht zwar Sinn, es sollten aber immer zuerst losere Alternativen durchdacht werden. Ich nutze zwar Vererbung relativ häufig, aber meist nur in sehr flachen Hierarchien [in der Regel max. 3 Ebenen] und ziehe wo möglich immer die Komposition vor.
-
Abstraktion dient dazu, die Komplexität zu reduzieren.
Und genau das ist ja das Ziel.
Abstraktion kostet aber nicht nur Zeit, sondern erhöht neben gewonnenen Freiheiten auch den Komplexitätsgrad einer Anwendung.
Der Spruch geht mir nicht in die Birne...
Ich würde es verstehen wenn jemand man sich mal zu Tode abstrahiert hat. Also der Code so abstrakt wurde, dass es in keinster Weise mehr von dem Problem zu tun hat. Aber ich habe es auch schon erlebt dass Leute so in Bits und Bytes dachten, dass ihnen der Sinn eines typedefs nicht klar war.
Anständig durchgeführte Abstraktion ist für meinen Geschmack immer Teil der Problemlösung. Und wenn diese Abstraktion mehrere Tage benötigen würde, würde ich mal meinen Chef nach einer Einführung eines Software Entwicklung Vorgehensmodell nachfragen. Denn längere, problembezogene Abstraktion führt zwangsläufig zur Problemanalyse.
Kleine Randbemerkung: Mein Ziel ist es immer gut und klar verständlichen Code zu produzieren und Dinge so einfach wie möglich zu halten.
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.
Nur weil jemand 1+1 mittels unendlichen Summen ausrechnet, heißt das nicht das for Schleifen böse sind.
-
In einem Projekt gibt es nur eine Formel um Rechnungsbeträge zu bilden, in einem anderen würde diese Formel aber nicht passen. Um den Code Wiederverwerten zu können müsste man diese Formel zusätzlich austauschbar machen (z.B. mittels Strategiemuster).
Dann würde man ja auch zwei Dinge miteinander verheiraten wollen, welche per se so nichts miteinander zu tun haben.
Andersrum mal gefragt: Wenn in Formel 1 ein Fehler wäre, wäre der Fehler dann auch in Formel 2?
-
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.