Folgende Benutzer bedankten sich beim Autor jocoder für den Beitrag:
DeathAndPain
Code: Alles auswählen.
methods: berechne_durchschnitt importing tabelle_mit_objekten type irgendwas returning value(durchschnitts_alter) type i.
method berechne_durchschnitt.
data(gesamt_alter) = 0.
loop at tabelle_mit_objekten into data(objekt).
gesamt_alter = gesamt_alter + objekt-alter.
endloop.
durchschnitts_alter = gesamt_alter / lines( tabelle_mit_objekten ).
endmethod.
Folgende Benutzer bedankten sich beim Autor SaskuAc für den Beitrag:
msentaburlar
Code: Alles auswählen.
data(gesamt_alter) = 0.
Code: Alles auswählen.
data gesamt_alter TYPE I.
Das mache ich eigentlich mit jedem Befehl... 🤪DeathAndPain hat geschrieben: ↑16.01.2020 08:56[...] und das = 0 schreibst Du nur, um das zu erreichen, was Du eigentlich willst[...]
Aber genau das sollte der Befehl auch ausdrücken, was er bei dieser Inline-Deklaration eben nicht tut.ewx hat geschrieben: ↑16.01.2020 09:27Das mache ich eigentlich mit jedem Befehl... 🤪DeathAndPain hat geschrieben: ↑16.01.2020 08:56[...] und das = 0 schreibst Du nur, um das zu erreichen, was Du eigentlich willst[...]
Also willst Du die Leute ärgern? 😉Ich finde diese Schreibweise super, denn sie fördert genau das, was häufig von vielen als unschön oder sogar nervig angesehen wird
Da kann man geteilter Meinung darüber sein, ob das schön oder unschön ist. Ich finde es richtig und wichtig bei Feldern, die, sagen wir mal, "routinenglobal" sind, also in einer (größeren) Unterroutine immer wieder benötigt werden. Inline-Deklarationen hingegen sollten streng lokal verwendet werden, also nicht irgendwann weiter unten im Code nochmal., nämlich ein Packen von Data-Anweisungen zu Beginn einer Funktion.
Und im vorliegenden Beispiel ist sie nicht "im Programmablauf", sondern am Beginn der Methode. Dort, an der typischen Stelle für Deklarationen, Inline-Deklarationen zu bringen, macht m.E. wenig Sinn. Dafür sind Inline-Deklarationen nicht gedacht. Genau das war mein Kritikpunkt.Ja, "DATA(x) = 1" macht das gleiche wie "DATA x TYPE i VALUE 1". Die erste Variante kann ich aber aber als Anweisung in den Programmablauf einfließen lassen. Die zweite Variante ist eine Deklaration, bei der ich es sehr unschön finde, wenn ich diese im Programmablauf finde.
Die SAP empfiehlt aber auch analog zu dem, was ich oben geschrieben habe, Inline-Deklarationen streng lokal zu verwenden und eben nicht die normalen Deklarationen durch Inlines zu ersetzen.Die Variante mit Inline-Deklaration wird auch im SAP Styleguide angeraten.
Folgende Benutzer bedankten sich beim Autor DeathAndPain für den Beitrag:
Legxis
Zu deiner Meinung:Und bitte jetzt nicht das Argument, dass alle Methoden nur 10 Zeilen lang sein sollten, so dass alles als lokal einzustufen ist. Dieses Paradigma halte ich für ebenso gutaussehend wie praxisuntauglich, denn es führt dazu, dass Fremdcode kaum mehr nachvollziehbar ist - obwohl es paradoxerweise genau das Gegenteil erreichen soll!
Code: Alles auswählen.
FORM WRITE_DATA.
PERFORM PASS1.
PERFORM PASS2.
ENDFORM.
Code: Alles auswählen.
FORM WRITE_DATA.
********** PASS 1 **********
" Actual code of pass 1
********** PASS 2 **********
" Actual code of pass 2
ENDFORM.
Glücklicherweise darf hier jeder seine eigene Meinung haben... 🙃DeathAndPain hat geschrieben: ↑16.01.2020 12:09Und danach dann die Implementierungen von PASS1 und PASS2. Das finde ich aber affig; mit dieser Kapselung gewinnt man nicht wirklich viel. Da mache ich lieber:[...]
Folgende Benutzer bedankten sich beim Autor ewx für den Beitrag (Insgesamt 2):
qyurryus • black_adept
Was du dadurch gewinnst? Wartbarkeit, lesbarkeit ( auch wenn du anderer meinung bist ) und erweiterbarkeit. ( und noch ein paar andere aspekte )DeathAndPain hat geschrieben: ↑16.01.2020 12:09Und danach dann die Implementierungen von PASS1 und PASS2. Das finde ich aber affig; mit dieser Kapselung gewinnt man nicht wirklich viel. Da mache ich lieber:Code: Alles auswählen.
FORM WRITE_DATA. PERFORM PASS1. PERFORM PASS2. ENDFORM.
Auch wenn jeder der beiden Pässe 50 Zeilen Code lang ist.Code: Alles auswählen.
FORM WRITE_DATA. ********** PASS 1 ********** " Actual code of pass 1 ********** PASS 2 ********** " Actual code of pass 2 ENDFORM.
Das muss ich auch so nicht. Die beiden Teile sind durch einen dicken Strich getrennt und insofern eigenständig. Höchstens könnte man argumentieren, dass ich durch die modulare Trennung jeweils nur die Felder deklarieren muss, die ich in dem betreffenden Pass brauche. Aber auch da ist mein Beispiel ein gutes, da ich in beiden Pässen weitestgehend die gleichen lokalen Felder und Tabellen benötige, so dass ich sogar Doppeldeklarationen spare. Die einzige theoretisch mögliche Wechselwirkung wäre ein vergessener CLEAR zwischen den Pässen. Aber der ist für mich kein ausreichendes Entscheidungskriterium.Wartbarkeit: Du musst dich nicht drum kümmern, was in pass2 passiert.
Das ist eben die große Illusion, die oft auch als Vorteil von OO angeführt wird, die aber in der Praxis allenfalls dann gilt, wenn der Code aus Deiner eigenen Feder stammt. Bei anderen, bei denen Du zunächst noch nicht mal weißt, mit welchen programmiertechnischen Ideen sie an das Problem herangegangen sind, welche Soll-Werte die Datenstrukturen (bei denen es sich womöglich gar selber um Containerobjekte handelt) haben, vielleicht sogar noch nicht mal, was das Programm genau machen soll, da hilft Dir der Name einen Dreck. Konkreten Code kannst Du interpretieren, auch wenn das je nach Umständen nicht einfach ist, aber Namen von Unterroutinen? Vergiss es. Sie sind hilfreich, ja, aber nicht mal näherungsweise ausreichend. Nur exzellente Dokumentation von jeder einzelnen Unterroutine und jedem einzelnen Parameter würde helfen, aber das macht praktisch niemand.Lesbarkeit: Da du nur wissen musst was und eben nicht wie etwas in einer Methode, die du aufrufst, passiert, sollte dir der name ( in kombination mit dem wissen um die dazugehörige klasse ) genügen, um den code lesen zu können.
Das muss ich auch so nicht. Da würde ich einfach schreiben:Erweiterbarkeit: Wenn du in der gesamt-routine, in der du eben pass1 und pass2 aufrufst, eine prüfung einbauen möchtest, welche z. b. berechtigungen prüft, dann schreibst du zw. den Aufrufen von pass1 und pass2 ( oder an einen anderen ort in dieser routine ) den Aufruf "prüfe_berechtigung_für_pass2" - und bei bedarf kannst du das wieder raus nehmen. Dafür musst du aber nicht pass2 anfassen und evtl. etwas "kaputt machen".
Code: Alles auswählen.
FORM WRITE_DATA.
********** PASS 1 **********
" Actual code of pass 1
********** Berechtigungsprüfung für PASS 2 **********
" Coding
********** PASS 2 **********
" Actual code of pass 2
ENDFORM.
Das ist sie in meinem Fall auch. Die Frage ist halt, wie groß die Units sind. In diesem Falle ist die Frage, ob es Sinn macht, die Hälfte der Datensicherung zu testen und in einem anderen Test die andere Hälfte, oder ob es nicht doch besser ist zu sagen, ich habe eine Programmunit, die die Daten aus dem Arbeitsspeicher wieder in die Datenbank schreibt, und die teste ich.Wenn man dann noch Unit-Tests schreibt, was meiner Meinung nach vorschrift sein sollte......, dann wäre die Wartbarkeit sogar durch diese modularisierung automatisiert.
Wenn ich in Pass 1 etwas ändere, dann weiß ich genau so wie bei Dir, dass Pass 2 sich nicht verändert hat. Beides sind Codeblöcke, die für sich stehen und für sich funktionieren, aber nur in sequentieller Abarbeitung gemeinsam Sinn ergeben und daher eine semantische Einheit bilden.Denn du weißt direkt, wenn du etwas transportierst ( und die entsprechenden prüfungen aktiv sind ) ob etwas noch funktioniert wie es soll oder eben nicht. Wie sollte man sowas mit riesigen Routinen machen können?
Ich habe schon eine Menge Inline-Deklarationen gesehen, die die Verständlichkeit des Codes deutlich erschwert haben, weil man erst mal ins Grübeln gekommen ist, welcher Datentyp da jetzt eigentlich bei rauskommt. Man sieht das Feld irgendwo, macht einen Doppelklick darauf und landet nicht bei einer verständlichen Deklaration, sondern inmitten einer Codegrütze, die in einem völlig anderen Kontext steht, so dass man erst mal überlegen muss, was das für ein Feld sein soll. Deswegen empfiehlt die SAP ja, Inline-Deklarationen nur streng lokal anzuwenden, und meiner Meinung nach sollte man sich daran auch halten (mal abgesehen von dem trivialen Ausnahmefall, den ich in einer früheren Antwort geschildert habe).Ich entwickle in letzter Zeit ein wenig in JavaScript, und habe dort alle meine deklarationen in dem moment wenn ich sie brauche. Das mache ich in ABAP inzwischen genauso. ( ein hoch auf die inline deklaration! ) - nur habe ich es hier zu Anschauungszwecken direkt in der ersten Zeile gemacht und nicht erst bei der ersten Verwendung. Außerdem, hilft es den Leuten vielleicht mal ein wenig auf die neue Syntax umzusteigen, wenn man es direkt so macht... sehe viel zu viel davon, dass leute upfront deklarationen vornehmen, obwohl inline für 95% der Fälle ausreicht...
Folgende Benutzer bedankten sich beim Autor DeathAndPain für den Beitrag:
Legxis
Aber eben nur theoretisch. Du verwendest aber evtl. gleiche Variablen in Block A und B. Du kannst also mit einer Änderung in Block A das Verhalten von Block B verändern, ohne dass es dir bewusst ist!DeathAndPain hat geschrieben: ↑16.01.2020 15:49Das muss ich auch so nicht. Die beiden Teile sind durch einen dicken Strich getrennt und insofern eigenständig.Wartbarkeit: Du musst dich nicht drum kümmern, was in pass2 passiert.