Was kann OOP-Code leisten, was prozeduraler Code nicht kann? - Seite 3

 

Bei kleinen Projekten können Sie zeigen, dass sich jedes Problem in prozeduralen Code aufschlüsseln lässt. Viel schwieriger wird es jedoch, wenn man über eine Codebasis von mehreren Millionen Zeilen verfügt und Teams von mehr als 100 Entwicklern, mehreren Business-Analysten und Architekten gleichzeitig Änderungen am "Modell" vornehmen wollen. Unter diesen Umständen wird das "Geschäftsmodell" in der Regel in einem Design-Tool wie UML definiert und ist dem gesamten Team zugänglich.

Allein das Geschäftsmodell enthält über 5000 Klassen. Ausgehend von diesem Geschäftsmodell gibt es Werkzeuge, die Klassen für das Objektmodell, die SQL-Schnittstellen und die Netzwerkschichten "generieren", so dass sich die Anzahl der Basisklassen auf 15.000 erhöht.

Für diese Diskussion möchte ich den Streit zwischen prozeduraler und OOP in drei "Erweiterungen" unterteilen, die der prozeduralen Sprache seit den 1960/1970er Jahren hinzugefügt wurden

1) "Objektbasiert": Hier werden Objekte und Code gekapselt, um fortgeschrittene "Strukturen" zu schaffen, die auch Verhaltensweisen haben können.

2) "Klassenbasiert": Hier können Objekte voneinander erben und in Hierarchien angeordnet werden.

3) "Objektorientiert": Hier kann der Benutzer "polymorphes" Verhalten (virtuelle Methoden oder Schnittstellen) innerhalb der Klassenhierarchien definieren.

Es gibt das Argument, dass alle oben genannten Funktionen mit genügend Aufwand in prozeduralen Sprachen implementiert werden können. So wurden beispielsweise die meisten GUI-Toolkits in den 80/90er Jahren in C erstellt und verfügten über diese Funktionen, aber sie sind für den Gelegenheits-Programmierer nicht einfach zu implementieren und sind für diese Diskussion nicht wirklich relevant.

Um also die Frage zu beantworten, können wir ein Projekt mit mehreren Millionen Zeilen und 100+ Entwicklern ohne die 3 OOP-Funktionen implementieren?

Meine persönliche Meinung ist, dass es praktisch unmöglich ist, ein Großprojekt ohne 1) und 2) zu realisieren, da es ohne ein "klassenbasiertes" System sehr schwer ist, die Datenstrukturen und Verhaltensweisen der realen Welt sauber und präzise in Code abzubilden. Und je größer das Projekt wird, desto mehr wird das, was als "das können wir in C implementieren" beginnt, zu einer endlosen Liste von Methoden mit weniger Struktur, die immer schwieriger zu warten ist.

Nun sind Sprachen, die nur 1) und 2) erfüllen, keine vollständigen OOP-Sprachen. Wir sollten also überlegen, ob "polymorphe (virtuelle) Methoden" wirklich notwendig sind. Dies ist eher ein "vielleicht" oder "manchmal", denn Polymorphismus ist nicht immer das richtige Werkzeug zur Lösung eines Problems und kann den Entwurf überkomplizieren. Bei der Modellierung von Datenstrukturen, die auf einen Objektspeicher oder eine SQL-Datenbank abgebildet werden, kann das Hinzufügen virtueller Verhaltensweisen die Datenabbildung erschweren. Bei der Definition erweiterbarer Toolkits oder APIs ist die Verwendung einer "Schnittstelle" oder Basisklasse mit "virtuellen Methoden" jedoch von unschätzbarem Wert. Insgesamt bin ich ein großer Fan von Polymorphismus, wenn er sparsam und im richtigen Kontext eingesetzt wird.

Ich habe an einigen millionenzeiligen "C"-Codebasen und mehreren millionenzeiligen C++/Java/C#-Codebasen gearbeitet, und die meisten der "C"-Codebasen verfallen nach 5 Jahren in den "Wartungsmodus", weil die Entwickler Angst haben, die Architektur zu ändern, da der Code einfach zu anfällig ist und Änderungen oft monatelange schmerzhafte Neuentwicklungen und Tests nach sich ziehen. Im Allgemeinen sind objektorientierte Projekte viel widerstandsfähiger gegenüber Änderungen und Refactoring.

 
Alain Verleyen:
Eine "if...then...else..."-Anweisung sollte die Aufgabe erfüllen.

if...then...else ist nicht in der Lage, "virtuelle" Methoden zu kodieren.

Es gibt mehrere Implementierungen von "Polymorphismus" in "C" und die meisten von ihnen verwenden Vektoren von Funktionszeigern, um die notwendigen Zuordnungen zu halten. Genauer gesagt müssen diese "Vektoren von Funktionszeigern" für jeden "Typ", den Sie in der "Hierarchie" modellieren wollen, definiert werden. Natürlich unterstützt "C" Hierarchien nicht direkt, also müssen Sie auch dieses Problem lösen.

Wenn Sie wirklich in die Wundertüte der in "C" implementierten "virtuellen" Methoden einsteigen wollen, können Sie die X-Windows-Toolkits ausgraben, die in jeder Linux-Distribution frei verfügbar sind.

Windows muss natürlich etwas anders sein und verwendet erweiterbare Strukturen mit ganzzahligen Nachrichten-IDs, was bedeutet, dass das "polymorphe" Verhalten über Switch-Anweisungen für die IDs implementiert wird. (wahrscheinlich die schmutzigste Art und Weise, es zu tun, aber es wird Sie ans Ziel bringen)

 
Alain Verleyen:

Sind Sie der Meinung, dass das Windows-Betriebssystem eine gute grafische Benutzeroberfläche bietet? Soweit ich weiß, ist es in C geschrieben, einer prozeduralen Sprache, nicht OOP.

Du liegst falsch, Dirk, wenn Du glaubst, dass ein komplexes Programm nur mit OOP erstellt werden kann. Du solltest lieber erklären, warum es besser ist, es mit OOP zu programmieren.

Der Windows-Kernel ist in "C", aber der Kernel ist nur eine kleine Komponente der Windows-Codebasis, und ein Großteil der Codebasis auf höherer Ebene ist in C++ mit externen Schnittstellen im "C"-Stil implementiert, um mehrere Sprachen zu unterstützen.

Sogar die alten Windows-GUI-Komponenten implementieren ihr eigenes handgerolltes "polymorphes Verhalten", das effektiv "OOP" in "C" ist. Wenn Sie z.B. ein "Handle" von einem GUI-Control zurückbekommen, erhalten Sie eine erweiterbare "C"-Struktur mit polymorphem Verhalten, das ist OOP, nur verpackt in einer hässlichen "C"-Syntax.

Zu sagen, dass Windows nicht OOP ist, weil es in "C" geschrieben ist, ist nicht ganz richtig.

 
Alain Verleyen:

Ich werde keine grafische Benutzeroberfläche in einer prozeduralen Sprache erstellen, um zu beweisen, dass Sie falsch liegen. Aber ich könnte es ohne jeden Zweifel.

Übrigens ist es auch einfach, unlesbaren und viel langsameren Code in OOP zu programmieren, und wie Sie wissen, ist die Metaquotes Standard Library ein guter Beweis dafür.

Dass OOP viel langsamer ist als prozeduraler Code, ist ein kompletter Mythos. Der Grund, warum viele OOP-Projekte langsamer sind, ist, dass sie schlecht konzipiert sind. Der Overhead für einen virtuellen Funktionsaufruf ist weitaus geringer, als man erwarten würde, insbesondere bei den heutigen On-Chip-Speicherabruf-Architekturen, die parallel nachschlagen und ausführen können.

https://hbfs.wordpress.com/2008/12/30/the-true-cost-of-calls/

Zitat aus dem obigen Link: "Aber die Kosten eines Aufrufs, egal welcher Art, werden von der Auswertung seiner Argumente dominiert. Wir haben gesehen, dass indirekte Aufrufe, egal ob virtuelle Methoden im Stil von C oder C++, von Natur aus kostengünstig sind. Ein Aufruf einer virtuellen Methode ist nicht teurer als ein indirekter Aufruf über ein struct-Mitglied (something->function(arg1,arg2)), so dass es einfach falsch ist, virtuelle Funktionen als unglaublich langsam zu bezeichnen."


Java kann viel langsamer sein als C++, weil jedes Stück gekapselter Daten selbst eine Heap-basierte Klasse sein muss, so dass man viel mehr Objekt-Dereferenzierungen hat. Allerdings kann Java bei Schleifen und grundlegenden mathematischen Operationen genau die gleiche Geschwindigkeit wie C erreichen.

Wenn man C mit C# vergleicht, ist es wirklich ziemlich schwierig, Code zu schreiben, der in C deutlich schneller ist als in C#, selbst wenn man einige der OOP-Funktionen einbezieht.

Wenn die Metaquotes-Standardbibliothek langsam ist, dann liegt das zu 90% am Design der Bibliotheksfunktionen und hat nur sehr wenig mit den verwendeten OOP-Funktionen zu tun.

(Zum Vergleich: Die C++ Standard Template Library übertrifft 95% aller jemals geschriebenen C-Projekte)

 
James Cater:
...

Vielen Dank für Ihren großartigen Beitrag.

 
Alain Verleyen:

Ich danke Ihnen für Ihren großartigen Beitrag.

Danke, und ich wollte Sie nicht angreifen, aber Sie sind der Einzige, der das Verfahrensargument vertritt :)
 
James Cater:
Danke, und ich wollte Sie nicht angreifen, aber Sie sind der Einzige, der sich für das Verfahrensargument einsetzt :)

Keine Sorge, ich muss meine Rolle als "Moderator" spielen.

 

Sicher, es wäre schön, ein paar Beispiele für das zu sehen, worüber Sie sprechen. Reden/Tippen ist schön und gut für Leute, die Erfahrung in all dem haben, aber ich bin ein visueller, praktischer Student, bitte posten Sie Beispiele.

Ich bin unschlüssig, ob ich mit mql4 weitermachen, zu mql5 wechseln oder einfach eine andere Plattform nutzen soll.

Danke Alain, dass du diesen Thread ins Leben gerufen hast. Dieses Forum braucht das wirklich.

 

Erwartest du wirklich, dass jemand, der professionell arbeitet, eine Compex-Bibliothek einfach so als "Beweis" postet? ;) Ich könnte dir einen Link zu etwas Fertigem posten, das hier auf dem Markt nicht verkauft werden kann, aber Alain wird mich treten, wenn ich das tue ;) Du kannst mein Profil besuchen und einen Blick auf das Wandbild werfen, um eine Idee zu bekommen oder mir eine PM schicken.

Eine andere Plattform? Sie werden keine andere Plattform mit einem so leistungsfähigen Compiler finden. Ganz und gar nicht.

@James Cater - vielen Dank für Ihre Kommentare.

 
Doerk Hilger:

Erwarten Sie wirklich, dass jemand, der professionell arbeitet, eine Compex-Bibliothek einfach so als "Beweis" postet? ;) Ich könnte dir einen Link zu etwas Fertigem posten, das hier nicht auf dem Markt verkauft werden kann, aber Alain wird mich treten, wenn ich das tue ;) Du kannst mein Profil besuchen und einen Blick auf das Wandbild werfen, um eine Idee zu bekommen oder mir eine PM schicken.

Eine andere Plattform? Sie werden keine andere Plattform mit einem so leistungsfähigen Compiler finden. Ganz und gar nicht.

@James Cater - vielen Dank für Ihre Kommentare.

Du hast den Punkt nicht verstanden, Dirk. Nicht-Spezialisten wollen einfache und klare Code-Beispiele, was ja auch mein Ziel mit diesem Thema war. Aber das scheint für Spezialisten völlig unverständlich zu sein.