Technical Articles
Constants management
Hi,
In every system i work i usually have a table for constants management, some tables are designed for single values, some tables to accept ranges too, but generally each table i found for constants management have some limitations.
I’m actually using a solution that give me enough freedom to accomodate any kind of constant i need and i’ve been built a class to work with the table in a way i feel comfortable, i’m going to share some code to work with single values and SAP ranges, but the class is expandable and the table fields can hold anything you need, while reading i recommend you to see the code in the github repository at the end of the post, without full source code it may be hard to follow the explanation.
I usually find tables with a single field or with fields for SIGN, OPTION, LOW and HIGH to let you define range constants too, but the table field to hold the values usually is defined with a length, this can be a limitation if you have to write a very long constant, the fields i defined for my constant table are:
The value will be a string, and i defined just a single field, because to have the flexibility i’m looking for i will be writing the constants in an XML format sometimes, for example in the case i want to write a SAP range. This xml will be generated and processed by a class that will have the purpose of ease the developer work.
The public interface of my class will have two main methods:
- READ_CONSTANT – For reading a constant i will need just one input parameter the constant name (PI_NAME) and the main output parameter will be PE_VALUE defined as type ANY.
- WRITE_CONSTANT – For writing a constant i will need four input parameters, the contant name (PI_NAME), the constant group (PI_GROUP), which only purpose is organizative, i will also need the type of constant i want to write (PI_TYPE), for this post i will work with two types, single field or SAP range, and finally i will need a variable with the value i must write to constants table (PI_VALUE).
Inside the READ_CONSTANT and WRITE_CONSTANT i will organize the code in separate methods for each type of constant, this methods will be private, for this post i will have:
- HELPER_READ_CONST_FIELD
- HELPER_WRITE_CONST_FIELD
- HELPER_READ_CONST_SAP_RANGE
- HELPER_WRITE_CONST_SAP_RANGE
It means that you can add new types and code for your new types, this makes the constant manager expandable and when combined with XML string that means that you would could save anything you need. You can use JSON if you feel more confortable or any kind of custom format you want, you just have to code a READ and WRITE method that know how to save and retrieve it back to a variable of the correct type.
You will notice the class have a CONFIGURE_CONSTANT method too, the purpose of this method is to show some kind of UI that allow the developer to configure it in a comfortable way, i didn’t found yet a way that fully satisfy me when configuring SAP ranges this is why, for now, CONFIGURE_CONSTANT will have just a private method for single fields, but in the examples below i will show how i work with range constants to make my life as easy as possible.
For details of implementation you can go to github repository, let’s now explain how i use this when coding a program, i’m going to explain first how i work with single field constants, in the github repository you have the program ZTOOLS_CM_R001 which code is:
*&---------------------------------------------------------------------*
*& Report ZTOOLS_CM_R001
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT ZTOOLS_CM_R001.
TABLES: sscrfields.
CONSTANTS: c_const_group TYPE ztools_const_group VALUE 'ZTOOLS_CM_R001',
c_const_name TYPE ztools_const_name VALUE 'TEST_FIELD_CONSTANT'.
DATA: d_developer TYPE abap_bool.
PARAMETERS: p_value TYPE i.
SELECTION-SCREEN FUNCTION KEY 1.
INITIALIZATION.
PERFORM initialization.
AT SELECTION-SCREEN.
PERFORM at_selection_screen.
START-OF-SELECTION.
PERFORM start_of_selection.
*&---------------------------------------------------------------------*
*& Form INITIALIZATION
*&---------------------------------------------------------------------*
FORM initialization .
* Determine if the user is a developer, constant configuration buttons
* will be shown only for developers.
* For testing purposes all users are devs.
d_developer = abap_true.
IF d_developer = abap_true.
CONCATENATE icon_configuration 'Config. test constant'
INTO sscrfields-functxt_01.
ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form AT_SELECTION_SCREEN
*&---------------------------------------------------------------------*
FORM at_selection_screen .
CASE sy-ucomm.
WHEN 'FC01'.
PERFORM configure_test_constant.
ENDCASE.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form CONFIGURE_TEST_CONSTANT
*&---------------------------------------------------------------------*
FORM configure_test_constant .
DATA: l_subrc TYPE sysubrc,
lwa_accepts_creation TYPE ztools_constants_manager=>t_accepts_creation.
lwa_accepts_creation-group = c_const_group.
lwa_accepts_creation-type = ztools_constants_manager=>e_constant_types-field.
CALL METHOD ztools_constants_manager=>configure_constant
EXPORTING
pi_name = c_const_name
pi_accepts_creation = lwa_accepts_creation
IMPORTING
pe_subrc = l_subrc.
IF l_subrc = 0.
MESSAGE 'Constant updated.' TYPE 'S'.
ELSE.
MESSAGE 'Constant not updated.' TYPE 'W'.
ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form START_OF_SELECTION
*&---------------------------------------------------------------------*
FORM start_of_selection .
DATA: l_value TYPE i,
l_total TYPE i.
CALL METHOD ztools_constants_manager=>read_constant
EXPORTING
pi_name = c_const_name
IMPORTING
pe_value = l_value.
l_total = l_value + p_value.
WRITE: / 'Constant value =', l_value.
WRITE: / 'Sum =', l_total.
ENDFORM.
I develop the programs but many times constants value are decided by another team, this team are not developers, i want to make the life of the person who are going to configure them as easy as possible no matter if it’s me or another team. This is why this sample program has a function key in selection screen, this function key must not be shown for final users, but i found it comfortable to visually have an option to configure constants involved in the program, if another developer is working in the program it easily will know which constants are and it would be easy to visualize or change the value.
The function key code is just a call to CONFIGURE_METHOD for the constant i want to configure and the result is:
But as explained before i didn’t build a CONFIGURE_METHOD for SAP ranges which are by far more difficult to directly define in database table as they are an XML document. To solve this problem i usually build a selection screen, i coded a sample program ZTOOLS_CM_R002 you can find in github which source code is:
*&---------------------------------------------------------------------*
*& Report ZTOOLS_CM_R002
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT ZTOOLS_CM_R002.
TABLES: sscrfields.
CONSTANTS: c_const_group TYPE ztools_const_group VALUE 'ZTOOLS_CM_R002',
c_const_name TYPE ztools_const_name VALUE 'TEST_SAP_RANGE_CONSTANT'.
DATA: d_developer TYPE abap_bool.
PARAMETERS: p_value TYPE i.
SELECTION-SCREEN FUNCTION KEY 1.
SELECTION-SCREEN: BEGIN OF SCREEN 9001.
SELECT-OPTIONS: s_valran FOR p_value.
SELECTION-SCREEN: END OF SCREEN 9001.
INITIALIZATION.
PERFORM initialization.
AT SELECTION-SCREEN.
PERFORM at_selection_screen.
START-OF-SELECTION.
PERFORM start_of_selection.
*&---------------------------------------------------------------------*
*& Form INITIALIZATION
*&---------------------------------------------------------------------*
FORM initialization .
* Determine if the user is a developer, constant configuration buttons
* will be shown only for developers.
* For testing purposes all users are devs.
d_developer = abap_true.
IF d_developer = abap_true.
CONCATENATE icon_configuration 'Config. test constant'
INTO sscrfields-functxt_01.
ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form AT_SELECTION_SCREEN
*&---------------------------------------------------------------------*
FORM at_selection_screen .
CASE sy-ucomm.
WHEN 'FC01'.
PERFORM configure_test_constant.
ENDCASE.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form CONFIGURE_TEST_CONSTANT
*&---------------------------------------------------------------------*
FORM configure_test_constant .
CALL METHOD ztools_constants_manager=>read_constant
EXPORTING
pi_name = c_const_name
IMPORTING
pe_value = s_valran[].
CALL SELECTION-SCREEN 9001 STARTING AT 10 10 ENDING AT 100 11.
IF sy-subrc = 0.
CALL METHOD ztools_constants_manager=>write_constant
EXPORTING
pi_name = c_const_name
pi_group = c_const_group
pi_type = ztools_constants_manager=>e_constant_types-sap_range
pi_value = s_valran[].
MESSAGE 'Constant updated.' TYPE 'S'.
ELSE.
MESSAGE 'Constant not updated.' TYPE 'W'.
ENDIF.
ENDFORM.
*&---------------------------------------------------------------------*
*& Form START_OF_SELECTION
*&---------------------------------------------------------------------*
FORM start_of_selection .
DATA: li_value_range TYPE RANGE OF i.
CALL METHOD ztools_constants_manager=>read_constant
EXPORTING
pi_name = c_const_name
IMPORTING
pe_value = li_value_range.
IF p_value IN li_value_range.
WRITE: / 'The value is inside the range'.
ELSE.
WRITE: / 'The value is not inside the range'.
ENDIF.
ENDFORM.
I have a function key for configure the SAP range, but as i don’t have a CONFIGURE_METHOD that works with ranges in the function key code i call a selection screen, before to display the selection screen i read the constant i will be configuring and i’m passing the current value of the constant to screen range variable, if the selection-screen is executed (SY-SUBRC = 0) then i will call the WRITE_CONSTANT method to save the selection screen range variable as constant in the database.
The resulting UI for configuring a range is:
I hope you can find it useful if you have no constant management code in your project or if you have a worse solution to handle constants, every comment with ideas on how to improve the solution or potential problems this solution may have are welcome.
Github repository: https://github.com/jordirosa/ConstantsManager
Regards.
FORMs and global variables...?
Anyway. A few thoughts.
The biggest question I have is "why?". Even using modern ABAP programming constructs instead of CALL METHOD, it doesn't help readability. It doesn't seem to have any advantages over simply coding a constant. OK, I suppose you can change the value... in which case probably better to refer to them as system parameters rather than constants.
So, I'll think of them as system parameters. Why not use one of the tables that SAP provide - TVARV or TVARVC? Or just use PARAMETER IDs?
Finally, if instead of STRING for field VALUE, you use XSTRING, you can put the actual value into the table, with no need to change its type.
Hi,
The reason is obviously it can be changed without having to change the code and trasport the modification to productive system, i thought this is why such kind of tables exists, for constants that are susceptible to be changed.
Why i don't use TVARV or TVARVC? As explained, because they have a limitation, the length. You may think 255 is long enough, i prefer not to have such limitation, i have longer constants, also if i want to save something different than a range i feel TVARV and TVARVC not clean enough, i dont need option, or sign fields, this last point is just a matter of personal preference.
And finally the class gives to me ease of use, expandability, and in some case a better UI to configure my constants (Obviously i code this UI, but with the exception of ranges i code it once), i usually work with constants that have a bit more complex structure than a single field as dictionaries or lists, in my project i have a structure defined for this kind of variables and i have a type in the class for them, and code to read/write and configure this kind of constants in an easier way, this is the why to build a custom class and to use a string, i simply build more comfortable code for the structures i usually use. Can you do the same using tvarv or tvarcv? Sure, but with 255 chars as the field limit.
Thanks to comment.
I can’t think I’ve ever needed a constant that’s more than a few characters long. A constant that can be changed isn’t a constant. A constant that is susceptible to change even more so. You really should refer to what you’re doing as a way of storing system wide parameters. Correct naming matters to avoid confusion.
But again, I can’t really think of any need for +255 character system wide parameter. Possibly file paths I suppose, but they can and should be handled by logical filenames.
I'm with Matthew here, nice effort but "why?" was also my first question. As others noted already, "constants" seems to be a misnomer here as this is more like configuration.
Personally, I'm not in favor of such "one size fits all" solutions. There could be a table with some purely technical values, if anyone wants to build a framework around it - that's fine. Then config / business rules type of information should be in the separate tables. BRF+ also exists for this reason. There are also other options like TVARV etc. for their own purposes. If you need over 255 characters then it's rather SO10 territory.
All in one seems like a great option on the surface but it increases the data loss (actually happened at one company - all "constants" wiped out by accident) and security risks. And you can't take advantage of a buffered table if static and dynamic "constants" are all in one place. Plus it kind of locks you into this legacy solution, which may affect future migrations.
So we are not really talking about constants here, if the values change every so often, directly in production.
I have a table for that sort of thing, as some values are "constant" for Australia but "constant" for Germany with different values, but both with the same semantic meaning. A semantic value in one SAP system may mean "Green Monster" but the actual value is Z123 in Australia and Y345 in Germany. Thus you can move code from one system to another without having to re-do the "constants".
I would say if there is a need to change a value directly in production every so often it is less of a "constant" and more of a "business rule".
For real constants though, like the value of PI, or SAP document types e.g. "C" for sales order I tend to use a constants interface. Some people do not like those at all, and of you cannot have a table - or can you using the source code based approach? They were supposed to be a replacement for TYPE-POOLS.
Fun Fact : Horst Keller once told me if you declare a global constant in a program then all running instances of that program access the exact same piece of memory that the constant lives in as opposed to variables where each instance accesses its local copy.
Cheersy Cheers
Paul
Thanks for sharing.
For the matter of fact, we've once written a (quite complex) tool for central management of parameters. Currently it's available only for internal use.
It supports both fixed and dynamic values (with/without customizing CR) for both single and multiple (range) values.
It includes a developer view (for definition of parameters and maintenance of fixed values) and an "implementer" view (for maintenance of dynamic values).
The developer (maintenance) view looks like this:
The interesting thing about it is that at the end of the day it generates (automatically) a class with constants (for fixed values) and methods (for dynamic values).
By doing so we could achieve two things:
There is also this tool: https://github.com/abapinho/abaK/wiki/abaK-functionalities
I think these kind of predefined values should rather bear the name “configuration” or “customization” instead of constants, as they drive the way how applications work. The same reason SAP created SPRO for.
I also believe that creating a separate piece of storage for every development is an overkill. Why make a Z-table when you only need a value or two in your program?
The question helping me to decide this:
Is the configuration simple enough to be stored in a TVARV-like format (in form of parameters and select-options)?
Hi Jordi. Thanks for sharing. This is the fourth approach on the subject that I see. For my work, however, it often depends on organizational elements. For example, company code and purchasing organization are important. For this reason, there are often independent database tables with some switches ("do something or don't do something") - it doesn't make everything easier. Unfortunately I haven't seen a really good, central solution to date 🙁
Are you telling us you haven't seen SPRO or BRF+? 🙂
SPRO is like an old fruit tree that you haven't cut in many years. But you're right, SPRO is just such a framework. I didn't see the wood for the trees 😉 BRF+ is on my list of things I want to work with. I haven't had the pleasure yet. Good thing you remind me of it.