Application Development 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: 

ABAP OOP constant declaration best practice

ray_mannion
Participant
0 Kudos

We have about a dozen function groups and 30-40 function modules which all need to commonly reference upwards of 100 constants.

We currently do this:

include /namespace/constants

But, the extended code check tells me it is bad practice to have an include used in more than one function group.

We're not going to rewrite all of our code to sit in a single function group, like it proposes.

As we move to object oriented development, we face the same question.

Is it best to put all of the constants into a single class and then reference it in our code like this:

if ls_knvp-parvw = /namespace/cl_constant=>gc_soldto_function

That feels cumbersome, but manageable. Maybe we can alias it or something?

I'd like to use a type group, but we can't put it in a namespace and the usage seems to be deprecated?

Basically, I want something easy to use that can be referenced from multiple classes or function groups. Shorter naming is preferable. Passing the extended syntax check is very important.

Thanks for your suggestions!

1 ACCEPTED SOLUTION

matt
Active Contributor

Having all your constants in one place, no matter whether you're writing something for Finance or for HR, is not good practice. The idea should be to be as specific as possible. Personally, I don't see anything wrong with having e.g.

CONSTANTS c_end_of_time TYPE d VALUE '99991231'

defined multiple times. If I didn't do it in a class, then I'd do it in an interface - but one constants interface per application. Having your constants defined in one or a few different places, used by many applications, to my mind is close to defining a global variable v_count for all your integer needs. I.e. not a good idea.

Group your constants into related groups, define them in interfaces, then use aliases in the class definitions.

27 REPLIES 27

matt
Active Contributor

Having all your constants in one place, no matter whether you're writing something for Finance or for HR, is not good practice. The idea should be to be as specific as possible. Personally, I don't see anything wrong with having e.g.

CONSTANTS c_end_of_time TYPE d VALUE '99991231'

defined multiple times. If I didn't do it in a class, then I'd do it in an interface - but one constants interface per application. Having your constants defined in one or a few different places, used by many applications, to my mind is close to defining a global variable v_count for all your integer needs. I.e. not a good idea.

Group your constants into related groups, define them in interfaces, then use aliases in the class definitions.

raghug
Active Contributor
0 Kudos

I do agree with your statement that having all the constants in one place is a bad idea. But, I don't like the idea of having an interface per application, declaring constants for just that application. At that point you are just moving the program constants to a class (or interface) for no real gain and just another element to deal with.

Reading Horst Keller's blog about enumeration, in that example, the shirt sizes are something that I would like declared in one place for the entire project / dev class / package. First that would be the definition of code reuse. Second, think about refactoring, in his example if a size XS is added, it has to be done in one place only instead of trying to find every place it was declared. Third, if the XS wasn't supposed to be there, you don't want another developer accidentally adding it to just one application.

Personally I like keeping reusable ones in a properly marked globally accessible place for the dev class (as a class or interface) and application specific ones within the program. If my program is primarily class based, then it is an attribute - and if I don't anticipate any one else using it for the same purpose, I bury it in the Private section, so that any future refactoring won't impact inadvertent use in another program.

matt
Active Contributor

I was using the word application deliberately to mean "connected group of programs". If that's your entire project than fine. The point that if you have a program for shirts, and another for coal mining, they shouldn't share the constants interface. Depending on your package regime, it might make sense to have one interface per package. Or it might not. It all depends on the granularity. I'd hate to see a constants interface for, e.g. FI applications.

At some point "reusable" becomes "global" and global is bad!

Burying single use constants in private is what I do also. However, if the class is like an API, and will be used by many other classes, then obviously there will be public constants. And if the class has many subclasses, there will be protected ones as well. 🙂

raghug
Active Contributor
0 Kudos

Thanks for the clarification of "application" - you seem to follow the dictionary meaning 😉 In that case, we are both on the same page.

And really bad, while we are commenting on it - is carrying around an include with every alphabet declared c_a = 'A', c_b = 'B', etc.... I have been in situations where I was forced to toe that line just so that I don't use...

IF my_var = 'X'.
OR
IF my_var = c_sun_is_shining.

they want me to use

IF my_var = c_x.

You've seen the same code as I have. I always say a constant should describe it's meaning and not it's content. And anyway - what's wrong with Abap_True ? 😉

Rich

raghug
Active Contributor
0 Kudos
a constant should describe it's meaning and not it's content.

Thank you, I hope you don't mind me stealing this phrase!

I tend to forgive not using ABAP_TRUE because in past versions of ABAP, it was available only if you explicitly declared the type-pool. I guess that is not an excuse any more!

matt
Active Contributor
0 Kudos

*muttering darkly* it wasn't an excuse then...

🙂

0 Kudos

<chuckles>

Tomas_Buryanek
Active Contributor

You can create instance of your "constant class". And it will shorten code for usage 🙂

Like this:

DATA: lo_cs1 TYPE REF TO /namespace/cl_long_class_name.
CREATE OBJECT lo_cs1.

IF l_variable = lo_cs1=>c_constant.
  "TRUE
ENDIF.
-- Tomas --

0 Kudos

Thank you - that is a good, simple suggestion

matt
Active Contributor

I dislike it. An instantiation without reason. What if the constructor is resource intensive? You're relying on the developer checking/knowing. No - I don't think it is a good idea. It could be used to make the code more readable, but at the expense of meaning.

0 Kudos

How about an interface? You aren't dealing with a constructor then.

DATA: lo_cs1 TYPE REF TO /namespace/if_long_interface_name.
CREATE OBJECT lo_cs1.

... lo_cs1=>constant.

matt
Active Contributor

You can't instantiate an interface. You won't get past the syntax check.

It was intended only for "constant class". But nevertheless I agree. It can be confusing or problem making

-- Tomas --

horst_keller
Product and Topic Expert
Product and Topic Expert

It must be

... lo_cs1->c_constant ...

n'est-ce pas ?


0 Kudos

C'est. 🙂

-- Tomas --

0 Kudos

Sorry, my mistake... what caught me off guard was it did pass syntax check without the instantiation - but that doesn't work either!

horst_keller
Product and Topic Expert
Product and Topic Expert

The ABAP programming guidelines say: put'em to a class or interface. And hey, since 7.51 we have enumerations ...

https://help.sap.com/http.svc/rc/abapdocu_751_index_htm/7.51/en-US/index.htm?file=abendeclaration_dt...

matt
Active Contributor
0 Kudos

oooo - enumerations. Lovely. 😉

raghug
Active Contributor
0 Kudos

I like your blog better https://blogs.sap.com/2016/10/10/abap-news-release-7.51-enumerations/ I guess I didn't dig hard enough on the help site 🙂

nomssi
Active Contributor
0 Kudos

Hello Ray,

as a constant is constant, so you are free to define both a global constant à la /namespace/cl_constant=>gc_soldto_function and a local scope redefinition:

CONSTANTS c_soldto_function TYPE ... VALUE /namespace/cl_constant=>gc_soldto_function.

JNN

raghug
Active Contributor

I think that misses the whole point of having a single place that the constants are declared. In your example you are re-declaring the constant for local use. I have found a slightly better way - so that you are declaring an ALIAS and not actually carrying around new declarations.

INTERFACE const.
  INTERFACES /namespace/if_long_interface_name.
  ALIASES sun FOR /namespace/if_long_interface_name~sun.
  ALIASES moon FOR /namespace/if_long_interface_name~moon.
  ...
ENDINTERFACE.
...
my_variable = const=>sun.
my_variable2 = const=>moon.

I still don't like even this method, because it looses the elegance and you have to determine which (or all) the constants to declare the alias for. If the OP truly has a 100 constants that need to stay together in one class/interface/include (whatever), that is a lot of redeclaring!

matt
Active Contributor
0 Kudos

If a bit of extra effort is made to make the code readable, I don't mind if a developer has to do a lot of redeclaration.

btw - I'd alias as c_sun, c_moon. Here using prefixes to indicate usage, not type.

raghug
Active Contributor
const=>c_sun.

Little redundant, no?

Here using prefixes to indicate usage, not type.

I guess you have the same aversion to Hungarian notation (I just learned about its source yesterday in a Coffee Corner post by Jelena) as I do.

matt
Active Contributor
0 Kudos

With the alias, there's no const=>c_sun - just c_sun

raghug
Active Contributor

Oh, you are talking about the method Jacques Nomssi described! I was talking about using the keyword ALIASES like my example... In that case yes, no argument there.

In my example, I was locally redeclaring the interface and Aliasing the used constants with that local redeclaration. You will have to use the const=> there.

Sandra_Rossi
Active Contributor
0 Kudos

Personally, I like this trick of aliasing constants (eventually using a custom-defined macro like "mac_alias

/namespace/if_long_interface_name : sun, moon") . Of course, I would prefer enumerations from ABAP 7.50.