Vielleicht liegt hier ja insgesamt ein Sprachproblem vor. Nenne doch mal eine (von mir aus auch sehr kurze) Liste aus ein paar Befehlen, die durch OO langsamer werden. ( Und dazu zählt nicht der TRY-CATCH-Block, weil dies ein OO-Konstrukt ist welches natürlich nicht langsamer werden kann [ langsamer als was? ]. Meinst du vielleicht, dass eine Folge von Befehlen aus dem OO-Kontext langsamer ist als eine klassische Befehlsfolge mit anderen Befehlen? )DeathAndPain hat geschrieben:Jein.[...]. Der einzelne Befehl wird mit OO erheblich langsamer.ewx hat geschrieben:Aber die Aussage, "dass bei der kleinsten Verwendung von OO-Elementen [...] sofort die ABAP-Performance eklatant einknickt." ist definitiv falsch.
Was meinst du mit "ohne Ballast"? Ok, bei einem READ hast du einen sy-subrc. Und was machst du damit? Irgendwas, was Laufzeit kostet. Klar, du kannst ihn einfach nicht auswerten, aber dann knallt es schnell. Dann dumpt dein Programm immerhin schnell. Keine Logik ist immer schneller als Logik.DeathAndPain hat geschrieben:Du beharrst darauf, nicht beim Thema zu bleiben. Dass OO viele Funktionalitäten bietet, die ohne nicht (bzw. nur auf Umwegen) erreichbar sind, ist unbestritten, hat aber mit der Performance nichts zu tun. Und wenn ich Daten für eine komplizierte Liste bereitstellen muss, bei der ich aus vielen Tabellen mit vielen Iterationen die Ergebniszeilen zusammenbasteln muss, dann nützen mir Kaskaden von Logs nichts, aus denen ich ersehen kann, an welcher Stelle mein Programm wegen Timeouts abgebrochen hat. Dann brauche ich einfach effizienten Code ohne Ballast.Ralf hat geschrieben:Das ist so nicht richtig, wenn man die Funktionalität dagegen hält.
DeathAndPain hat geschrieben:Da bin ich anderer Meinung.Ralf hat geschrieben:Nein. Außer, dass beide aus ABAP-Coding bestehen, gibt es praktisch keine Parallelen.
Eine solche Behauptung möchtest du belegen.DeathAndPain hat geschrieben:Jein. Ich halte das für eine Blickwinkelfrage. Der einzelne Befehl wird mit OO erheblich langsamer.
Soso, du bezweifelst und das reicht dir. Wenn man weiß, wie man einen gescheiten Iterator mit Sprungvorhersage baut (das habe ich schon gemacht -- ganz im Gegenteil zu dir), kann der sogar *schneller* sein als ein einfacher READ.DeathAndPain hat geschrieben:Wenn ich in meinem Programm mit seinem vielen Iterationen über die internen Tabellen mit den Teilwerten jetzt aber anfangen würde, aus den internen Tabellen Containerobjekte zu machen und - überspitzt formuliert - jeden READ TABLE durch den Aufruf einer GETter-Methode zu ersetzen, die sich dann über diverse Dereferenzierungen den Wert besorgt, dann habe ich keine Zweifel, dass das absolut verheerend für die Programmlaufzeit wäre.
Was du natürlich weißt, ohne es je mit entsprechenden Patterns ausprobiert zu haben.DeathAndPain hat geschrieben:Von daher sind Werkzeuge zur Abstraktion hier eigentlich interessant. Aber wenn ich da mit Objekten und Methoden jongliere, dann geht mir die Performance dermaßen in die Knie, dass das Ganze nicht zu gebrauchen ist.
Wir sind nicht hier, um Freunde zu finden. Wenn Enno recht hat, hat er recht.black_adept hat geschrieben:Mit dieser Aussage machst du dir weder Ralf noch D&P zum Freund.
Nein, wenn man über einfache statische Methoden hinausgeht. Ein Beispiel: Ich habe n Buttons, die durch Klassen repräsentiert werden, in denen festgelegt ist, welches Icon das hat, welchen Funktionscode, etc. Außerdem implementieren alle diese Klassen ein Interface, das die Methode RUN enthält, in der die eigentliche Funktion definiert ist. Für einen Button ist das eine Druckfunktion, für einen anderen eine Exportfunktion, ein dritter versendet vielleicht eine Mail. Wird ein Button gedrückt, übergibt der Dialog der Applikation einfach nur dieses Interface, die Applikation weiß, dass es Methode RUN ausführen soll.black_adept hat geschrieben:Doch - die beiden haben große Ähnlichkeiten in der Verwendung.
Es GIBT aber öffentliche Attribute und ich bin nicht der Nabel der Welt. Eine Funktionsgruppe hat niemals öffentliche Attribute.black_adept hat geschrieben:Wenn ich andere Posts von dir lese stellst du auch all deine Attribute auf privat und arbeitest mit Settern und Gettern, so dass das dann doch wieder ähnliches Verhalten istralf.wenzel hat geschrieben: Ich kann (ohne Dirty Assign) nicht von außen auf Attribute einer Funktionsgruppe zugreifen
Und beim Übergeben des Namens des Funktionsbausteins wird der Zustand der Funktionsgruppe mit übergeben? Bei Klassen ist das so. Ich kann in einer Funktionsgruppe keinen Materialstamm speichern und eben diesen (mit der für ihn notwendigen Logik UND seinem Zustand, also seinen Attributen) an einen anderen Funktionsbaustein übergeben.black_adept hat geschrieben:Wenn du den Namen der FuGr oder des FuBa übergibst ist das völlig ausreichend um damit i.a. das abzubilden von dem ich glaube, dass du es meinst.ralf.wenzel hat geschrieben:Ich kann eine Funktionsgruppe oder einen Funktionsbaustein überhaupt nicht an eine Prozedur übergeben.
ewx hat recht. Ich weiß zwar auch nicht mehr genau, wo ich es gelesen habe (ist Jahre her), aber es stand in einer offiziellen SAP-Doku. Ich glaube, das war irgendein Hilfetext. Darin wurde betont, dass man sich gut überlegen solle, welche Funktionsbausteine man alles in eine Funktionsgruppe reinpackt, da beim Aufruf eines einzigen davon die ganze Funktionsgruppe in den Hauptspeicher geladen wird, weswegen man nur Funktionsbausteine, die auch tatsächlich zusammengehören, in dieselbe Gruppe packen soll.black_adept hat geschrieben:Bitte nachreichen, wo diese Information offiziell dokumentiert ist ( falls es überhaupt stimmt, was ich ohne die nachzureichende Doku erst mal bezweifele ).ewx hat geschrieben:Beim Aufruf eines Funktionsbausteins wird übrigens die gesamte Funktionsgruppe in den Speicher geladen, beim Aufruf einer Methode nur der Sourcecode dieser Methode...
Ich würde die Aussage schon auch unterstützen. Nur muss man beachten, dass die Abstrahierung von OO sich erst ab einer gewissen Projektgröße rechnet. Bei kleineren Projekten ist ohne OO sowohl die Wartbarkeit besser (da man den Quellcode noch lesen, verstehen und debuggen kann) als auch die Entwicklungszeit kürzer (da man sich die vielen formalen Gebilde (z.B. getrennte Definition und Implementation von Unterroutinen) sparen kann und lesbarer Code auch mit weniger Kommentarzeilen auskommt (obwohl ich ein großer Fan umfassend kommentierten Codes bin)). Umgekehrt kommt bei sehr komplexen Projekten Ralf an und sagt zu recht, dass er viel Funktionaliät in hochabstrakten Klassen wiederverwenden kann und eine Menge automatisch läuft, ohne dass er dazu noch einen Programmierfinger krümmen müsste.black_adept hat geschrieben:Mit dieser Aussage machst du dir weder Ralf noch D&P zum Freund.ewx hat geschrieben:von einem SAP-Entwickler erwarte ich, dass er einen guten Kompromiss aus Wartbarkeit und Entwicklungszeit findet
Ich habe mir bislang nicht die Mühe gemacht, ganze Listen von Befehlen gegen ihre OO-Gegenstücke zu testen. Zum Teil berufe ich mich auf gesunden Menschenverstand und behaupte, dass es schneller geht, einem Feld per Gleichheitszeichen einen Wert zuzuweisen, anstatt eine Getter-Methode aufzurufen, die ihrem Rückgabeparameter dann ein privates Objektattribut zuweist und das ganze dann zurückliefert.black_adept hat geschrieben:Vielleicht liegt hier ja insgesamt ein Sprachproblem vor. Nenne doch mal eine (von mir aus auch sehr kurze) Liste aus ein paar Befehlen, die durch OO langsamer werden. ( Und dazu zählt nicht der TRY-CATCH-Block, weil dies ein OO-Konstrukt ist welches natürlich nicht langsamer werden kann [ langsamer als was? ]. Meinst du vielleicht, dass eine Folge von Befehlen aus dem OO-Kontext langsamer ist als eine klassische Befehlsfolge mit anderen Befehlen? )
Leider (bei Formroutinen). Aber nicht bei jedem Rahmenprogramm ist es der wesentliche Zweck, nichts anderes zu machen, als solche Unterroutinen nach außen anzubieten. Das ist nur bei Klassen, Funktionsgruppen und Subroutinenpools so, wobei ich davon ausgehe, dass unsere Meinung über Subroutinenpools sich nicht wesentlich unterscheidet.Ralf hat geschrieben:Jedes Rahmenprogramm kann Teilprogramme beinhalten, die man von außen aufrufen kann (das geht sogar bei FORM-Routinen).
Ich hätte sagen sollen, "statische Klassen". Verzeih mir diese Ungenauigkeit.Ralf hat geschrieben:Und nein, du kannst keine *Zustände* definieren, sondern *einen Zustand*.
DeathAndPain hat geschrieben:Häufig sind Wartbarkeit und Entwicklungszeit mit Blick auf die Frage OO oder nicht OO also keine konkurrierenden, sondern vielmehr komplementäre Ziele.
DeathAndPain hat geschrieben:Der 7.00-Code war am schnellsten, die beiden 7.40-Codes waren aber nur so unwesentlich langsamer (aus der Erinnerung würde ich sagen 3%), dass es den besser lesbaren Code allemal wert war. Nur wenn die gesuchte Tabellenzeile nicht existiert hat - also genau dann, wenn die Ausnahmeklasse gerufen wurde und damit ein OO-Element aktiv wurde - kam ich in der ersten Version reproduzierbar auf in etwa die siebenfache Laufzeit (also +600%). Das dabei erforderliche Auswerten des SY-SUBRC war in der Messung mit drin!
DeathAndPain hat geschrieben:Ralf hat geschrieben:Und nein, du kannst keine *Zustände* definieren, sondern *einen Zustand*.
Ich hätte sagen sollen, "statische Klassen". Verzeih mir diese Ungenauigkeit.
Der Teil mit dem Laden der vollständigen Funktionsgruppe wird nicht angezweifelt - aber der Teil, dass nur der Sourcecode einer einzigen Methode statt dem Code der gesamten Klasse geladen wird scheint mir doch sehr fragwürdig.DeathAndPain hat geschrieben:ewx hat recht. Ich weiß zwar auch nicht mehr genau, wo ich es gelesen habe (ist Jahre her), aber es stand in einer offiziellen SAP-Doku. Ich glaube, das war irgendein Hilfetext. Darin wurde betont, dass man sich gut überlegen solle, welche Funktionsbausteine man alles in eine Funktionsgruppe reinpackt, da beim Aufruf eines einzigen davon die ganze Funktionsgruppe in den Hauptspeicher geladen wird, weswegen man nur Funktionsbausteine, die auch tatsächlich zusammengehören, in dieselbe Gruppe packen soll.black_adept hat geschrieben:Bitte nachreichen, wo diese Information offiziell dokumentiert ist ( falls es überhaupt stimmt, was ich ohne die nachzureichende Doku erst mal bezweifele ).ewx hat geschrieben:Beim Aufruf eines Funktionsbausteins wird übrigens die gesamte Funktionsgruppe in den Speicher geladen, beim Aufruf einer Methode nur der Sourcecode dieser Methode...
Paul Graham in diesem recht [url=http://www.paulgraham.com/icad.html]lesenswerten Artikel recht weit unten[/url] hat geschrieben:This practice is not only common, but institutionalized. For example, in the OO world you hear a good deal about "patterns". I wonder if these patterns are not sometimes evidence of case (c), the human compiler, at work. When I see patterns in my programs, I consider it a sign of trouble. The shape of a program should reflect only the problem it needs to solve. Any other regularity in the code is a sign, to me at least, that I'm using abstractions that aren't powerful enough-- often that I'm generating by hand the expansions of some macro that I need to write.
Überlege was du sagst. Der Mann, der das geschrieben hat ist kein Idiot und da er das so geschrieben hat, hat er auch einen Grund dafür. Mag sein, dass du mit ihm nicht übereinstimmst [ wenn du dem Link gefolgt bist und mal seinen nicht ganz kurzen Artikel zur Gänze gelesen hast ]- aber eine andere Aussage grundsätzlich als "Quatsch" abzutun setzt denjenigen, der den "Quatsch" gesagt hat in ein denkbar schlechtes Licht. Das ist sehr schlechter Diskussionsstil.ralf.wenzel hat geschrieben:Die Aussage ist natürlich Quatsch
Folgende Benutzer bedankten sich beim Autor black_adept für den Beitrag (Insgesamt 2):
Daniel • DeathAndPain
Das ist eine Frage der Umsetzung und des guten Willens. Wenn ich das mit Funktionsgruppen machen würde, dann würde ich die "privaten Methoden" als Formroutinen realisieren. Natürlich wäre es technisch möglich, die von extern aufzurufen, aber ich denke, dass jeder, der so etwas täte, wüsste, dass er einen Fehler macht. Sowas macht auch in der Praxis keiner. Ich habe jedenfalls noch nie gesehen, dass jemand quer Formroutinen fremder Modulpools oder gar Reports aufgerufen hätte, ausgenommen solcher, die genau dafür vorgesehen waren (z.B. als Include, das nur Formroutinen enthält wie MPPERS00 oder als dezidierter "Subroutinenpool"). Auch letzteres finde ich furchtbar und bin mir sicher, dabei mit Dir auf einer Linie zu liegen, aber obwohl ich schon so einige Programmierchaoten in meiner Laufbahn getroffen habe, habe ich das noch nie gesehen, dass jemand quer in Formroutinen fremder Programme einspringt, die dafür gar nicht vorgesehen sind. Und nochmal: Du kannst einen Programmierer nicht mit formalen Mitteln dazu zwingen, sauber zu arbeiten, egal wieviel programmtechnische Bürokratie, bis hin zu Wasserköpfen wie der Trennung von Definition und Implementation, die die Lesbarkeit des Programms in den Abgrund reißt, Du einführst. An anderer Stelle hast Du selbst gesagt, dass man kaum eine Chance hat, Klassen zu verstehen oder zu nutzen, wenn sie nicht dokumentiert sind. Ein Programmierer, der so schlampert arbeitet, dass er aus Faulheit quer in die Formroutine eines anderen Reports einspringt, würde niemals ordentlich strukturierte und dokumentierte Klassen und Methoden erstellen. Da hätteste dann eher sowas wie eine instanziierte Klasse, bei der genau ein Objekt erzeugt wird und der gesamte Nutzcode im Constructor steht. Dann endet das Programm, und das ist dann sein OO.Schon bei der Kapselung sind Funktionsgruppen damit „raus“, weil es keine geschützten Funktionsbausteine gibt. Jeder Funktionsbaustein ist von außen aufrufbar, somit muss der Aufrufer wissen, was er aufrufen darf und was nicht (das ist das Gegenteil von „autonom agieren“).
Normal ja, bester Weg nein. Ich bin weit davon entfernt, Dir an der Stelle einen Vorwurf zu machen, weil ich das kenne und genau weiß, dass die (in meinem Fall innerbetrieblichen) Kunden nicht wissen, was sie wollen. Dennoch muss natürlich das Bestreben sein, das Projekt so genau wie möglich im Vorfeld abzustecken und zu definieren, eben damit sich solche nachträglichen Anpassungen im Rahmen halten. Sonst bist Du ganz schnell bei 250% Deines geplanten Aufwandes oder baust gar einen Großflughafen.Zudem entwickeln wir agil. Das bedeutet: Wie das fertige Haus aussehen soll, weiß man erst, wenn tapeziert ist, weil der Kunde ständig neue und geänderte Anforderungen an uns heranträgt, da er erst lernt, welche Möglichkeiten sich ihm bieten. Das ist völlig normal und in diesem Falle der beste Weg.
Da hast Du recht. Wenn ein eigenständiges, verkäufliches Produkt entstehen soll, dann braucht man ohne Ende Customizingmöglichkeiten. Das halte ich auch für ein Paradebeispiel einer Situation, in der OO mit seinen ganzen Abstrahierungsmöglichkeiten vollkommen Sinn macht.Was wir dabei nie vergessen dürfen: Wir entwickeln ein AddOn, das später als Produkt verkauft werden soll. Wir wissen also gar nicht, inwieweit die Prozesse anderer Kunden abweichen. Was wir sicher wissen, ist: Sie werden. Wir müssen also eine ähnliche Einstellbarkeit und Erweiterungsfähigkeit bieten wie die SAP. Das ist etwas vollkommen anderes, als für einen bekannten Kunden etwas zu entwickeln.
Bedingt. Ich bin auch kein Fan des IF-Befehls. Häufig braucht man ihn, aber wenn es eine Alternative gibt (sei es CASE, sei es 7.40-Syntax, sei es CHECK ), dann ist die in aller Regel besser. Man kann aber schon hingehen und z.B. alle Varianten, die Du mit einer Subklasse abbildest, als Fälle eines CASE aufführen, der meinetwegen pro WHEN einen PERFORM ausführt. Dann musst Du auch nicht alles neu testen, wenn Du eine der Formroutinen veränderst, denn die wird ja nur in dem speziellen Fall gerufen, in dem bei Dir Deine geänderte Subklasse gerufen werden würde. Der Nachteil wäre die geringere Abstraktion, der Vorteil aber einmal mehr die bessere Verständlichkeit, was da passiert, weil man im Code auf einen Blick alle Varianten sieht, die möglich sind und auch unter welchen Umständen sie jeweils gerufen werden. Für jemanden, der den Code nicht kennt, halte ich das für ein ganzes Stück besser nachvollziehbar.Sowas gab es auch bei früheren Kunden, eine Auftragsschnittstelle (prozedural entwickelt) sollte Varianten erhalten. Mein erster Schritt war, die nicht durch IF/THEN/ELSE zu realisieren, sondern durch Subklassen, was dazu führte, dass ich gemeinsames Coding in der Hauptklasse hatte und Individuelles in den Subklassen. Insbesondere bräuchte ich bei keiner der Varianten die schon bestehenden neu zu testen, weil ich die ja gar nicht verändert habe. Das hat einen immensen Testaufwand erspart, denn einen prozeduralen Report hätte man jedesmal komplett neu testen müssen.
Da wäre ich Dir dankbar, wenn Du erläutern würdest, wie man sich das genau vorzustellen hat.Natürlich ist es einfacher und schneller, eine DB-Tabelle aus Feldern zu definieren. Trotzdem definieren wie sie immer aus Strukturen, die einen Gruppennamen erhalten