Application Development and Automation Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

unused custom code ABAP

0 Likes
9,911

Hi All,

Is there a way in ABAP to find unused custom code by executing any standard reports.

Regards

Jude

1 ACCEPTED SOLUTION
Read only

BaerbelWinkler
SAP Champion
SAP Champion
7,532

judemelvin

Hi Jude,

we are currently having similar discussions, so here is some feedback, based on systems running on NW 750 with EHP8 on HANA-DB:

Removing unused custom code from the system right away just because it looks as if a program is no longer used, may not be the best approach. If it's a rarely run but important program this can cause quite a few hassles when the program is needed again. So, for starters you need at least one year's worth of runtime information before you make such a decision to ensure that you at the very least capture executions for month- and year-end-closing.

The way we have been tackling this, is to simply flag presumably no longer needed programs as obsolete via an entry in a Z-table. If somebody then comes along and requires the program again, all that is needed is to delete the flag which obviously is much more hassle-free than having to recreated the program from scratch (or versioning).

Once a program has been in this incactive-state for some time, we may make the decision to physically delete it. But that then entails to also (and as a first step) delete all the variants and transactions which may exist in the systems for the program.

In order to know which programs are candidates for deactivation we've somewhat relied on a old custom-process which updates a counter for executions of programs in a Z-table. This is done via a modification in the ABAP-runtime program from where a function module gets called. This however only works for report programs started via a selection-screen and - as we recently noticed - doesn't necessarily capture all executions.

I created a program which queries this Z-table and recently enhanced it by also retrieving data from ST03N via function module SAPWL_WORKLOAD_GET_STATISTIC. The code to do that is a bit complex due to the way the retrieved data looks (and the FM has not been released by SAP) but it works and provides better data for more programs than our Z-process.

My not really pretty code looks like this:

  DATA: lv_date LIKE sy-datum.
  DATA: lt_usertcode TYPE STANDARD TABLE OF sapwlustcx,
        ls_usertcode TYPE sapwlustcx.

  DATA: BEGIN OF ls_st03n,
          report LIKE trdir-name,
          tcode  LIKE tstc-tcode,
          count  LIKE sapwlustcx-count,
        END OF   ls_st03n.

  DATA: lt_st03n LIKE TABLE OF ls_st03n.

  DATA: ls_st03n_all LIKE gs_st03n,
        lt_st03n_all LIKE gt_st03n.

  DATA: BEGIN OF ls_tcode,
          tcode TYPE tstc-tcode,
        END OF   ls_tcode.

  DATA: lt_tcode LIKE STANDARD TABLE OF ls_tcode.

  DATA: BEGIN OF ls_tstc,
          tcode TYPE tstc-tcode,
          pgmna TYPE tstc-pgmna,
        END OF   ls_tstc,
        lt_tstc LIKE STANDARD TABLE OF ls_tstc.

  FIELD-SYMBOLS: <fs_st03n> LIKE ls_st03n.

  "You need to have a start date
  lv_date = gv_st03n_date.
  lv_date+6(2) = '01'.

  "For each month determine ST03N data - all the data will be retrieved!
  DO.

    CLEAR lt_usertcode.

    CALL FUNCTION 'SAPWL_WORKLOAD_GET_STATISTIC'
      EXPORTING
        periodtype            = 'M'
        startdate             = lv_date
        instance              = 'TOTAL'
      TABLES
        application_statistic = lt_usertcode
      EXCEPTIONS
        unknown_periodtype    = 1
        no_data_found         = 2
        no_server_given       = 3
        OTHERS                = 4.

    IF sy-subrc EQ 0.

      "Returned table lt_usertcode gives either the reportname or
      "the tcode in field entry_id. What it is needs to be determined
      "via the "T" or "R" at the end of the field
      LOOP AT lt_usertcode INTO ls_usertcode.
        CLEAR ls_st03n.
        ls_st03n-count = ls_usertcode-count.
        IF ls_usertcode-entry_id+72(1) EQ 'T' AND
           ls_usertcode-entry_id(1)    EQ 'Z'.
          "Entry is for a Z-TCode
          ls_st03n-tcode = ls_usertcode-entry_id(20).
          "Store Z-TCodes for upcoming look-up
          "of report names
          ls_tcode-tcode = ls_usertcode-entry_id(20).
          COLLECT ls_tcode INTO lt_tcode.
        ELSEIF ls_usertcode-entry_id(1)    EQ 'Z'.
          ls_st03n-report = ls_usertcode-entry_id(40).
        ENDIF.
        IF ls_st03n-report IS NOT INITIAL OR
           ls_st03n-tcode  IS NOT INITIAL.
          COLLECT ls_st03n INTO lt_st03n.
        ENDIF.
      ENDLOOP.
    ENDIF.

    "Get next month until date larger than today
    CALL FUNCTION 'MONTH_PLUS_DETERMINE'
      EXPORTING
        months  = 1
        olddate = lv_date
      IMPORTING
        newdate = lv_date.

    IF lv_date GT sy-datum.
      EXIT.
    ENDIF.

  ENDDO.

  "Get reportnames for TCodes from TSTC
  IF lt_tcode IS NOT INITIAL.

    SELECT tcode, pgmna
      FROM tstc
      INTO CORRESPONDING FIELDS OF TABLE @lt_tstc
       FOR ALL ENTRIES IN @lt_tcode
     WHERE tcode = @lt_tcode-tcode.

    IF sy-subrc EQ 0.
      SORT lt_tstc BY tcode.
    ENDIF.
  ENDIF.

  "Collect all data based on reportname into final table
  LOOP AT lt_st03n INTO ls_st03n.

    ls_st03n_all-count = ls_st03n-count.

    "Get reportname if ST03N-data contained TCode
    IF ls_st03n-tcode IS NOT INITIAL.
      READ TABLE lt_tstc INTO ls_tstc
                         WITH KEY tcode = ls_st03n-tcode
                         BINARY SEARCH.

      IF sy-subrc EQ 0 AND
         ls_tstc-pgmna IS NOT INITIAL.
        ls_st03n_all-report = ls_tstc-pgmna.
      ENDIF.
    ELSE.
      ls_st03n_all-report = ls_st03n-report.
    ENDIF.

    COLLECT ls_st03n_all INTO lt_st03n_all.

  ENDLOOP.

  SORT lt_st03n_all BY report.

For this to work, ST03N data collection has to have been active in your system(s) for as long as possible, otherwise you'll not get anything meaningful back.

We are currently looking into getting "proper" data via SCMON but are facing some technical issues which are already beeing looked at. So, for the time being we keep relying on our stitched-together custom solution.

Hope this helps!

Cheers

Bärbel

14 REPLIES 14
Read only

Former Member
0 Likes
7,532

Hi,

There is nothing standard available to retrieve unused code. But if you mean within 1 report, the extended check can come up with code that is not used.

Please explain exactly what you want and what you're trying to achieve.

Kind regards, Rob Dielemans

Read only

0 Likes
7,532

Hi Rob,

Functional team wants to remove all the unused custom codes from the system, this is what they want to achieve.

Regards

Jude

Read only

matt
Active Contributor
0 Likes
7,532

I'm fascinated. Why does the functional team want to remove unused code from the system? That has absolutely zero relevance to functional analysts - their work is in MM, LM, BI etc...

Read only

0 Likes
7,532

Hi Jude,

That is a valueless achievement. A good achievement would be: we want to lower TCO by 10% in 2019.

And reducing the number of custom coded objects is one of several means to reach that goal.

Kind regards, Rob Dielemans

Read only

OlgaDolinskaja
Product and Topic Expert
Product and Topic Expert
7,532

Hi Jude,

you can use transaction SCMON to monitor the usage of custom code. But: you need to do it for a certain period of time.

See https://blogs.sap.com/2017/04/06/abap-call-monitor-scmon-analyze-usage-of-your-code/ for further details.

Best regards,

Olga.

Read only

0 Likes
7,532

Hi Olga,

I have seen this blog, however my AS ABAP version is 7.40, i do have solman 7.2 but when i run through the setup i see few SAP notes to be implemented but my version does not fulfill the prerequisites hence looking for a report or a way to extract it with in the system not via solman

Regards

Jude

Read only

0 Likes
7,532

Hello,

In my backend system (ST-PI 7.40 SP06), the transaction is /SDF/SCMON instead of SCMON. Did you try to run it in your ABAP system ?

Regards

Read only

0 Likes
7,532

Hi Olga,

Currently I am working on the prerequisites based on your blog, hope i will be able to check the details via solman.

Read only

kiran_k8
Active Contributor
0 Likes
7,532

unused custom code means commented one or the Z Programs ?

K.Kiran.

Read only

BaerbelWinkler
SAP Champion
SAP Champion
7,533

judemelvin

Hi Jude,

we are currently having similar discussions, so here is some feedback, based on systems running on NW 750 with EHP8 on HANA-DB:

Removing unused custom code from the system right away just because it looks as if a program is no longer used, may not be the best approach. If it's a rarely run but important program this can cause quite a few hassles when the program is needed again. So, for starters you need at least one year's worth of runtime information before you make such a decision to ensure that you at the very least capture executions for month- and year-end-closing.

The way we have been tackling this, is to simply flag presumably no longer needed programs as obsolete via an entry in a Z-table. If somebody then comes along and requires the program again, all that is needed is to delete the flag which obviously is much more hassle-free than having to recreated the program from scratch (or versioning).

Once a program has been in this incactive-state for some time, we may make the decision to physically delete it. But that then entails to also (and as a first step) delete all the variants and transactions which may exist in the systems for the program.

In order to know which programs are candidates for deactivation we've somewhat relied on a old custom-process which updates a counter for executions of programs in a Z-table. This is done via a modification in the ABAP-runtime program from where a function module gets called. This however only works for report programs started via a selection-screen and - as we recently noticed - doesn't necessarily capture all executions.

I created a program which queries this Z-table and recently enhanced it by also retrieving data from ST03N via function module SAPWL_WORKLOAD_GET_STATISTIC. The code to do that is a bit complex due to the way the retrieved data looks (and the FM has not been released by SAP) but it works and provides better data for more programs than our Z-process.

My not really pretty code looks like this:

  DATA: lv_date LIKE sy-datum.
  DATA: lt_usertcode TYPE STANDARD TABLE OF sapwlustcx,
        ls_usertcode TYPE sapwlustcx.

  DATA: BEGIN OF ls_st03n,
          report LIKE trdir-name,
          tcode  LIKE tstc-tcode,
          count  LIKE sapwlustcx-count,
        END OF   ls_st03n.

  DATA: lt_st03n LIKE TABLE OF ls_st03n.

  DATA: ls_st03n_all LIKE gs_st03n,
        lt_st03n_all LIKE gt_st03n.

  DATA: BEGIN OF ls_tcode,
          tcode TYPE tstc-tcode,
        END OF   ls_tcode.

  DATA: lt_tcode LIKE STANDARD TABLE OF ls_tcode.

  DATA: BEGIN OF ls_tstc,
          tcode TYPE tstc-tcode,
          pgmna TYPE tstc-pgmna,
        END OF   ls_tstc,
        lt_tstc LIKE STANDARD TABLE OF ls_tstc.

  FIELD-SYMBOLS: <fs_st03n> LIKE ls_st03n.

  "You need to have a start date
  lv_date = gv_st03n_date.
  lv_date+6(2) = '01'.

  "For each month determine ST03N data - all the data will be retrieved!
  DO.

    CLEAR lt_usertcode.

    CALL FUNCTION 'SAPWL_WORKLOAD_GET_STATISTIC'
      EXPORTING
        periodtype            = 'M'
        startdate             = lv_date
        instance              = 'TOTAL'
      TABLES
        application_statistic = lt_usertcode
      EXCEPTIONS
        unknown_periodtype    = 1
        no_data_found         = 2
        no_server_given       = 3
        OTHERS                = 4.

    IF sy-subrc EQ 0.

      "Returned table lt_usertcode gives either the reportname or
      "the tcode in field entry_id. What it is needs to be determined
      "via the "T" or "R" at the end of the field
      LOOP AT lt_usertcode INTO ls_usertcode.
        CLEAR ls_st03n.
        ls_st03n-count = ls_usertcode-count.
        IF ls_usertcode-entry_id+72(1) EQ 'T' AND
           ls_usertcode-entry_id(1)    EQ 'Z'.
          "Entry is for a Z-TCode
          ls_st03n-tcode = ls_usertcode-entry_id(20).
          "Store Z-TCodes for upcoming look-up
          "of report names
          ls_tcode-tcode = ls_usertcode-entry_id(20).
          COLLECT ls_tcode INTO lt_tcode.
        ELSEIF ls_usertcode-entry_id(1)    EQ 'Z'.
          ls_st03n-report = ls_usertcode-entry_id(40).
        ENDIF.
        IF ls_st03n-report IS NOT INITIAL OR
           ls_st03n-tcode  IS NOT INITIAL.
          COLLECT ls_st03n INTO lt_st03n.
        ENDIF.
      ENDLOOP.
    ENDIF.

    "Get next month until date larger than today
    CALL FUNCTION 'MONTH_PLUS_DETERMINE'
      EXPORTING
        months  = 1
        olddate = lv_date
      IMPORTING
        newdate = lv_date.

    IF lv_date GT sy-datum.
      EXIT.
    ENDIF.

  ENDDO.

  "Get reportnames for TCodes from TSTC
  IF lt_tcode IS NOT INITIAL.

    SELECT tcode, pgmna
      FROM tstc
      INTO CORRESPONDING FIELDS OF TABLE @lt_tstc
       FOR ALL ENTRIES IN @lt_tcode
     WHERE tcode = @lt_tcode-tcode.

    IF sy-subrc EQ 0.
      SORT lt_tstc BY tcode.
    ENDIF.
  ENDIF.

  "Collect all data based on reportname into final table
  LOOP AT lt_st03n INTO ls_st03n.

    ls_st03n_all-count = ls_st03n-count.

    "Get reportname if ST03N-data contained TCode
    IF ls_st03n-tcode IS NOT INITIAL.
      READ TABLE lt_tstc INTO ls_tstc
                         WITH KEY tcode = ls_st03n-tcode
                         BINARY SEARCH.

      IF sy-subrc EQ 0 AND
         ls_tstc-pgmna IS NOT INITIAL.
        ls_st03n_all-report = ls_tstc-pgmna.
      ENDIF.
    ELSE.
      ls_st03n_all-report = ls_st03n-report.
    ENDIF.

    COLLECT ls_st03n_all INTO lt_st03n_all.

  ENDLOOP.

  SORT lt_st03n_all BY report.

For this to work, ST03N data collection has to have been active in your system(s) for as long as possible, otherwise you'll not get anything meaningful back.

We are currently looking into getting "proper" data via SCMON but are facing some technical issues which are already beeing looked at. So, for the time being we keep relying on our stitched-together custom solution.

Hope this helps!

Cheers

Bärbel

Read only

0 Likes
7,532

"we've somewhat relied on a old custom-process which updates a counter for executions of programs in a Z-table. This is done via a modification in the ABAP-runtime program from where a function module gets called."

What modification in the ABAP-runtime have you done ? What is the name of this standard object(s) ?

Read only

7,532

chaouki.akir

It's just a call to a Z-function module in program RSDBRUNT at the beginning of FORM %_INIT_PAI. Due to its location it only captures - as mentioned above - executions of report-programs with a selection-screen. The modification has been in there for many years without causing issues as far as I know and when it was introduced UPL/SCMON didn't yet exist. But, I don't think that anybody would (or should) approve such a modification today as standard alternatives are available, providing data which is a lot more reliable.

Read only

stefan3
Discoverer
0 Likes
7,532

Hello Jude,

The Code Inspector is a tool that offers different static checks of program code. It can be called by right-clicking on the program name in the Object Navigator and select Check -> Code Inspector from the context menu. Also, it can be called separately using transaction code SCI. This way, you can create your own check variants. The initial screen looks like in the following picture.

Inspection field is used if the result shall be saved or execution performed in a background job. Object Set field is used for selecting the repository objects that shall be included in the check. Check Variant is used to define which checks shall be performed and by clicking on a new button - you can choose check categories. Under the category Syntax Check/Generation there is search function Search of ABAP-Tokens. This way, you can search comments for a particular search string (e.g. *TODO*).

Hope this helps you!

Best Regards,

Stefan

Read only

matt
Active Contributor
7,532

I worked on a project removing unused code. We used UPL (the predecessor to SCMON). Interesting technical side note - the data is stored in BW cubes, once extracted from the managed systems. But then the data is taken out of those cubes and put into database tables. My suspicion is that the team tasked with building these applications didn't understand how to query cubes...

But anyway.

We used 14 months of data so as to avoid removing yearly run programs. We also put the object key of the object to be delete into a transport of copies, then release that transport - and then deleted the object itself. This way, if we did delete something important, it could be recovered simply be importing the ToC.

Of course, when dealing with tens of thousands of objects, these tasks need some automation. Since you'll be probably storing many objects in a single backup ToC transport, so you'll want to do any recovery into a sandpit system - then just take the objects that you need from there. Interestingly, again, if you look at the code used by SOLMAN on the managed system, it looks like SAP started producing this kind of automation, but gave up - it gets very difficult with function groups.