Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
jpsapabap21
Participant
I recently stumbled upon ABAP 7.5 documentation. I was interested to see what is new. But rather I got to know what is old. SAP now says that subroutines are obsolete.

Shocked? Well, I was. I have been using performs and have always preferred them over methods. A habit that I am trying to change but not very successful at it so far.

So when I saw the statement 'Performs are Obsolete'. I was bit worried - how would I cope with this?

As per the guidelines available at this link, whenever you are developing new code, do not create new Subroutines(Performs) or Function Modules, use objects/methods instead.

The rules say, and there are couple of them -

Rule 1 : Do not implement in function modules and subroutines

Use FMs and Performs only if they are a must. Use Methods instead.

Rule 2 : Use ABAP Objects

Use ABAP objects wherever possible for new and further developments. Classic processing blocks should only be created in exceptional cases.

And as per every rule, these rules also have exceptions. Not everything can be done in classes. Well, not yet. So the exception is long. But over the time SAP will reduce the exceptions. Some of the exceptions are as below –

  1. RFC function modules – RMI or Remote Method Invocation is not yet available

  2. Update function modules – These are still to be used

  3. CALL SCREEN and CALL SELECTION-SCREEN – Object-oriented handling of classic dynpros is still not available. This is a feature that I personally would love. 

  4. PERFORM ON COMMIT|ROLLBACK – We anyways do not use these generally, but if you have to – go ahead.

  5. GENERATE SUBROUTINE POOL – I had to use this only once in 13 years. So not really looking forward.


So, our new ABAP reports should still be created using a program, have selection screen and have events, but instead of performs we should have methods. Here is an example of how it should look.
*&--------------------------------------------------------*
*& Report YABAP_750_REPORT
*&--------------------------------------------------------*
*&
*&--------------------------------------------------------*
REPORT yabap_750_report.

CLASS lcl_alv DEFINITION FINAL.

PUBLIC SECTION.
CONSTANTS :
information TYPE sy-msgty VALUE 'I'.

TYPES :
tt_flights TYPE STANDARD TABLE OF sflight
WITH EMPTY KEY.
"... add more types here

METHODS :
constructor
IMPORTING
i_carrier TYPE sflight-carrid
i_connection TYPE sflight-connid,
start_report_process
RETURNING
VALUE(r_error) TYPE char1.

"... add more public methods here

PROTECTED SECTION.
"Add protected data/methods if needed

PRIVATE SECTION.
DATA :
carrier TYPE sflight-carrid,
conn_id TYPE sflight-connid,
flights TYPE tt_flights.
"... add more data declarations here

METHODS :
get_flights
RETURNING
VALUE(rt_flights) TYPE tt_flights,
display_flights
RETURNING
VALUE(r_error) TYPE char1.
"... add more private methods here

ENDCLASS.

CLASS lcl_alv IMPLEMENTATION.
METHOD constructor.
"Set variables based on called parameters
carrier = i_carrier.
conn_id = i_connection.
"Initialize attributes
CLEAR flights.
ENDMETHOD.

METHOD start_report_process.
CLEAR r_error.
flights = get_flights( ).
IF flights IS INITIAL.
MESSAGE e001(00) WITH 'No data found'(002)
INTO DATA(lv_error).
r_error = abap_true.
ELSE.
r_error = display_flights( ).
ENDIF.
ENDMETHOD.

METHOD get_flights.
CLEAR rt_flights.
SELECT * FROM sflight INTO TABLE @rt_flights
WHERE carrid = @carrier
AND connid = @conn_id.
ENDMETHOD.

METHOD display_flights.
CLEAR r_error.
TRY.
"Create ALV table object for the output data table
cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_table)
CHANGING t_table = flights ).
lo_table->get_functions( )->set_all( ).
lo_table->get_columns( )->set_optimize( ).
lo_table->display( ).
CATCH cx_salv_msg. "ALV can not be displayed, issue error
MESSAGE e001(00) WITH 'Error in ALV creation'(003) INTO DATA(lv_error).
r_error = abap_true.
ENDTRY.
ENDMETHOD.

"... add more methods implementation here
ENDCLASS.

"... build selection screen here or in another include
SELECTION-SCREEN BEGIN OF BLOCK main_block WITH FRAME TITLE TEXT-001.
PARAMETERS : carrid TYPE sflight-carrid,
connid TYPE sflight-connid.
SELECTION-SCREEN END OF BLOCK main_block.

START-OF-SELECTION.
"Create object for the class
DATA(o_alv) = NEW lcl_alv( i_carrier = carrid
i_connection = connid ).

"Below code starts the main process and issues error
"It can be coded as per requirement
IF o_alv->start_report_process( ) IS NOT INITIAL.
MESSAGE ID sy-msgid TYPE lcl_alv=>information NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.

 

Conclusion:



  • If you have not switched to using methods over performs, this is the time to do so.

  • Using this or a similar template, reports can be created very easily.

  • This style can also be applied to other programs, like file/proxy based interface program.


In short, the message is, even if we are used to a way of coding, which is also comfortable, we should change with the ABAP advancements.

And this, is my first step.

This is also my first blog, so your comments and suggestions are welcome. Please use the comment section below or you can also post your questions here.

 

- Jagdish Patil
31 Comments
BiberM
Active Participant
Welcome and keep on learning on that path. In my opinion it it totally worth it and overdue.

Just another hint: some of your Exceptions are only partially exceptions: at least for the use cases 1 and 2 you can use the function Module as pure wrapper. They can contains only one Method call.
joltdx
Active Contributor
Yes, you have the right approach! Let's go!

(And to be fair, PERFORM have been obsolete since long before 7.50 🙂)
keremkoseoglu
Contributor
When you have a local class with a constructor, extended check may warn you that you have a global variable.

To prevent that, I tend to make all methods and variables of "lcl_alv" static.
jpsapabap21
Participant
Thanks Kerem for this tip. Its definitely useful.

I used to create the object inside a subroutine, but then, you know. 🙂

 
jpsapabap21
Participant
Hi Jörgen

Thanks for the link. I feel a little embarrassed now that I never knew this. 7.3 has been around for so long, and I am using subroutines as well for so long that I never thought this could be the case.

As I said, I just happened to come across this by mistake. And I am glad that I did, because for past so many years, I kept avoiding using objects.
Sandra_Rossi
Active Contributor

As you say, "there are exceptions", but "exception classes" are not exceptions and I would use them so that to write the starting code differently, but it's a matter of preference I guess 😉

TRY.
o_alv->start_report_process( ).
CATCH cx_root INTO DATA(x_root).
MESSAGE x_root TYPE 'I' DISPLAY LIKE 'E'.
ENDTRY.

NB: some people prefer to catch only what is expected to be raised, I prefer to catch everything at the lowest level.

jpsapabap21
Participant
0 Kudos
Hi Michael

Overdue !! So true.

On the exceptions - yes, I agree that this code sample does not use exceptions well. Something to improve for me. Will definitely work on it.
Sandra_Rossi
Active Contributor
If the documentations before 7.31 had not been removed, you could find out that PERFORM is obsolete since 7.02 (2009) 😄
jpsapabap21
Participant
Thanks Sandra. Its been a long time since we interacted.

Yes, I have this confusion, which one is the correct way. I also prefer the cx_root, but not because of any particular reason but its simpler as I don't have to check which ones to handle.
hardyp180
Active Contributor
In some sense subroutines became obsolete when ABAP Objects was introduced in SAP 4.6 back in the year 2000, even if they were only "officially" obsolete in 2009.

However I would imagine that of all the new ABAP code that has been written all around the world on this very day, 75%+ would be done in FORM routines.

21 years and counting and still very little uptake.

So I would disagree with one of the statements in the above blog.

  • If you have not switched to using methods over performs, this is the time to do so.


Should be replaced by

  • If you have not switched to using methods over performs, the year 2000 was the time to start doing so, so you are a bit late to the party


Whilst I am asking for the impossible, how about people investigating ABAP Unit and TDD as well?

Cheersy Cheers

Paul

 
joltdx
Active Contributor
0 Kudos
Well, the information has in fact been out there, but nobody MAKES us read it... Between that and the fact that things are backwards compatible and that obsolete things still actually work (for a good reason), we either need to find it or be told it. And the more the better!
jpsapabap21
Participant
0 Kudos
Hi Paul

Late to the party indeed.

Its too bad that all the new ABAPers that get trained on the job or through the Fresher's training or whatever the term different organization use - all use this old style.

I got trained in 2007 in ABAP, and the 21 days training did not cover CREATE OBJECT at all. OOABAP was treated as a different skillset than ABAP.

Only if I could go back in time and get started on this in 2007.

 
Michael_Keller
Active Contributor

Little addition: One of the very rare use cases for subroutines in these days is message control. You need a subroutine (form) in a processing program (report) to process a message.

jpsapabap21
Participant
0 Kudos
Hi Michael

Can you share more information on this? A code snippet or any link may be?
arseni_gallardo
Active Participant
0 Kudos
Hi Jardish,

 

You do not need the PERFORM ON COMMIT|ROLLBACK functionality. You can create handler methods for event TRANSACTION_FINISHED of class CL_SYSTEM_TRANSACTION_STATE. The KIND parameter will tell you whether you are in COMMIT or in ROLLBACK.
jpsapabap21
Participant
0 Kudos
Hi Arseni

Thanks for this tip, I will definitely try this.

We don't get such use case too often for development, but I will try to check this as I am curious to see how this works.
jpsapabap21
Participant
0 Kudos
Yes, the information needs to be shared.

I heard a story today -

Developer used Inline Declarations and a SME in a external(outside project) SME review asked to move all the data declaration to TOP include. 🙂
former_member660513
Participant
I started with ABAP in 2008 on 7.02. And form routines were considered obsolete already. Whether you like them or not, or you prefer them to OO artefacts, is a matter of own taste, i guess.

What really irritates me from the programming language point of view, is that the syntaxes are not identical - who the FORM signature looks like(syntax) and the METHOD signature(syntax).

Meaning, that there are multiple ways to get the same task done, which i personally don't like.

Also, they drive you to think differently( slightly different flow, because of the different syntactic possibilities ).

I would say choose of them, and stick to the approach  - personally try to do everything which is technically possible with the OO syntax, use FMs when needed, and form routines only in exceptional cases.

Developers using other technologies would probably ask the question 'From when on will the obsolete stuff will become really not supported' 🙂

I would guess, the way i know SAP, that the language features will be really restricted only on special platforms, like ABAP for Cloud Development(which dont have a huge codebase, yet... ) or NGAP, etc.. So we will be seeing form routines for many years to come 🙂
SuhaSaha
Advisor
Advisor
Well, i am not quite sure what you mean. If you want to control the order of execution of the routines you have to use the PERFORM ON COMMIT.

I don't think there is an alternate solution available yet.
Michael_Keller
Active Contributor
jpsapabap21
Participant
0 Kudos
Thanks Michael. I got it now.

I believe we would find similar application of subroutines in table maintenance generator events or a substitution routine.  But these would be a must have subroutines till the time there is replacement.

FMs would also be used in scenarios like screen enhancement for transactions like BP(Business Partner) using the BDT.
larshp
Active Contributor
ABAP is such a large language, that personally I cannot remember what is preferred/obsolete, so every time I encounter something, I implement tooling to remind me, this so far has resulted in

https://github.com/larshp/abapOpenChecks

and

https://abaplint.org

which both have multiple rules to find obsolete syntax,
jtidalgo
Explorer
Interesting. I also found out recently (this week) that subroutines are already obsolete. Good read!
jpsapabap21
Participant
0 Kudos
Thanks Lars for these links. Its very interesting stuff. I will try to use this and share the result.
Jelena
Active Contributor
0 Kudos
Get rid of r_error and use the exceptions all the way.

The exception handling is one of the best things about using classes/methods. It used to be a pain in the back to do something like that in the routines (you'd have to declare a bunch of r_error's in every one of them just to display an error message somewhere at the top). Once you realize the advantage of exceptions, there is no going back to the subroutines. Makes the code more readable too.

Thanks for sharing!
matt
Active Contributor
0 Kudos
Having initially felt that, I now use class based exceptions exclusively. They're so much more flexible. As you find the first time you have to pass the return code up to a higher level.

Furthermore, it might be an indication that you've not really layered your development properly.

Fwiw, my model classes always throw exceptions - which are then handled by the controller class.
madhu_vadlamani
Active Contributor
0 Kudos
Nice.
jpsapabap21
Participant
0 Kudos
Thanks Jelena. Yes, this is absolutely valid suggestion and I am adopting the use for exceptions in the actual programs. In this blog post I avoided its use because lot of people who are not used to classes and methods will see the exceptions and think its more complicated and stick to performs.
jpsapabap21
Participant
0 Kudos
Thanks Madhu.
0 Kudos
Starting Point
BaerbelWinkler
Active Contributor
0 Kudos

This may be a stupid question, but here goes:

I recently had to apply changes to a typical userexit's Z-Include:

FUNCTION EXIT_SAPLV50E_003.
*"----------------------------------------------------------------------
*"*"Lokale Schnittstelle:
*" IMPORTING
*" VALUE(I_DOCUMENT) LIKE RL50E-K_FLAG DEFAULT '2'
*" ....
*" CHANGING
*" VALUE(C_EXPORT_LINE_ITEM_DATA) LIKE EIPO
*" STRUCTURE EIPO DEFAULT ' '
*" ...
*"----------------------------------------------------------------------
INCLUDE ZXV50U03.
ENDFUNCTION.

The logic had thus far been added directly in ZXV50U03 and I wanted to a) create my new (small) logic in its own routine and b) move the existing code from the include into it's own routine. As I was working in the function module context I went the easy route and simply created new form routines which ended up in their own (new) include ZXV50F01 as is usually the case for these user exits. They now get called from within IF-statements:

IF i_sales_org EQ 'ABCD'.
PERFORM zz_determine_exart USING i_invoice_item
CHANGING c_exart.
ENDIF.

IF i_invoice_item-werks = 'ABCD'.
PERFORM zz_determine_verld USING i_invoice_item
CHANGING c_export_line_item_data-verld.
ENDIF.

Could I have easily avoided these PERFORMs and if so how? I just can't picture how working with classes and methods would look like in this particular context and how much "overhead" it would generate to set up. Especially given that I did this as part of a fairly quick code change and not some general clean-up task.

Thanks much and cheers

Bärbel

Note: I created a stand-alone question for this now over in Q&A to give it more visibility.

Labels in this area