Diskussion:Programmfehler/Archiv/2014
Objektorientierte Laufzeitumgebungen
Es geht um folgenden Absatz im Abschnitt "Reproduzierbarkeit von Programmfehlern": In objektorientierten Laufzeitumgebungen existieren die Datenobjekte unabhängig davon, ob dazugehörige Programmsequenzen laufen oder nicht. Da verschiedene Programme auf dieselben Objektdaten zugreifen dürfen und können, ist es oft nicht vorhersehbar, welche Programmroutinen zu welchem Zeitpunkt diese Objekte verändern. Auch in diesen Fällen kann es leicht dazu kommen, dass Ergebnisse und Programmfehler scheinbar nicht reproduzierbar sind.
Ich denke da ist einiges falsch:
- Es gibt keine OO Laufzeitumgebungen & das Gesagte trifft auch für C++ zu (das in keiner "Laufzeitumgebung" rennt)
- Dass Daten im Speicher liegen, die gerade nicht von Programmsequenzen benötigt werden, ist auch in prozeduralen Sprachen so.
- Dass verschiedene Programmteile auf dieselben Daten zugreifen dürfen und können, ist auch in prozeduralen Sprachen so.
Wenn dann erschweren OO Sprachen (auf Grund des Polymorphismus) das Erkennen von Programmfehlern im Code, da man ja aus dem Code nicht erkennen kann welche Implementierung einer Methode zur Laufzeit verwendet wird. Das hat aber nichts mit Reproduzierbarkeit von Programmfehlern zu tun.
Ich denke also, dass OO Sprachen (egal in welcher Laufzeitumgebung sie laufen) keine geringere Reproduzierbarkeit von Programmfehlern aufweisen als nicht-OO Sprachen. Habe den Absatz daher gelöscht. Bitte ihn nur nach Diskussion bzw. mit Belegen wieder hinzuzufügen. --Sebastian.Dietrich ✉ 22:26, 19. Okt. 2014 (CEST)
- Es ist in meiner Erfahrung leider immer wieder schwierig, mit C++-Programmierern über objektorientierte Laufzeitsysteme zu diskutieren. Für diejenigen, die sich damit nicht so gut auskennen:
- Selbstverständlich gibt es objektorientierte Laufzeitumgebungen. In solchen kann der Programmcode, der Objektinstanzen erzeugt oder bearbeitet, komplett entfernt und durch anderen (in der Regel aktualisierten) Programmcode ersetzt werden, ohne dass irgendeine Objektinstanz gelöscht oder neu erzeugt werden muss, weil die Objektstruktur im Laufzeitsystem verankert ist. In komplexen Systemen hat kein Programmierer die Kontrolle, welche Programmmodule überhaupt geladen sind oder ausgeführt werden (könnten).
- Bekannte Beispiele für objektorientierte Laufzeitumgebungen sind die Common Language Runtime von .NET oder die Java Virtual Machine.
- Es stimmt, dass das Überladen von Methoden eine Programmfehlersuche fast unmöglich macht. Beim Polymorphismus in der objektorientierten Programmierung werden jedoch Methoden überschrieben, aber nicht überladen - der Polymorphismus mit dem Überladen von Methoden oder Operatoren hat mit Objektorientierung nichts zu tun. Gute objektorientierte Programmiersprachen erlauben das Überladen von Operatoren, Prozeduren, Methoden oder Konstruktoren gar nicht. Das erleichtert die Programmfehlersuche übrigens erheblich. Und genau deswegen macht es unter anderem keinen Sinn, C++-Code in einer dynamischen Laufzeitumgebung laufen zu lassen.
- C++ ist gar keine richtige objektorientierte Programmiersprache. C++ ist ja genauso wie C noch nicht einmal typsicher und hat lediglich ein paar minderwertige Funktionen hinzubekommen, die es erlauben, einige Elemente aus der objektorientierten Programmierung nachzuahmen und neue, völlig überflüssige Elemente hinzuzufügen, die eine Programmfehlersuche praktisch unmöglich machen.
- Eine objektorientierte Laufzeitumgebung muss obligatorisch eine automatische Speicherbereinigung haben, und deswegen gibt es in objektorientierten Programmiersprachen auch keine Prozedur free () oder dealloc ().
- Man muss ja für die Belege nicht bis zu den Wurzeln von Smalltalk zurückgehen; ich empfehle wärmstens die Lektüre eines der folgenden älteren, aber immernoch aktuellen Bücher:
- Hanspeter Mössenböck: Object oriented programming in Oberon 2
- Jürg Gutknecht und Niklas Wirth: Project Oberon
- Viele Grüße --Bautsch (Diskussion) 23:24, 19. Okt. 2014 (CEST)
- Oje, anscheinend hast eine falsche Sicht von mir. Ich kenne mich mit OO (insbesondere Java) vortrefflich aus, du musst mir da nichts erklären und muss dir da leider widersprechen:
- Es gibt keine OO Laufzeitumgebungen. Die von dir genannten sind Laufzeitumgebungen, aber nicht ausschließlich für OO Sprachen bestimmt. Auf der JVM laufen jede Menge nicht OO Sprachen.
- Nachdem es keine OO Laufzeitumgebungen gibt müssen die natürlich auch keine GarbageCollection haben. Real-Time Java kommt z.B. ohne GC aus. C++ detto.
- C++ ist genauso eine OO Programmiersprache, wie Java oder C#. Typsicherheit hat nix mit OO zu tun. Genauso könnte man sagen, dass Java keine OO Sprache ist, weil es primitive Datentypen kennt.
- Überladen macht die Programmfehlersuche nicht schwieriger oder gar unmöglich. Dass es eine zweite/dritte Methode mit anderen bzw. mehr/weniger Parametern gibt, ist kein Problem. Ich habe auch nie vom Überladen, sondern von Polymorphismus gesprochen.
- Welche "guten" OO Sprachen verbieten das Überladen von Methoden oder Konstruktoren? Ich kenn da keine.
- Wie soll Überschreiben bzw. Polymorphismus die Programmfehlersuche erleichtern? Aus dem Code erkennt man ja nicht welche Methode jetzt aufgerufen wird.
- Danke für die Oberon Empfehlungen - passen hier halt nicht wirklich...
- --Sebastian.Dietrich ✉ 23:57, 19. Okt. 2014 (CEST)
- Oje, anscheinend hast eine falsche Sicht von mir. Ich kenne mich mit OO (insbesondere Java) vortrefflich aus, du musst mir da nichts erklären und muss dir da leider widersprechen:
- Leider konnte auch ich diese Ergänzung nicht so ganz nachvollziehen. Ich kann mir da zwar sehr vage etwas vorstellen, in welche Richtung die Aussage zielen könnte, aber so ist sie mir leider unverständlich.
- Ich muss Sebastian da auch zustimmen: Welche konkreten Probleme sollten denn bei der Fehlersuche bei überladenen/polymorphen Funktionen auftauchen? Oder was sollte objektorientiert mit automatischer Speicherbereinigung zu tun haben?
- Und inwiefern hilft Oberon hier weiter? Das ist AFAIK eine Sprache, die nur vereinzelt im akademischen Bereich genutzt wird?--Plankton314 (Diskussion) 11:10, 20. Okt. 2014 (CEST)
Darf ich einen Vermittlungsversuch unternehmen? Bautsch, deine Ergänzung fand im Abschnitt 'Reproduzierbarkeit von Programmfehlern' statt. Meine Meinung: Auch wenn sie richtig sein sollten, sind sie hier, vor allem in diesem Umfang fehl am Platz. Das Kapitel will nur sagen, dass manche Fehler nicht reproduzierbar sind. Die Gründe dafür können m.E. vielleicht als Beispiele kurz aufgezählt, aber keinesfalls in ihren Details behandelt werden. Erstens ist das nicht mehr OMA-geeignet, zweitens müsste es dafür andere (Haupt-)Artikel geben. --VÖRBY (Diskussion) 09:06, 20. Okt. 2014 (CEST)
- Worum es mir geht, mit einigen Beispielen:
- Ich hatte im Artikel gar nichts von Polymorphismus geschrieben, aber in der Tat entstehen vermeidbare Programmierfehler durch das Überladen von Methoden und Operatoren. Dies ist ein Polymorphismus, der in objektorientierten Programmiersprachen zwar oft vorhanden ist, aber anders als das Überschreiben zum Zwecke der Vererbung nichts mit Objektorientierung zu tun hat. Ein typisches einfaches Beispiel im Zusammenhang mit Programmfehlern ist der Ausdruck 3 / 2, der in der C-Welt ohne Not als ganzzahlige Division betrachtet wird, da der Divisionsoperator überladen ist. Dieser Programmfehler ist aber leicht reproduzierbar. Beim Überschreiben im Sinne der Mehrfachvererbung (das ist auch ein Polymorphismus) und bei varianten Parameterdatentypen gibt es aber unüberschaubare Konsequenzen, sowohl für den Compiler als auch für den Programmierer. Es kann keineswegs vorausgesetzt werden, dass sich ein und derselbe Quelltext in verschiedenen Systemen reproduzierbar verhält. Beispiel: ein Konstruktor ist in sechs Vererbungsstufen überschrieben, und zusätzlich gibt es auf jeder Stufe mehrere überladene Varianten mit verschiedenen Datentypen und Parametern. Kein Programmierer kann mehr ernsthaft überblicken, welche Supercalls da noch tatsächlich ausgeführt werden, insbesondere wenn die vererbenden Klassen gewartet werden und dabei überladene Konstruktoren hinzugefügt oder entfernt werden dürfen, da dazwischenliegende Superklassen mit scheinbar identischen Schnittstellenbeschreibungen bestehen bleiben.
- Eine einfach zu verstehende Quelle von Programmfehlern ist die nicht festgelegte Reihenfolge der Abarbeitung von Parametern: f (g (x), h (x)) kann auf zwei Maschinen völlig verschiedene Ergebnisse erzeugen, je nachdem ob erst g (x) oder erst h (x) ausgewertet wird. Das hat aber primär nichts mit Objektorientierung zu tun.
- Wenn in einer Laufzeitumgebung typunsichere Programmiersprachen oder Dispose-Kommandos zur Freigabe von Speicher für den Programmierer zugelassen werden (und warum tut man das in komplexen Systemen heutzutage um alles in der Welt noch ?), sind in objektorientierten Programmen Fehler praktisch vorprogrammiert. Das muss eine automatische Speicherbereinigung erledigen, die die Kontrolle über alle noch erreichbaren Objektinstanzen hat - der Programmierer hat die jedenfalls definitiv nicht mehr, weil manche Objektinstanzen unabhängig von der Anwendungssoftware im Standard-Framework der Laufzeitumgebung verankert sind. Und genau aus diesem Grund ist C++ in diesem Zusammenhang überhaupt nicht geeignet. Und selbstverständlich hat auch eine Java Virtual Machine eine automatische Speicherbereinigung - das ist ein Muss (siehe oben). Siehe zum Beispiel: Java Garbage Collection Basics
- Bitte den Artikel zu .NET korrigieren, wenn er fälschlich behaupten sollte, es verwende als Hauptbestandteil eine objektorientierte Laufzeitumgebung. Aus meiner Sicht ist die Aussage jedoch völlig korrekt.
- Strukturierte Programme, die als Polymorphismus nur die einfache Vererbung erlauben, sind erheblich einfacher zur Warten und zu Debuggen, weil nicht annähernd so viele Verzweigungen überblickt und getestet werden müssen.
- Das Oberon-System ist ein Betriebssystem mit objektorientierter Laufzeitumgebung, ohne die die objektorientierte Programmiersprache gar nicht funktionieren würde, beziehungsweise genauso viele Programmfehler verursachen würde wie die C-basierten Betriebs- und Laufzeitsysteme. Viele der Prinzipien von Smalltalk und des Oberon-Systems (leider nicht alle) sind von C# und Java und deren Laufzeitsystemen aufgegriffen worden.
- Die dazugehörige Programmiersprache Oberon verzichtet ohne Einschränkungen der Funktionalität sowohl auf das Überladen als auch auf die Mehrfachvererbung.
- Näheres in den von mir genannten Büchern, die passen hier wirklich gut. --Bautsch (Diskussion) 15:15, 20. Okt. 2014 (CEST)
Fehlende Programmfehlerquellen
Mir ist überhaupt gerade erst aufgefallen, dass die folgenden häufigen oder typischen Ursachen von Programmfehlern im Artikel nirgends erwähnt werden:
- Spaghetticode / Goto
- Zirkelbezug / zyklische Importe / mehrdeutige Importe
- unvollständige Programmierschnittstellen und Modul- oder Klassenschnittstellen
- Seiteneffekte
- Mehrfachvererbung
- Überladen
Ich weiß nicht, wo das alles eingebaut werden kann und soll, und im Augenblick kann ich das leider nicht leisten, sondern nur hier deponieren. --Bautsch (Diskussion) 15:33, 20. Okt. 2014 (CEST)
- Bitte sei dir bewusst, dass dies hier ein Eintrag in einem Lexikon ist. Das kann keine Doktorarbeit und auch kein Fachbuch sein. Es gibt ein Kapitel 'Fehlerarten'. Dort sind bereits manche Fehler konkret als Beispiel erwähnt, da könnte man ggf. weitere anfügen, zweckmäßigerweise mit einem Link. Mehr wäre aber hier kontraproduktiv. Was 'häufig' und was 'typisch' ist, scheint mir auch sehr subjektiv zu sein.--VÖRBY (Diskussion) 18:27, 20. Okt. 2014 (CEST)
- Sämtliche aufgeführten Punkte sind in der Einleitung abgedeckt: "[...] Festlegung der Spezifikation nicht oder falsch umgesetzt [...] Laufzeitumgebung fehlerhaft bzw. anders als erwartet [...] Unvollständigkeit, Ungenauigkeit oder Mehrdeutigkeiten in der Spezifikation [...]".
- Nur eben sehr generell, anstatt einer derart "expliziten Auflistung".
- --arilou (Diskussion) 09:22, 15. Apr. 2015 (CEST)
Klassifizierung von bugs
Ich suche, jedoch finde ich wenig infos über die Klassifizierung von bugs, in A-bug, B-bug und C-bug. Hat jemand gute Quellen und könnte die hier posten? Ich baue das auch gerne ein. --Raymond83 (Diskussion) 06:30, 20. Nov. 2014 (CET)
- Ich habe diese Klassen (ABC ...) bei "Klassifizierung" erwähnt. Konkret definiert das der angewendete Prozess, ggf. wird es auch von der verwendeten Fehlertrackingsoftware bestimmt. Beispiellinks könnte man dazu z.B. als Einzelnachweis anfügen. --VÖRBY (Diskussion) 10:13, 20. Nov. 2014 (CET)
- Danke. Ist es noch möglich mehr ins Detail zu gehen? Wo ist/könnte der Unterschied zwischen A-Bug, B-Bug und C-Bug sein? Ich kann mir vorstellen, dass es kritische (Abstürz) also A-Bug, schwere (Fehlermeldung) also B-Bug und leichte Fehler (wie Design) also C-Bug sein könnten? --Raymond83 (Diskussion) 14:55, 21. Nov. 2014 (CET)
- Hallo, nach meiner Erfahrung wird ABC usw. - wie beschrieben - individuell festgelegt. Dementsprechend kann auch der Bug-Bearb-Prozess unterschiedlich definiert sein, z.B. bezüglich der Priorisierung. Ich denke, es wird immer so ähnlich sein wie Du schreibst. Weitere Details kann/sollte man nur als Beispiele aufzählen, mit einer Referenz auf einen konkreten Fall (möglichst 'prominent', z.B. ISTQB o.ä.). Ich kann nochmal recherchieren. --VÖRBY (Diskussion) 16:02, 21. Nov. 2014 (CET)
Ich habe Belege eingefügt, nach denen Fehler u.a. nach ABC.. bzw. 123.. klassifiziert werden. Gute Beispiele zeigt der BITKOM-Leitfaden. In einem umfassenden Fehlerprozess werden Fehler aber detaillierter klassifiziert (und bearbeitet).
- Das habe ich gesucht. Danke :) --Raymond83 (Diskussion) 16:27, 25. Nov. 2014 (CET)
- Archivierung dieses Abschnittes wurde gewünscht von: VÖRBY (Diskussion) 09:32, 25. Nov. 2014 (CET)