ABAP Clean Code

Alles rund um die Sprache ABAP®: Funktionsbausteine, Listen, ALV
68 Beiträge Vorherige Seite 3 von 5 (current) Nächste
68 Beiträge Vorherige Seite 3 von 5 (current) Nächste

Re: ABAP Clean Code

Beitrag von nickname8 (Specialist / 106 / 15 / 16 ) » 20. Mai 2019 16:47

Hi Ralf,
eine Sache die ich schon öfter von dir gelesen habe, ist, dass du SELECTs in eine Klasse verlagerst, deren Objekte generisch erzeugt werden (und wie ich verstanden habe, auch die SELECTs dynamisch zusammenbaut). Je nach dem, was man braucht.

Finde den Ansatz total interessant und würde gerne mal die Logik eines kleineren Projektes ebenfalls so kapseln.

Aber da stellen sich sofort folgende Frage:wie erzeugst du ein dynamischen SELECT der spezielle (open)SQL-Befehle benötigt? Mit speziell meine ich jetzt ganz grob alles, was über ein

Code: Alles auswählen.

SELECT fields FROM dbtab INTO itab WHERE x = y

geht.
Also sowas wie DISTINCT, JOIN, ORDER BY, UP TO x ROWS...
Bekommt man das alles dynamisch hin?


Re: ABAP Clean Code

Beitrag von ralf.wenzel (Top Expert / 3415 / 149 / 220 ) » 20. Mai 2019 18:32

Also, ich beantworte erstmal deine Frage konkret und dann schreibe ich was zum Umfeld: Wir hatten solche Fälle bisher nicht. Die Frage ist auch: Lässt man das lieber den (einen) DB-Server machen oder einen (der mehreren) SAP-Server. Wie man das lösen KANN, schreibe ich unten.

Was wir hatten, war FOR ALL ENTRIES, wo man schnell den Fehler macht, eine leere Tabelle zu übergeben. Den fangen wir ab und sagen dem Anwender "das ist falsch" ehe wir die DB ansprechen.

Zum Umfeld:

Was wir hier haben, ist eine Klassenhierarchie für die Persistenz. Ganz oben in der Basisklasse der ganzen Hierarchie gibt es eine Methode, die den SELECT (und wirklich nur den) enthält. Diese Methode könnte man redefinieren, um z. B. ein ORDER BY unterzubringen für bestimmte Fälle. Das haben wir z. B. gemacht für Cluster-Tabellen. Neben dem Hauptzweig für transparente Tabellen gibt es einen weiteren, wo diese Methode redefiniert ist und ein IMPORT bzw. EXPORT macht, von der erben alle Persistenzklassen für Clustertabellen. Für den Entwickler, der z. B. Daten selektiert, ist das völlig egal. Der sagt, was er hat und was er haben will und fertig. Im Zweifel weiß der nichtmal, dass das in einer Clustertabelle steht.

"Unter der Haube" ist eine Persistenzschicht sehr komplex, aber das muss den Aufrufer ja (wie gesagt) nicht interessieren. Der macht ein result = bla->read( selkrit ). selkrit kann eine Struktur der Tabelle sein, also z. B. MARA. Oder eine Tabelle dieser Struktur. Oder eine Struktur, bei der alle Einzelfelder RANGE-Tabellen sind für das jeweilige Feld. Oder eine Tabelle einer solchen RANGE-Tabellen-enthaltenden Struktur. Was man reinwirft, wird "drinnen" analysiert und das Ergebnis (hier: result) ist eine Tabelle der Einträge (also z. B. eine Tabelle vom Zeilentyp MARA).

Das sind jetzt nur ein paar Beispiele, letztlich liegt ein Customizing dahinter, welcher Typ als selkrit erwartet wird und welcher Typ in result geliefert wird. So eine Persistenzklasse hat man ratzfatz erstellt, weil fast alles aus der Basisklasse geerbt wird und man nur noch Zugriffsmethoden bauen muss (damit man cls=>read_mara4matnr( matnr ) machen kann statt maraobj->read( marastruc ) in der dann nur das MATNR-Feld belegt ist). Eine Zugriffsmethode in die Persistenzklasse schreiben ist nicht aufwendiger als einen SELECT zu schreiben. Die kann man sich aber im Grunde schenken, wenn man keine Zeit hat. Es gibt ja eine öffentliche Schnittstelle (siehe unten).

Sowas wie die WHERE-Bedingung wird dann aus den Inhalten von selkrit generiert.

Der Vorteil gegenüber BOPF ist, dass die SAP das nicht unterstützen muss. Das geht also mit JEDER Tabelle. Und der Vorteil der generischen Persistenzschicht ist, dass man die Persistenz komplett von der Geschäftslogik entkoppelt. Das heißt insbesondere auch, dass Änderungen in der Persistenz nicht zwangsläufig dazu führen, dass ich alle DB-Zugriffe anpassen muss. Im Grunde könnte man sogar Dateien hochladen über diese Persistenzschicht.

Mein Tipp: Fang damit an, solche Persistenzklassen zu bauen, in der du für jeden select eine Methode baust. Also eine Klasse für die MARA mit einer Methode read_from_matnr( ) - importing matnr returning mara, für die Selektion eines einzelnen MARA-Satzes anhand seiner MATNR. Irgendwann wirst du merken, was sich immer und immer wiederholt und das verlagerst du in eine Oberklasse. Und irgendwann wirst du die WHERE-Bedingung generisch erzeugen wollen, um sie nicht immer in die Methode reinschreiben zu müssen (nach dem Motto: Was ich habe, übergebe ich doch der Methode - warum muss ich dann noch die WHERE-Bedingung jedesmal reinschreiben?). So bildet sich nach und nach eine Persistenzschicht heraus und du lernst Schritt für Schritt, was du brauchst und wie du das umsetzt.

Wie z. B. unsere Idee "wir müssen für jedes Einzelfeld auch eine RANGETAB übergeben können, sonst funktionieren zu viele Selektionen nicht". Dann schreibt man eine Routine, die eine solche RANGETAB als selkrit-Komponente erkennt und entsprechend auswertet.

Irgendwann baust du dir z. B. Tabellenpufferungen da ein und so weiter und so fort.

Als allerersten Schritt würde ich aber ein Interface (ZIF_PERSISTABLE) definieren, das von allen Persistenzklassen implementiert wird. Du brauchst in erster Linie die Methoden create( ), read( ), update( ) und delete( ). Bereite dich jetzt schon darauf vor, dass die zukünftig deine zentralen Zugriffsmethoden sein werden. Dann brauchst du nichts einzureißen, während du dazulernst.


Ralf

Folgende Benutzer bedankten sich beim Autor ralf.wenzel für den Beitrag (Insgesamt 3):
nickname8 (20. Mai 2019 19:42) • Icke0801 (21. Mai 2019 16:06) • 4byte (28. Mai 2019 10:09)


Re: ABAP Clean Code

Beitrag von nickname8 (Specialist / 106 / 15 / 16 ) » 20. Mai 2019 19:44

Schade dass man nur einmal auf bedanken klicken kann 😊
Ich werde drüber nachdenken, mir ein Konzept erarbeiten und bisschen damit rumspielen. Vor allem den Tipp mit dem Interface finde ich mega um einen Einstieg zu bekommen.

Re: ABAP Clean Code

Beitrag von ralf.wenzel (Top Expert / 3415 / 149 / 220 ) » 20. Mai 2019 19:48

Du irrst, du hast 3392 Beiträge (mit diesem 3393) zur Auswahl, von denen jeder einen Danke-Button hat *rofl*


Ralf

Re: ABAP Clean Code

Beitrag von DeathAndPain (Top Expert / 1052 / 122 / 230 ) » 20. Mai 2019 21:16

Und auch wenn er immer wieder behauptet, einem SELECT sei egal, ob ein konventionelles oder ein HANA-System angesprochen wird, wird das auch durch Wiederholung nicht richtiger. Wer sowas sagt, der hat sich die Dokumentationen und Anleitungen der SAP zu HANA noch nicht angesehen.
Nicht "wenn", sondern "falls", denn das habe ich nicht getan. Ich habe nicht von einem HANA-System, sondern nur von einer HANA-Datenbank gesprochen. Die kann man auch als ganz gewöhnliche relationale Datenbank nutzen, auch wenn man damit einiges verschenkt. Z.B. bei HCM geht es auch gar nicht anders, da HCM on HANA erst 2023 kommen soll.

Re: ABAP Clean Code

Beitrag von ralf.wenzel (Top Expert / 3415 / 149 / 220 ) » 20. Mai 2019 21:33

Klar kann ich das. Ich kann auch mit dem Ferrari Brötchen holen und mich wundern, dass ich die kaum schneller habe als mit dem Rad.

Fakt ist, dass man sich dazu einer Kompatibilitätsschicht bedient, und dann beschwerst du dich NICHT über die künstlich eingebaute Schicht, die man eigentlich nicht braucht.


Ralf

Re: ABAP Clean Code

Beitrag von DeathAndPain (Top Expert / 1052 / 122 / 230 ) » 21. Mai 2019 08:12

Klar braucht man sie, sonst würde R/3 on HANA nicht funktionieren.
Mein Tipp: Fang damit an, solche Persistenzklassen zu bauen, in der du für jeden select eine Methode baust. Also eine Klasse für die MARA mit einer Methode read_from_matnr( ) - importing matnr returning mara, für die Selektion eines einzelnen MARA-Satzes anhand seiner MATNR.
Womit man dann für jedes einzelne MARA-Feld, das man lesen möchte, effektiv wieder einen SELECT * macht wie in der guten alten Zeit...

Re: ABAP Clean Code

Beitrag von ralf.wenzel (Top Expert / 3415 / 149 / 220 ) » 21. Mai 2019 08:15

SELECT *? Nein, gerade nicht. Wie kommst du darauf?


Ralf

Re: ABAP Clean Code

Beitrag von DeathAndPain (Top Expert / 1052 / 122 / 230 ) » 21. Mai 2019 14:30

Weil Du mit Deinem importing matnr returning mara andeutest, dass Du die ganze Feldleiste MARA zurückzugeben gedenkst.

Re: ABAP Clean Code

Beitrag von ralf.wenzel (Top Expert / 3415 / 149 / 220 ) » 21. Mai 2019 14:43

Das Wort „Beispiel“ ist Dir geläufig? Ich schrieb: Wenn du einen MARA-Satz zur MATNR selektieren willst....

Im Übrigen muss im Returning-Parameter nicht jedes Feld gefüllt sein. Dennoch hat man mehrere Werte in einem Parameter (was Voraussetzung ist für returning).


Ralf

Re: ABAP Clean Code

Beitrag von DeathAndPain (Top Expert / 1052 / 122 / 230 ) » 22. Mai 2019 08:11

Du darfst mit "returning" keinen Einzelwert zurückgeben? Das halte ich für ein Gerücht.

Re: ABAP Clean Code

Beitrag von ST22 (Specialist / 235 / 22 / 28 ) » 22. Mai 2019 08:39

Ich denke Ralf meinte, wenn man mit Returning mehrere Werte zurück erhalten will, muss man das in eine Struktur verpacken und dann ist es egal, ob in dieser Struktur nur ein Feld gefüllt ist oder n.

Folgende Benutzer bedankten sich beim Autor ST22 für den Beitrag (Insgesamt 2):
ralf.wenzel (22. Mai 2019 08:56) • 4byte (28. Mai 2019 10:10)


Re: ABAP Clean Code

Beitrag von black_adept (Top Expert / 3243 / 54 / 568 ) » 22. Mai 2019 09:50

ST22 hat geschrieben:
22. Mai 2019 08:39
Ich denke Ralf meinte, wenn man mit Returning mehrere Werte zurück erhalten will, muss man das in eine Struktur verpacken und dann ist es egal, ob in dieser Struktur nur ein Feld gefüllt ist oder n.
Muss man nicht, da es auch anders geht. Aber es ist fast immer der sinnvollste Weg.
ralf.wenzel hat geschrieben:
20. Mai 2019 18:32
Und der Vorteil der generischen Persistenzschicht ist, dass man die Persistenz komplett von der Geschäftslogik entkoppelt. Das heißt insbesondere auch, dass Änderungen in der Persistenz nicht zwangsläufig dazu führen, dass ich alle DB-Zugriffe anpassen muss. Im Grunde könnte man sogar Dateien hochladen über diese Persistenzschicht.
ralf.wenzel hat geschrieben:
21. Mai 2019 14:43
Das Wort „Beispiel“ ist Dir geläufig? Ich schrieb: Wenn du einen MARA-Satz zur MATNR selektieren willst....
@Ralf: Leider hast du mit damit aber ein extrem ungünstiges Beispiel gebracht. Ich bin ja bei dir, wenn du eine Zwischenschicht einziehen willst um ein DAO zu generieren. Aber kann nicht so richtig nachvollziehen - wie D&P wahrscheinlich auch - was für Änderungen an der Persistenz geschehen müssten um mich zu zwingen größere DB-Zugriffsänderungen durchzuführen. Wann hat denn SAP irgendwann mal so etwas gemacht, dass ich auf die MARA ( oder irgend eine andere Standardtabelle ) nicht mehr lesend so zugreifen kann wie bisher.
Und wenn es um Eigenentwicklungen geht: Ich kann mich nicht entsinnen, dass ich oder ein anderer Entwickler in den Umgebungen in denen ich Coding habe Clustertabellen für irgend etwas verwendet hat wo ich auf den Gedanken kommen könnte so etwas wie falsche SELECTs darauf auszuprobieren.
Und letztlich: Wenn ich auf die MARA zugreifen will schreibe ich normalerweise SELECT...FROM MARA. Du schreibst irgend eine Klassenbasierten Zugriff, der dann im Anschluss genau das Selbe macht. Die Wahrscheinlichkeit, dass SAP die MARA so ändert, dass ich jemals meine Selects anpassen müsste halte ich für mehr als unwahrscheinlich.
Und wie ein Aufruf eines klassenbasierten Zugriffs auf die MARA gegenüber einem direkten SELECT auf die MARA die Persistenz von der Geschäftslogik entkoppelt entzieht sich mir bei genauerem Nachdenken auch - zumindest wenn ich nur deine Erklärungen durchgehe.

Folgende Benutzer bedankten sich beim Autor black_adept für den Beitrag:
DeathAndPain (24. Mai 2019 18:27)

live long and prosper
Stefan Schmöcker

email: stefan@schmoecker.de

Re: ABAP Clean Code

Beitrag von ralf.wenzel (Top Expert / 3415 / 149 / 220 ) » 22. Mai 2019 10:01

black_adept hat geschrieben:
22. Mai 2019 09:50
Und wenn es um Eigenentwicklungen geht: Ich kann mich nicht entsinnen, dass ich oder ein anderer Entwickler in den Umgebungen in denen ich Coding habe Clustertabellen für irgend etwas verwendet hat wo ich auf den Gedanken kommen könnte so etwas wie falsche SELECTs darauf auszuprobieren.
Darum geht es ja gar nicht, es geht darum, dass viele mit Cluster-Tabellen gar nicht umgehen können - bei unserem Konzept muss man nichtmal wissen, was eine Clustertabelle ist. Man muss eigentlich überhaupt nicht wissen, was eine Tabelle ist und wie man darauf zugreift oder ob die Daten auf verschiedene Tabellen verteilt sind.

Ich muss wissen: "Ich hätte gern die Labordaten zu folgenden Blutspendern: ... ". Wo die herkommen und wie die sich zusammensetzen, ist dabei völlig nebensächlich. Das ist insbesondere dann spannend, wenn dabei auf die DB eines fremden Systems zugegriffen wird, ohne dass der Entwickler, der die Daten bekommt, das überhaupt weiß.
black_adept hat geschrieben:
22. Mai 2019 09:50
Und letztlich: Wenn ich auf die MARA zugreifen will schreibe ich normalerweise SELECT...FROM MARA. Du schreibst irgend eine Klassenbasierten Zugriff, der dann im Anschluss genau das Selbe macht. Die Wahrscheinlichkeit, dass SAP die MARA so ändert, dass ich jemals meine Selects anpassen müsste halte ich für mehr als unwahrscheinlich.
Und wie ein Aufruf eines klassenbasierten Zugriffs auf die MARA gegenüber einem direkten SELECT auf die MARA die Persistenz von der Geschäftslogik entkoppelt entzieht sich mir bei genauerem Nachdenken auch - zumindest wenn ich nur deine Erklärungen durchgehe.
Also, wir haben hier ein agiles Projekt, wo sich die Tabellen in der Tat relativ häufig ändern. Zudem kann man schön Automatismen einbauen, die dann gleich für alle gelten (zum Beispiel das Füllen von "created_by..../updated_by...."-Feldern oder das Verhindern von Zugriffen mit leerer FOR ALL ENTRIES, Aufbauen einer zweiten DB-Verbindung für bestimmte Tabellen, um an der LUW vorbei Daten wegzuschreiben, etc.).

DAO-Klassen, wo dann explizit SELECTs drinstanden, hatte ich auch schon in Projekten, das macht auch nicht weniger Arbeit, man zentralisiert aber nichts.

Ralf

Re: ABAP Clean Code

Beitrag von black_adept (Top Expert / 3243 / 54 / 568 ) » 22. Mai 2019 11:13

ralf.wenzel hat geschrieben:
22. Mai 2019 10:01
Ich muss wissen: "Ich hätte gern die Labordaten zu folgenden Blutspendern: ... ". Wo die herkommen und wie die sich zusammensetzen, ist dabei völlig nebensächlich. Das ist insbesondere dann spannend, wenn dabei auf die DB eines fremden Systems zugegriffen wird, ohne dass der Entwickler, der die Daten bekommt, das überhaupt weiß.
SAP nennt so was BAPI.
ralf.wenzel hat geschrieben:
22. Mai 2019 10:01
Also, wir haben hier ein agiles Projekt, wo sich die Tabellen in der Tat relativ häufig ändern. Zudem kann man schön Automatismen einbauen, die dann gleich für alle gelten (zum Beispiel das ... )
Ihr entwickelt also eine robuste Schnittstelle auf eigene Tabellen, wo sich das eine oder andere noch ändern kann. Damit wird dann auch dein Entkopplungsargument klar. Aber dein Vorschlag an nickname8 zum Üben lief darauf hinaus eine Schnittstelle auf SAP-Standardtabelle MARA zu bauen. Das passt für mich einfach nicht gut zusammen...
live long and prosper
Stefan Schmöcker

email: stefan@schmoecker.de

Vorherige Seite 3 von 5 (current) Nächste

Aktuelle Forenbeiträge

Welche Entwicklertools?
vor 3 Stunden von LostDarkness 2 / 891
Werksspezifische Konfiguration kopieren
vor 5 Stunden von eleve 2 / 32
Removal of left space - next to a docking container
vor 5 Stunden von Haemma83 16 / 89

Unbeantwortete Forenbeiträge

BAPI_PO_CREATE1 und Einkaufsinfosatz
vor 2 Tagen von SweetRuedi 1 / 74
WCOCO: Gruppe für Betragsfelder 0S01
vor 5 Tagen von SAP_ENTWICKLER 1 / 48
CAS-Nr.: Chemical Abstracs Service
vor einer Woche von SAP_ENTWICKLER 1 / 87
Interaktives Skript, Rolle IC-Manager
vor 3 Wochen von erubadhron86 1 / 124