First-hand knowledge.

Browse the Book

In this chapter, you’ll learn about clean ABAP guidelines for a fundamen- tal building block in your ABAP code: methods. You’ll see how methods work with an object-oriented design and follow best practices for me- thod parameters, readability, and invocation.

“Methods”

Contents

Index

The Authors

Klaus Haeuptle, Florian Hoffmann, Rodrigo Jordão, Michel Martin, Anagha Ravinarayan, Kai Westerholz Clean ABAP: A Style Guide for Developers 351 Pages, 2021, $79.95 ISBN 978-1-4932-2026-7

www.sap-press.com/5190 Chapter 4 Methods

This chapter deals with clean ABAP methods. We’ll walk through key 4 method concepts such as method design, method body, and control flow. We’ll also explore the preferred way to call methods with clean ABAP.

Methods are the ultimate containers of executable code in ABAP Objects. Other types of structures that directly contain code are function modules, programs, and subrou- tines, but as discussed in Chapter 2, Section 2.3, methods are the preferred low-level building blocks for clean ABAP code. Many other chapters in this book describe detailed clean code patterns and recommen- dations for ABAP code within methods. This chapter deals with the design, declaration, and usage of methods; high-level control flow within methods; method body guide- lines; and invoking methods. We’ll start with an in-depth discussion on methods in the context of object-oriented programming in Section 4.1. Then, in Section 4.2, we’ll dive deeply into method parameters and their use before turning, in Section 4.3, to clean code principles to apply to the method body. To finish this chapter, we’ll show you how to call your methods cleanly in Section 4.4.

4.1 Object-Oriented Programming

In this section, we’ll discuss how to make methods work better within an object- oriented design, picking up on our earlier discussion of object-oriented programming in Chapter 3, Section 3.1.

4.1.1 Static and Instance Methods Static methods are methods declared with the CLASS-METHODS keyword and are attached to the class itself, not to instances of the class. To call a static method, you’ll use the class name directly, without needing to create an instance of that class. In this way, static methods are not truly object-oriented. They do not participate in the class inher- itance hierarchy and do not participate in dynamic dispatch (thus, the term “static”). Listing 4.1 shows you how to declare a static method.

95 4Methods 4.1 Object-Oriented Programming

CLASS blog_post DEFINITION Also, the behavior of instance methods can be redefined and more easily mocked in PUBLIC. unit tests. Their data scope is the scope of the class instance, and resources can be con- figured per instance. For these reasons, we recommend using instance methods by PUBLIC SECTION. default, rather than static methods. 4 CLASS-METHODS: Look at the related discussion involving classes in Chapter 3, Section 3.1.2. publish. Methods should be static in the following cases: for static creation methods and for ENDCLASS. utility methods.

Listing 4.1 Static Method Definition Static creation methods are methods that work as specialized constructors (as described earlier in Chapter 3, Section 3.3.3). These methods return an instance of the owning You can call this method using the class name directly, followed by a fat arrow (=>): class or a subclass, as shown in Listing 4.3, where the create_as_copy method serves as a static creation method by creating a copy of the passed in source_blog_post instance. blog_post=>publish( ). CLASS blog_post DEFINITION Since static methods constrain the behavior to a specific implementation, they are not PUBLIC. flexible. Instance methods, meanwhile, are attached to instances of the class. Instance methods PUBLIC SECTION. are declared with the METHODS keyword, as shown in Listing 4.2. CLASS-METHODS: CLASS blog_post DEFINITION create_as_copy PUBLIC. IMPORTING source_blog_post TYPE REF TO blog_post PUBLIC SECTION. RETURNING VALUE(result) TYPE REF TO blog_post. METHODS: publish. ...

ENDCLASS. ENDCLASS.

Listing 4.2 Instance Method Definition Listing 4.3 Static Creation Method Example

To call an instance method, you need an instance of the class, followed by a thin arrow Utility methods are methods that don’t depend on any underlying resources and per- (->): form a static operation that is not reasonably expected to change and does not need DATA my_blog_post TYPE REF TO blog_post. any parameterized behavior. These methods should usually be part of a utility class ... that provides related operations (see Chapter 3, Section 3.1.2). An example of the defini- my_blog_post->publish( ). tion of a utility method is shown in Listing 4.4, where the fahrenheit_to_celsius method performs a simple temperature conversion. This kind of operation does not require any variation and is perfectly fine as a utility method. Consider Using Instance Methods by Default CLASS temperature_conversion DEFINITION The key to the flexibility of instance methods is the fact that they are attached to PUBLIC instances of classes. At runtime, a specific instance could refer to any subclass in the ABSTRACT hierarchy of the declared class variable (including itself), which makes the method call FINAL. “dynamic” or “virtual.”

96 97 4Methods 4.1 Object-Oriented Programming

PUBLIC SECTION. Public Instance Methods Should Be Part of an Interface CLASS-METHODS fahrenheit_to_celsius For a class to serve as a good citizen in an overall design, the class should implement IMPORTING interfaces that define its abstract behavior. Consequently, most, if not all, of its public temperature_in_fahrenheit TYPE temperature instance methods should be part of an interface. 4 RETURNING In this way, the class itself becomes a mere implementation of the concepts repre- VALUE(result) TYPE temperature. sented by the interfaces it implements, and consumers don’t need to depend directly on the class at all. This important step enables the dependency inversion principle, the ... D in SOLID.

ENDCLASS. Not all classes need to implement interfaces. Exception classes, value objects (see Chap- Listing 4.4 Utility Method Example ter 3, Section 3.1.2), and enumeration classes (see Chapter 6, Section 6.2.2), for example, usually don’t need to present an abstraction over their operations and, as such, aren’t Both static and instance methods are implemented with the METHOD … ENDMETHOD con- usually backed by interfaces. In general, classes that represent values or entities that struct in the class implementation area, as shown in Listing 4.5 for the static method only contain data, and not services, won’t implement interfaces. temperature_conversion=>fahrenheit_to_celsius. For more information about interfaces and their advantages, refer to Chapter 3, Section CLASS temperature_conversion IMPLEMENTATION. 3.1.1. Let’s revisit and improve the design of the thermal_switch class presented in Chapter 3, METHOD fahrenheit_to_celsius. Section 3.1.2, specifically in Listing 3.15. The thermal_switch class’s main service is to pro- result = ( temperature_in_fahrenheit - 32)*5/9. ENDMETHOD. tect a wrapped device from overheating. Its methods are trip (to trip the switch and turn the device off) and reset (to reset the switch to a normal state), which were imple- ENDCLASS. mented as direct public instance methods on the class. To make those methods into interface methods and better abstract consumers of a Listing 4.5 Static Method Implementation thermal protector from the specific implementation present in the thermal switch, we can extract the interface thermal_protector, as shown in Listing 4.6.

Don’t Call Static Methods through Instance Variables INTERFACE thermal_protector It is possible to call a static method through an instance of a class. However, a static PUBLIC. method is attached to the class itself, and calling it through an instance is redundant and a potential source of confusion. METHODS: Make the fact that you’re calling a static method clear by always qualifying the method trip call with the class name. FOR EVENT critical_temperature_reached OF thermal_sensor, reset.

4.1.2 Public Instance Methods ENDINTERFACE. Public instance methods in a class effectively define its interface to outside consumers. Listing 4.6 The thermal_protector Interface Anyone with access to the class can call that class’s public instance methods. The thermal_switch class now implements thermal_protector, which results in all its To better manage dependencies and improve isolation, you should decouple from con- public instance methods being backed by interfaces. Listing 4.7 shows its refactored crete classes and focus on the abstraction that the class presents. In this way, replacing PUBLIC SECTION. implementation details with alternative implementations, like mock instances for testing, will be easier.

98 99 4Methods 4.1 Object-Oriented Programming

CLASS thermal_switch DEFINITION Let’s revisit the fan class we introduced in Chapter 3. Now, let’s say we have a new FINAL requirement to create a fan subclass that steps over multiple values when its intensity PUBLIC. is changed. We can redefine the appropriate methods with the desired implementa- tion, as shown in Listing 4.8. PUBLIC SECTION. CLASS step_fan DEFINITION 4 INTERFACES: PUBLIC switchable, FINAL thermal_protector. INHERITING FROM fan.

ALIASES: PUBLIC SECTION. trip FOR thermal_protector~trip, reset FOR thermal_protector~reset. METHODS: constructor METHODS: IMPORTING step TYPE int4, constructor increase_intensity REDEFINITION, IMPORTING decrease_intensity REDEFINITION. managed_device TYPE REF TO switchable sensor TYPE REF TO thermal_sensor. PRIVATE SECTION. ... DATA: Listing 4.7 The Refactored thermal_switch Public Section step TYPE int4.

The resulting Unified Modeling Language (UML) design is shown in Figure 4.1, which ENDCLASS. shows that a thermal_switch is both a thermal_protector and a switchable. CLASS step_fan IMPLEMENTATION.

«interface» «interface» «interface» METHOD constructor. switchable thermal_protector thermal_sensor super->constructor( ). me->step = step. is_on(): bool «handler» trip() «event» is_off(): bool reset() critical_temperature_reached() ENDMETHOD. toggle() METHOD increase_intensity. DO step TIMES. super->increase_intensity( ). ENDDO. managed_device ENDMETHOD. device thermal_switch METHOD decrease_intensity. DO step TIMES. Figure 4.1 The thermal_switch and thermal_protector Design super->decrease_intensity( ). ENDDO. 4.1.3 Method Redefinition ENDMETHOD.

Within a subclass, you can redefine instance methods that are not final and have a spe- ENDCLASS. cialized implementation for the subclass that should be called in lieu of the superclass implementation. Listing 4.8 The step_fan Subclass

100 101 4Methods 4.2 Parameters

The step_fan class shown in Listing 4.8 inherits from fan and redefines the methods Some invocation keywords are optional depending on how the method is declared and increase_intensity and decrease_intensity to execute them in a certain number of called. In this section, we’ll cover guidelines on parameter declarations. Section 4.4 will steps. Note how the methods are declared again with the REDEFINITION keyword. The discuss guidelines for method invocation. redefined methods can then call the corresponding superclass version with the super-> syntax. Note also that the constructor is required to call the superclass constructor as 4 4.2.1 How Many Input Parameters Are Too Many? its first statement. Let’s look at the input parameters for the method declaration shown in Listing 4.9.

Be Careful When Redefining Methods METHODS add_item As explored in Chapter 3, Section 3.1.2, inheritance is a powerful tool that is often hard IMPORTING to get right. product_id TYPE product_id product_group TYPE product_group When you have method redefinitions, some behavior present in the superclass is amount TYPE int4 adjusted to fulfill a new requirement. This adjustment could break clients’ assump- unit_of_measure. tions about the superclass, which violates the Liskov substitution principle, the L in SOLID. Listing 4.9 Too Many Input Parameters? Minimize the number of methods that are redefined. Strive to only implement meth- ods that are abstract in the superclass. This approach makes the design easier to rea- The add_item method shown in Listing 4.9 has many parameters that describe separate son about since each class has only a single version of each method. This kind of concepts, all lumped together as input parameters. Creating new structures or classes hierarchy is called a normalized hierarchy in the book Working Effectively with Legacy for these concepts makes the method clearer and easier to test and improves the over- Code (Prentice Hall, 2004). all design, as shown in Listing 4.10.

METHODS add_item IMPORTING 4.2 Parameters product TYPE REF TO product quantity TYPE quantity. Method parameters fall broadly into three kinds or categories: input, output, and Listing 4.10 Minimized Number of Input Parameters input-output parameters.

Input parameters are declared with the IMPORTING keyword. Output parameters can be Too many input parameters may also be an indication that the method does more than declared as EXPORTING parameters or as a single RETURNING parameter. Input-output one thing. More information on this topic is found in Section 4.3.1. parameters are declared with the CHANGING keyword.

One common source of confusion for novice ABAP developers is that, apart from the Aim for as Few Input Parameters as Possible CHANGING keyword, these keywords have other keywords as counterparts when invoking The number of input parameters for a method can significantly affect how usable and methods, as listed in Table 4.1. understandable the method is to callers, the complexity of its internal implementa- tion, and how hard it is to test it. In general, the less input parameters a method has, Declaration Invocation the easier it is to consume it, understand its operation, and test it. IMPORTING EXPORTING Minimize the number of IMPORTING parameters to your methods. Most methods EXPORTING IMPORTING should have less than three input parameters. Three or more parameters makes the sheer number of possible parameter value combinations harder to use and test. RETURNING RECEIVING

CHANGING CHANGING 4.2.2 Optional Input Parameters Table 4.1 Parameters Declaration and Invocation Counterparts ABAP does not support method overloads, which occur when methods with the same name exist that only differ in their parameters. As a result, optional parameters, which

102 103 4Methods 4.2 Parameters

are parameters marked with the modifier OPTIONAL, have historically been used to con- METHODS to_csv trol different behaviors within methods. IMPORTING separator TYPE string DEFAULT `,` A typical example is a method that processes either a table of items or a single item, as RETURNING shown in Listing 4.11. ... 4 METHODS process Listing 4.13 Parameter with Default Value IMPORTING item_to_process TYPE item OPTIONAL items_to_process TYPE item_table OPTIONAL. 4.2.3 Preferred Input Parameters Listing 4.11 Mutually Exclusive Optional Parameters If all input parameters to a method are optional, either by marking them as OPTIONAL or using a default value, then one of them can be annotated as a PREFERRED PARAMETER, as This kind of method signature is confusing to the caller and harder to implement. What shown in Listing 4.14. is not clear is which parameters are required, which combinations of parameters are METHODS to_csv valid, and which parameters are mutually exclusive. The implementation must check IMPORTING for all valid combinations and fail or branch accordingly. separator TYPE string DEFAULT `,` PREFERRED PARAMETER quote type string DEFAULT `"` Split the Behavior Instead of Adding Optional Parameters RETURNING Different behaviors should be implemented in different methods (see Section 4.3.1). ... Separate methods with properly chosen names and specific parameters for each case Listing 4.14 Method with Preferred Parameter should be created. Using separate methods provides clear guidance for which parame- ter combinations are valid and expected and are easier to implement. When calling a method with a parameter marked as a PREFERRED PARAMETER and provid- ing a single parameter, you don’t need to name the parameter at the call site; the pre- For the example shown in Listing 4.11, separating the functionality results in the meth- ferred parameter will automatically be used. Thus, when calling the to_csv method ods shown in Listing 4.12. defined in Listing 4.14 with a single parameter, that parameter, if not named, will be METHODS: bound to the preferred parameter, for instance, in the following call: DATA(item_as_csv) = item->to_csv( `;` ). process_item IMPORTING Although this style makes the call more concise, which parameter is being supplied item_to_process TYPE item, might not be clear, thus making the code harder to understand. Even if unnecessary, naming the parameter can increase readability, such as in the following code: process_items IMPORTING DATA(item_as_csv) = item->to_csv( separator = `;` ). items_to_process TYPE item_table. If the parameter is not marked as a PREFERRED PARAMETER, the caller will be forced to Listing 4.12 Separate Methods for Separate Functionalities name the parameter when calling it.

Default parameter values, which are accomplished by annotating a parameter with the Use a Preferred Parameter Sparingly DEFAULT modifier and including a default value, should be used to advertise that the parameter is optional for the caller, but not for the method, which will use the default Only use a PREFERRED PARAMETER if the method name and its preferred parameter are clear and easy to understand when the method is being called, especially when omit- value if one is not provided. For an example of a default parameter, look at the to_csv ting the parameter name (see also Section 4.4.4). method in Listing 4.13. The parameter separator is optional and, if not assigned by the caller, will have the value `,` (a comma) by default.

104 105 4Methods 4.2 Parameters

4.2.4 Boolean Input Parameters METHOD calculate_credit_score. Imagine you have a credit score service class that provides a method for calculating the IF use_strong_heuristics = abap_true. credit score of a customer. The definition of this class is shown in Listing 4.15, where the " use a slower but more robust algorithm.... calculate_credit_score method uses a Boolean parameter to control whether to use strong heuristics in the calculation. 4 ELSE. CLASS credit_score_service DEFINITION " use a faster but less robust algorithm.... PUBLIC FINAL. ENDIF.

PUBLIC SECTION. ENDMETHOD.

Listing 4.16 Branching Implementation METHODS:

constructor When a method takes a Boolean input parameter, usually the method does two things IMPORTING customer TYPE REF TO customer, instead of one (see also Section 4.3.1).

calculate_credit_score Create Separate Methods Instead of Using Boolean Parameters IMPORTING use_strong_heuristics TYPE abap_bool Using Boolean parameters to control decisions and branching inside of a method’s RETURNING VALUE(credit_score) TYPE int4. body makes the method more complex and harder to use and maintain. PRIVATE SECTION. Different behaviors should be implemented in different methods with properly chosen names. DATA: customer TYPE REF TO customer. In our example, the calculate_credit_score method should be broken up into two methods, each focused on a different algorithm, as shown in Listing 4.17. ENDCLASS. METHODS: Listing 4.15 Credit Score Service with a Method with a Boolean Parameter

calculate_simple_credit_score The calculate_credit_score method can be called in the following way: RETURNING VALUE(credit_score) TYPE int4, DATA(my_credit_score) = my_credit_score_service->calculate_credit_score( abap_true ). calculate_complex_credit_score RETURNING VALUE(credit_score) TYPE int4. In this code, what that Boolean parameter means in the call is not clear. You can allevi- ate this problem by naming the parameter (see Section 4.4.4), as in the following code: Listing 4.17 Separate Methods Instead of a Branching Method

DATA(my_credit_score) = In this way, not only is implementing each method individually easier, consuming my_credit_score_service->calculate_credit_score( those methods separately is also easier. If needed, common code within the original use_strong_heuristics = abap_true ). method could be refactored into supporting private methods.

This version improves things a bit even though the burden is on the client to use this You can even go a step further and create separate classes for each scenario. For our style. Moreover, an issue with the semantics of the method still exists. credit score service, we could have an interface with a simple calculate_credit_score method with a separate class implementing each algorithm. Thus, even the decision of It’s not hard to imagine that the implementation of calculate_credit_score will look which algorithm to use is lifted from client code. The client code itself would only something like the code shown in Listing 4.16. depend on the interface and its simpler method.

106 107 4Methods 4.2 Parameters

4.2.5 EXPORTING Parameters If the output parameters of your method do not form a logical entity, split the method Results that a method provides to the caller can be declared either as EXPORTING param- into several focused methods. If they do form a logical entity, group parameters into a eters or a single RETURNING parameter. more cohesive structure or a class and use this structure to minimize the number of EXPORTING parameters. EXPORTING parameters allow you to define multiple outputs from a method, as shown in 4 Listing 4.18. For the check_business_partners method, the output parameters form a logical entity, METHODS check_business_partners a check result, which could be made explicit as a check_result structure. Then, the IMPORTING check_result structure can be used to type the now single EXPORTING parameter of the business_partners TYPE business_partners method, as shown in Listing 4.20. EXPORTING result TYPE result_type TYPES: failed_keys TYPE /bobf/t_frw_key BEGIN OF check_result, messages TYPE /bobf/t_frw_message. result TYPE result_type, failed_keys TYPE /bobf/t_frw_key, Listing 4.18 Multiple EXPORTING Parameters messages TYPE /bobf/t_frw_message, END OF check_result. The check_business_partners method can validate a list of business partners provided in the input parameter business_partners. The outcome of this validation is returned METHODS check_business_partners in three output parameters: result is the overall status of the validation, failed_keys is IMPORTING a table of the business partner keys that failed validation, and messages is a list of mes- business_partners TYPE business_partners sages generated as part of the validation. EXPORTING EXPORTING parameters are optional for the caller, so when calling check_business_part- result TYPE check_result. ners, you can capture the output parameters that you’re interested in, as shown in List- Listing 4.20 Minimizing EXPORTING Parameters ing 4.19. check_business_partners( Note that this approach is still not the cleanest way to declare check_business_partners, EXPORTING which we’ll explore next. business_partners = my_business_partners IMPORTING 4.2.6 RETURNING Parameters result = DATA(business_partners_check_result) messages = DATA(business_partner_messages) ). RETURNING parameters allow you to declare a single RETURNING parameter for a method, which can be thought of as the result of the method call. Listing 4.19 Invoking a Method with EXPORTING Parameters The last iteration of our check_business_partners method shown in Listing 4.20 ended Note how you need to provide the counterpart keywords to the declaration of IMPORTING up with a single EXPORTING parameter. Calling that method is shown in Listing 4.21. and EXPORTING parameters, which flips them to EXPORTING and IMPORTING, respectively. check_business_partners( EXPORTING Minimize the Number of EXPORTING Parameters business_partners = my_business_partners The presence of many EXPORTING parameters is an indication that your method might IMPORTING be doing more than one thing, which makes the method harder to implement and result = DATA(business_partners_check_result) ). harder to consume. A good method does one thing (Section 4.3.1), and that sharp focus Listing 4.21 Calling a Method with a Single EXPORTING Parameter should be reflected by the outputs of the method as well.

108 109 4Methods 4.2 Parameters

Therefore, we recommend simply calling the RETURNING parameter result or some- Prefer RETURNING to EXPORTING thing similar. What your methods are returning will be obvious and at the same time As you minimize the number of EXPORTING parameters, when you end up with a single invisible, almost like a keyword of the language itself. EXPORTING parameter, make this parameter a RETURNING parameter. Use a meaningful name for the RETURNING parameter only if what it stands for is not A RETURNING parameter is a more conventional way to declare an output parameter. obvious, for example, in methods that return me for method chaining or in methods 4 This kind of parameter makes calls to the method shorter and allows for method chain- that create an entity but don’t return the created entity, only its key. ing (when you chain a method call to the result of another method call without assign- ing the return value to any intermediate variable). Some performance recommendations advise using EXPORTING parameters passed by 4.2.7 CHANGING Parameters reference for large tables of data (described in more detail in Section 4.2.8). However, You can use CHANGING parameters when a value is both an input and an output to a using RETURNING parameters for these cases is usually acceptable. If you have proof of method. In this case, the method can change a component of the parameter as part of poor performance and of a tangible benefit, you can resort to the more cumbersome its operation. This approach only makes sense for structures and internal tables, which procedural style that comes with using EXPORTING. As usual with performance issues, are values with internal components. A structure has fields that can be changed, while measure and adjust accordingly. an internal table has rows that can be changed.

Listing 4.22 shows the final refactoring of the definition of the check_business_partners For example, let’s say you have many entities that need to be validated, and you want method, in which the EXPORTING parameter is changed to a RETURNING parameter. to collect all their validation messages in a single message table. You can use the exam- ple method shown in Listing 4.23 in your entity classes. METHODS check_business_partners IMPORTING METHODS validate business_partners TYPE string CHANGING RETURNING messages TYPE message_table. VALUE(result) TYPE check_result. Listing 4.23 CHANGING Parameter Declaration Listing 4.22 RETURNING Parameter Declaration This instance method will validate the current entity and append any generated valida- Calls to check_business_partners are much cleaner, as in the following code: tion messages to the collecting parameter messages, which is an internal table of mes- sages. The messages parameter could already contain messages (perhaps added earlier DATA(business_partners_check_result) = by other validation methods), and as a result, by using the same variable in a number check_business_partners( my_business_partners ). of validate calls, all the generated messages will be collected in the parameter, as shown in Listing 4.24. Consider Using result as the Name of RETURNING Parameters The ability to name a RETURNING parameter is not a common capability in many main- Use CHANGING Parameters Sparingly stream programming languages. In those languages, a method simply returns the out- CHANGING parameters should be reserved for cases where an existing structure or inter- put with a special statement, for example, return 42. nal table that is potentially already filled with data is changed, like messages in the val- Good method names obviate the need to name the RETURNING parameter. The RETURN- idate method example. ING parameter name would do little more than parrot the method name or repeat Use input parameters for object references that you work with, since your method can something obvious, perhaps even create conflict with other members of the class. still call instance methods on the parameter to change its internal state. Consumers also rarely refer to the RETURNING parameter name when invoking your If you fill up or replace the parameter completely (i.e., you assign a new value to the method. They either assign the result of the method to a variable, use it as part of a parameter), an EXPORTING parameter or a RETURNING parameter is more appropriate. larger expression, or ignore the result altogether.

110 111 4Methods 4.2 Parameters

DATA messages TYPE message_table. ABAP has important optimizations for value copy semantics. When a value is assigned LOOP AT entities INTO DATA(entity). to another variable or parameter, a copy is only made when needed, usually when entity->validate( CHANGING messages = messages ). changing something in the copy. This approach is commonly referred to as copy-on- ENDLOOP. write optimization. Listing 4.24 CHANGING Parameter Usage Pass-by-reference is when a reference to the original value is passed to the method. If 4 the method can reassign the value, the calling method will also be impacted by the To eliminate the CHANGING parameter of the validate method, you can introduce a class change. that represents a message container, which will collect messages and also provide Pass-by-reference is the default for IMPORTING, EXPORTING, and CHANGING parameters. many more convenient methods for a list of messages. As an example, look at the mes- Pass-by-value is the only accepted option for RETURNING parameters. As a result, you’ll sage_container class in Listing 3.16, discussed in Chapter 3, Section 3.1.3. always see the VALUE modifier in RETURNING parameters. This modifier can also be used The refactored validate method should look like Listing 4.25. for other parameter categories to make them pass-by-value. METHODS validate Although rarely used, the syntax for pass-by-reference can also be made explicit with IMPORTING the REFERENCE modifier. For example, the code shown earlier in Listing 4.10 can be message_container TYPE ref to message_container. rewritten into the code shown in Listing 4.27.

Listing 4.25 Refactored CHANGING Parameter to IMPORTING Reference METHODS add_item IMPORTING This version is also easier to consume since the method now doesn’t have a CHANGING REFERENCE(product) TYPE REF TO product parameter, as in Listing 4.26. REFERENCE(quantity) TYPE quantity.

DATA(message_container) = NEW message_container( ). Listing 4.27 Explicit Pass-by-Reference Syntax LOOP AT entities INTO DATA(entity). entity->validate( message_container ). ENDLOOP. Do Not Reassign IMPORTING Parameters Passed by Value

Listing 4.26 Using the Refactored Method Whenever an input parameter is passed by reference, which is the default, the parame- ter cannot be reassigned inside the method. A pass-by-value IMPORTING parameter can be reassigned within the method. But, since Avoid Using More Than One Kind of Output Parameter this parameter is a copy, its new value will not be visible to the caller. Avoid combining EXPORTING, CHANGING, and RETURNING parameters in the same method. This approach is a poor practice that you should avoid. IMPORTING parameters are Different kinds of output parameters indicate that the method might do more than meant to be inputs to a method, and reassigning them doesn’t make sense. Use proper one thing, which is confusing to readers and makes calling the method needlessly com- local variables instead if you need to use the input as a starting value for a computa- plicated. tion and then update the local variables instead. Use a pass-by-reference input param- eter if you don’t need the parameter to be pass-by-value.

4.2.8 Pass-by-Value and Pass-by-Reference To make the quantity parameter shown in Listing 4.27 pass-by-value, you can end up Apart from the input or output category of parameters, you can also declare parame- with the declaration shown in Listing 4.28. ters to be pass-by-value or pass-by-reference. METHODS add_item Pass-by-value is when a copy of the parameter value is made before calling the method, IMPORTING and the method parameter is assigned to that copy. Note that, when you pass an object REFERENCE(product) TYPE REF TO product reference by value, a copy of the reference is made, which is just a pointer that points to VALUE(quantity) TYPE quantity. the same object in memory. Listing 4.28 Pass-by-Value Input Parameter

112 113 4Methods 4.3 Method Body

... Mind the Semantics of EXPORTING Parameters, Prefer Pass-By-Value Parameters passed by reference ultimately point to existing memory areas that may ENDMETHOD. have already been filled. EXPORTING parameters that are passed by reference will retain Listing 4.30 Initializing EXPORTING Parameters their original value before the method was called. This makes them work like CHANGING 4 parameters (Section 4.2.7). If you change the EXPORTING parameters to pass-by-value, as shown in Listing 4.31, the To make an EXPORTING parameter passed by reference behave like a true output param- parameters will be initial by default when entering the method, and there’ll be no need eter, it’s important to actually assign a value to it. It might make sense to clear the to clear or assign them to their initial value. value at the beginning of the method if the parameter could end up unassigned, per- haps because of the method logic or an exception that is raised early on. METHODS try_parse_int IMPORTING Another option is to make the EXPORTING parameter into a pass-by-value parameter, text TYPE string which will make it behave like a RETURNING parameter. EXPORTING parameters that are EXPORTING passed by value are handed over as new, separate memory areas that are empty. VALUE(success) TYPE abap_bool There’s no need to preemptively clear them, just like there’s no need to clear RETURNING VALUE(result) TYPE int4. parameters. Therefore, prefer pass-by-value EXPORTING parameters. Listing 4.31 Pass-by-Value EXPORTING Parameters Pass-by-reference EXPORTING parameters should be used when there’s a measurable Another advantage of EXPORTING parameters that are pass-by-value is that they prevent performance hit when using pass-by-value. One such case is when you process large a situation where the same variable could be assigned to an input and an output parame- internal tables in batches. You can reuse an existing memory area repeatedly so as not ter by the caller at the same time, and the method could clear the IMPORTING parameter to incur the cost of allocation for each batch. Cases like these should be rare. Aim for value indirectly by clearing the output EXPORTING parameter before doing its work. clarity and correctness first and improve the performance only when it becomes an issue. CHANGING Parameters Passed by Value Don’t Make Sense As an example of EXPORTING parameters, look at the declaration of the try_parse_int CHANGING parameters are both inputs and outputs to a method. Even though you can method in Listing 4.29. make a CHANGING parameter a pass-by-value parameter with the VALUE modifier, doing so does not change the way the CHANGING parameter works and generally does not make METHODS try_parse_int sense. Leave CHANGING parameters with their default pass-by-reference semantics. IMPORTING text TYPE string EXPORTING success TYPE abap_bool 4.3 Method Body result TYPE int4. Code is more often read than it is written, and thus the code within a method should be Listing 4.29 Method with EXPORTING Parameters optimized for reading. Not only will the method be easier to read, it will also be easier to consume, change, adapt, and test. You’ll find reasoning about the method easier and To make sure that the pass-by-reference EXPORTING parameters to try_parse_int are ini- will spot defects more quickly. In this section, we’ll explore some important guidelines tialized before the method returns, the method body starts by setting and clearing the to ensure the code within your methods is clear, understandable, and flexible. parameters, as shown in Listing 4.30.

METHOD try_parse_int. 4.3.1 Do One Thing

success = abap_false. To be easier to read, test, and maintain, a method should not only have a single respon- clear result. sibility, but it should perform that responsibility in the simplest way possible. A method should do one thing, and only one thing.

114 115 4Methods 4.3 Method Body

Many clean ABAP rules we discuss in this book help make your methods more focused log_line( line ). and closer to the goal of doing only one thing. A method probably only does one thing ENDLOOP. if it follows the following rules: " move to the previous exception ½ It has a small number of input parameters. current_exception = current_exception->previous. ½ 4 It doesn’t include Boolean parameters. IF current_exception IS BOUND. ½ It has exactly one output parameter. log_line( `---- Exception has previous exception` ). ½ It only throws one type of exception. ENDIF. ENDWHILE. ½ It is small. ENDMETHOD. ½ It stays at a single level of abstraction. Listing 4.33 log_exception First Implementation ½ You cannot extract other meaningful methods. ½ You cannot meaningfully group its statements into sections. The supporting log_line method logs a single line of text to the log file, and the split_ Let’s start by looking at the definition of a method for logging exceptions, as shown in text_into_lines method splits a long text into multiple lines using a fixed number of Listing 4.32. columns for each line. This method returns a table of strings representing the lines. Even though the log_exception method has a single responsibility, many steps are METHODS needed to perform its tasks, for instance, the following: log_exception IMPORTING 1. Store the exception in a local variable. exception_instance TYPE REF TO cx_root. 2. Start a loop while the exception is bound (not null). Listing 4.32 Definition of a Method to Log Exceptions 3. Get the class name of the exception. 4. Log a header including the class name. The log_exception method will be used by some batch processing code whenever the 5. Split the exception text into lines. batch processing program encounters an exception. The code will call log_exception to 6. Loop and log each line. write information about the exception_instance to a log file and then abort the batch process. Log files only accept a maximum number of characters per line. A user can 7. Move to the previous exception. later read these logs and get more information about the exception to determine what 8. Repeat the first loop. went wrong with the processing. These steps hint at many things that the method does: It loops to log the previous Our first implementation of the log_exception method is shown in Listing 4.33. exception, queries the exception class name, and splits the exception text into lines. METHOD log_exception. The next section will discuss a clean ABAP rule that improves the log_exception DATA(current_exception) = exception_instance. method until the method finally does only one thing in as few steps as possible. WHILE current_exception IS BOUND. " log a header with the exception class name 4.3.2 Descend One Level of Abstraction DATA(class_name) = cl_abap_classdescr=>get_class_name( current_exception ). A method should tell a story that’s easy to follow and understand. Its body should stay log_line( at the same level of abstraction, which is just below the responsibility denoted by its |---- Exception occurred: { class_name }| ). name. If more details of the story are needed, you can delve into the methods called by the " split the exception text into lines and log them first method until one of two things happen. Either you’ll reach basic statements of the DATA(exception_text) = current_exception->get_text( ). language that implement some low-level algorithm, or you’ll reach a method call that DATA(lines) = split_text_into_lines( exception_text ). belongs to an interface. LOOP AT lines into data(line).

116 117 4Methods 4.3 Method Body

Either way, you should have a complete understanding of how a part of your code does and splitting the exception text into lines is at a level of abstraction below the level its work and whether the code coordinates with other dependencies. For more infor- we’re interested in. We’re talking about details we’re not ready to delve into just yet. mation on class design and the crucial role of interfaces, check out Chapter 3. Taking a step back and thinking about what the method should accomplish, we might That’s the beauty of well-crafted abstractions. The design is decoupled enough that you come up with the following steps, which are at the same level of abstraction: 4 only need to understand the parts of the system that you currently require. You won’t 1. Log a header for the exception. need to read the whole codebase to understand what a certain part of the system does. 2. Log a body for the exception. 3. Log the previous exception, if any. Descend One Level of Abstraction Statements in a method should be one level of abstraction below the method name This series of steps will translate into the final methods shown in Listing 4.34. itself. All these statements should be on the same level of abstraction. METHOD log_exception. This rule is called the “Stepdown Rule” in the book Clean Code: A Handbook of Agile log_exception_header( exception_instance ). Software Craftsmanship (Pearson, 2008) and called the “Single Level of Abstraction log_exception_body( exception_instance ). Principle (SLAP)” in the book The Productive Programmer (O’Reilly, 2008). The concept log_previous_exception( exception_instance->previous ). probably first appeared in the book Best Practice Patterns (Prentice Hall, ENDMETHOD. 1996), where it was called the “Composed Method Pattern.” METHOD log_exception_header. DATA(class_name) = How can you keep a method focused on a single level of abstraction? One approach is cl_abap_classdescr=>get_class_name( exception_instance ). to explain what the method does in a few sentences or steps, which should all be log_text( related to its goal. These steps should not go into more detail than is needed to under- |---- Exception occurred: { class_name }| ). stand the responsibility of the method. The steps then should become the downstream ENDMETHOD. methods the method calls or the statements it executes. METHOD log_exception_body. DATA(exception_text) = exception_instance->get_text( ). Extract Method Refactoring log_text( exception_text ). The extract method refactoring is a fundamental refactoring approach presented in ENDMETHOD. the book Refactoring: Improving the Design of Existing Code (Addison-Wesley, 1999). METHOD log_previous_exception. You extract cohesive parts of a method into new methods, which are then called by the CHECK exception_instance IS BOUND. original method in the place from which the functionality was extracted. log_text( `---- Exception has previous exception` ). This refactoring is supported by ABAP Development Tools (ADT). Select the section of a log_exception( exception_instance ). method you want to extract and press (Alt)+(Shift)+(M) on Windows or ENDMETHOD. (Cmd)+(Alt)+(M) on macOS to start the extract method refactoring wizard. METHOD log_text. DATA(lines) = split_text_into_lines( text ). The log_exception method shown previously in Listing 4.33 is divided into sections of log_lines( lines ). statements with separate responsibilities, delimited by clarifying comments. The sec- ENDMETHOD. tion comments in the method describe the following steps: 1. Log a header with the exception class name. METHOD log_lines. LOOP AT lines INTO DATA(line). 2. Split the exception text into lines and log them. log_line( line ). 3. Move to the previous exception (and repeat). ENDLOOP. ENDMETHOD. Not all these sections are at the same level of abstraction. We want to know at a high- level what it means to log an exception. Details about getting the exception class name Listing 4.34 Each Method at a Single Level of Abstraction

118 119 4Methods 4.3 Method Body

These methods are now each at the same level of abstraction and one level below the clsdeferrd TYPE vseocdefer, responsibility implied by their names. intdeferrd TYPE vseoidefer, new_clskey_save TYPE seoclskey. Apart from making your methods simple and easy to understand, breaking down methods in this way might unearth interesting possibilities in the design. Whole new Listing 4.35 Too Many Data Declarations: A Prelude to a Huge Method classes and subfeatures that were tangled up in the code may come to light and provide 4 you with an enriched vocabulary for your project. Your design becomes less coupled, more cohesive, and much cleaner. Keep Methods Small You can start thinking about logging the exception body, not just logging the excep- How small a method should be can’t be easily quantified. Methods should be as small tion text. This approach might mean, later on, that you’ll also include the exception as possible, but not smaller. stack trace with the text. You might start to think how to separate the formatting from As a rule of thumb, methods should have less than 20 statements, but optimally 5 the logging, and a whole new exception_formatter class or interface, with its own set of statements or less. Note that we’re measuring in statements, not lines of code. responsibilities, might emerge. Using the rules in this chapter, like the single level of abstraction principle, and extract- ing meaningful methods to create new, smaller methods will get you closer to this goal. 4.3.3 Keep Methods Small

ABAP is a notoriously verbose language. Coupled with a ton of legacy code, you may Look at the original log_exception method shown earlier in Listing 4.33. You might find gargantuan methods or function modules spanning thousands of lines of code. have thought this method was reasonably sized. However, as shown earlier in Listing These sprawling methods are hard to understand, never mind debug and change. 4.34, still many cohesive parts could be made into simpler methods. The resulting When you’re confronted with a data declaration section as big as the code shown in methods were much smaller than the original and much cleaner. The resulting log_ Listing 4.35, you already know this method does way more than one thing. exception method reads like the steps it implements. You can read it and understand DATA: what it does at a high-level quickly without even delving into the other methods. class TYPE vseoclass, Now, look at the log_exception_body method, shown in Listing 4.36. attributes TYPE seoo_attributes_r, methods TYPE seoo_methods_r, METHOD log_exception_body. events TYPE seoo_events_r, DATA(exception_text) = exception_instance->get_text( ). types TYPE seoo_types_r, log_text( exception_text ). aliases TYPE seoo_aliases_r, ENDMETHOD. implementings TYPE seor_implementings_r, Listing 4.36 The log_exception_body Method inheritance TYPE vseoextend, friendships TYPE seof_friendships_r, You might think you can still extract another method from it, resulting in the code typepusages TYPE seot_typepusages_r, shown in Listing 4.37. clsdeferrds TYPE seot_clsdeferrds_r, intdeferrds TYPE seot_intdeferrds_r, METHOD log_exception_body. attribute TYPE vseoattrib, log_exception_text( exception_instance ). method TYPE vseomethod, ENDMETHOD. event TYPE vseoevent, type TYPE vseotype, METHOD log_exception_text. alias TYPE seoaliases, DATA(exception_text) = exception_instance->get_text( ). implementing TYPE vseoimplem, log_text( exception_text ). friendship TYPE seofriends, ENDMETHOD. typepusage TYPE vseotypep, Listing 4.37 The Extracted log_exception_text Method Is Redundant

120 121 4Methods 4.3 Method Body

A new log_exception_text method could have a place, perhaps if log_exception_body The step_fan constructor first calls the superclass constructor and then validates its did more than just log the exception text. At this point, however, the new method is input parameter and raises an exception right away if it’s invalid. It’s important to add simply a reiteration of the old one and doesn’t add much semantic value over the exist- as much information to the exception as possible. In this case, the custom invalid_ ing method. argument_exception includes the argument name and the invalid argument value. Stop extracting methods when you feel comfortable that the method expresses its 4 intent clearly and simply through its statements. Focus on the Happy Path or Error Handling A method body should emphasize the happy path it’s built for. If it needs to perform error handling, it’s important that this error handling code doesn’t divert attention 4.3.4 Fail Fast from the main intent of the method. If it does, put the error handling code in a dedi- Often, when an error occurs or an exception is thrown, the root cause of the problem cated method. For more information on this topic, refer to Chapter 11. can be traced to some parameter having an invalid value introduced earlier in the pro- gram flow. The closer that exception is to the place the error was introduced, the easier As it stands, the step_fan constructor error handling code dominates its logic. It makes the error is to find and fix. sense to break it down so that it’s more readable, as shown in Listing 4.39.

METHOD constructor. Fail Fast super->constructor( ). Document and check the input parameters to your methods and fail with an exception validate_step( step ). as early as possible if they are not valid for the execution of the method. me->step = step. This recommendation is especially important for public and protected methods. Pri- ENDMETHOD. vate methods could also benefit from validation (or using ASSERT) should the program and the assumptions that they make change, but usually you can rely on the validation METHOD validate_step. already performed by the methods that call them. IF step < 1 OR step > max_intensity. RAISE EXCEPTION NEW invalid_argument_exception( Validating later is not only hard to spot and understand but might waste important argument_name = `step` resources. Not validating might make your code fail in hard-to-predict ways and might argument_value = step ). result in invalid data and undesirable behaviors. ENDIF. ENDMETHOD. The step_fan class, shown earlier in Listing 4.8, is not validating its step input parame- Listing 4.39 Separate Error Handling Method ter to the constructor. This value is used to step over a fixed amount when changing the fan intensity. A negative value or zero wouldn’t work, and a value that’s bigger than Note that this kind of validation is meant to aid other developers fix their calling code, the maximum intensity wouldn’t make sense. The code should validate this value and and not for end users, since this validation is very technical in nature. End users could fail at the earliest possible spot, which is on construction, as shown in Listing 4.38. get business-relevant validation errors in the form of messages that are presented to METHOD constructor. them. Earlier in Section 4.2.7, Listing 4.26, we presented the code to validate a list of super->constructor( ). entities. If this is part of a larger method that does some processing with the entities, IF step < 1 OR step > max_intensity. failing early might mean failing if any of those validations generated an error message. RAISE EXCEPTION NEW invalid_argument_exception( Adding in some refactoring, we might end up with the code shown in Listing 4.40. argument_name = `step` DATA(message_container) = NEW message_container( ). argument_value = step ). validate_entities( message_container ). ENDIF. message_container->raise_if_in_error( ). me->step = step. ENDMETHOD. ... Listing 4.38 Constructor Validation Listing 4.40 Raising When a Message Container Has Error Messages

122 123 4Methods 4.4 Calling Methods

In this case, the message_container class has a method that raises an exception if it con- This step adds another indentation level, which might break the visual flow of the code. tains any error messages. Validation messages are added to the exception, which could However, how you or your team feel about using CHECK statements is up to you. Com- be caught by an upper layer and then shown to end users in a suitable manner. For munity discussion might suggest that the statement is so unclear that few people will example, they could be OData error messages that are then displayed in a message pop- understand its intended behavior. over in an SAPUI5 application. No matter what you choose, you should not use CHECK outside of the initialization sec- 4 tion of a method. The statement behaves differently in different positions and may 4.3.5 CHECK versus RETURN lead to unclear, unexpected effects. Another type of validation is when you simply return early if the arguments to a For example, a CHECK statement inside a LOOP ends the current iteration of the loop and method don’t meet its expectations. In these cases, it’s fine for the method to simply proceeds to the next iteration. In this context, a reader might mistakenly expect the return instead of raising an exception. CHECK statement to end the method or exit the loop. In this case, we recommend using an IF statement in combination with CONTINUE instead, since CONTINUE can only be used Earlier in Listing 4.34, you saw an example of this “return early” behavior for the inside loops. method log_previous_exception. If the exception_instance parameter is not bound (which means that the value is null), the method will return early without completing its work. 4.4 Calling Methods Another method that would benefit from this kind of validation is the main log_excep- tion method itself. If the exception instance is not bound, the method simply returns At this point, we’ve explored many aspects of calling a method in ABAP, from calling without doing any work, as shown in Listing 4.41. static methods, where you’ll specify the class name using a fat arrow (=>), to calling instance methods, where’ll you need a reference to an instance of the class and use the METHOD log_exception. thin arrow syntax (->). CHECK exception_instance IS BOUND. log_exception_header( exception_instance ). Interface methods can be called the same way as class methods if you have a reference log_exception_body( exception_instance ). pointing to the interface type. If, however, you have a reference to a class and want to log_previous_exception( exception_instance->previous ). call an interface method on it, you need to add the interface name and a tilde (~) to the ENDMETHOD. start of the method call. For example, if you have an instance of a thermal_switch (shown earlier in Listing 4.7) in the my_thermal_switch variable, you can call its interface Listing 4.41 Check If the Exception Instance Is Bound method switchable~is_on in the following way:

Both methods now use the CHECK statement. This statement reads perfectly fine but is DATA(is_on) = my_thermal_switch->switchable~is_on( ). not a common statement and might cause some confusion. What happens when the check condition evaluates to false might not be clear. The class can also alias the interface method to make the call look like a normal class instance method call. An example of an aliased interface method and its usage can be Another way to implement this kind of validation is to use a condition check followed found in Chapter 3, Section 3.1.2. by a RETURN statement, as shown in Listing 4.42. With regard to how parameters are passed to methods, many options are available, METHOD log_exception. depending on how the method is declared. In this section, we’ll explore some guide- IF exception_instance IS NOT BOUND. lines to make your method invocations clearer and more readable. RETURN. ENDIF. log_exception_header( exception_instance ). 4.4.1 Passing Input Parameters log_exception_body( exception_instance ). Listing 4.43 shows a possible declaration of the method split_text_into_lines, which log_previous_exception( exception_instance->previous ). we used earlier in Listing 4.33. ENDMETHOD.

Listing 4.42 Return If the Exception Instance Is Not Bound

124 125 4Methods 4.4 Calling Methods

METHODS: split_text_into_lines( split_text_into_lines EXPORTING IMPORTING text = text text TYPE string columns_per_line = 80 columns_per_line TYPE int4 DEFAULT 40 RECEIVING 4 RETURNING result = DATA(lines) ). VALUE(lines) TYPE string_table. Listing 4.46 Using the RECEIVING Keyword Listing 4.43 split_text_into_lines Declaration

When only providing input parameters to a method and assigning its RETURNING param- Omit the RECEIVING Keyword eter to a variable, you can simply call the method, as shown in Listing 4.44. The call style using the RECEIVING keyword is unnecessarily verbose and forces you to specify the EXPORTING keyword for input parameters. DATA(lines) = split_text_into_lines( To make the code more readable, omit the RECEIVING keyword and capture the return text = text value of the method directly. columns_per_line = 80 ). The EXPORTING parameters from a method are captured by using the IMPORTING keyword Listing 4.44 Calling a Method with Input Parameters and a RETURNING Parameter in a call. You’ve already seen an example of a call like this earlier in Listing 4.19. Another You can also explicitly annotate the parameter category before the parameter list. In example is shown in Listing 4.47, which calls the try_parse_int method declared earlier the case of IMPORTING parameters, the caller must use the counterpart keyword EXPORT- in Listing 4.29. ING (Section 4.2.5), as shown in Listing 4.45. try_parse_int( DATA(lines) = EXPORTING split_text_into_lines( text = `42` EXPORTING IMPORTING text = text success = DATA(parse_succeeded) columns_per_line = 80 ). result = DATA(parsed_int) ).

Listing 4.45 Explicitly Using EXPORTING Listing 4.47 Capturing EXPORTING Parameters with the IMPORTING Keyword

Any time an EXPORTING or CHANGING parameter is used, you must declare the parameter Omit the Optional EXPORTING Keyword category with the proper keyword in the method call. As described earlier in Section 4.2, EXPORTING parameters are called with the IMPORTING keyword, and CHANGING parameters When all you have are input parameters and possibly a returning parameter, the are called with the CHANGING keyword, as shown earlier in Listing 4.24. This rule also EXPORTING keyword is optional in a method call. forces you to explicitly define the keyword EXPORTING for IMPORTING parameters. However, this style is unnecessarily verbose and redundant. Omit the optional EXPORT- ING keyword in these cases. 4.4.3 The CALL METHOD Construct Another way to call a method in ABAP is to use a style reminiscent of the way function 4.4.2 Capturing Output Parameters modules are called, with the CALL METHOD construct, as shown in Listing 4.48. RETURNING parameters can be simply assigned as a value coming out of the method call This call style doesn’t use parentheses around the parameters. With this approach, you itself, as we’ve seen in Listing 4.44. are forced to declare all keywords for capturing parameters, including the RECEIVING A RETURNING parameter from a method can also be captured alongside the parameter keyword for a RETURNING parameter. list by using the RECEIVING keyword on a method call, as shown in Listing 4.46.

126 127 4Methods 4.4 Calling Methods

CALL METHOD split_text_into_lines EXPORTING Use the Optional Parameter Name If It Adds Clarity text = text Make the code clear at the call site. Only use a named parameter when the label makes RECEIVING the code easy to understand. Omit the named parameter when it’s redundant or add- result = DATA(lines). ing unnecessary noise to the code. 4 Listing 4.48 Using CALL METHOD

4.4.5 Self-Reference Reserve CALL METHOD for Dynamic Method Calls In the code inside instance methods, the self-reference me is implicitly set by the system The CALL METHOD construct for calling methods is obsolete and unnecessarily verbose. and can be used to access the current class instance. This self-reference is equivalent to Use the call style with parentheses to make the code more consistent and easier to the self-reference this in languages like Java and #. read and to better support other clean code patterns discussed in this chapter. Picking up on the version of the log_exception method shown earlier in Listing 4.41, we Only use the CALL METHOD construct for dynamic method calls, where the class or the could implement the same code by explicitly using the self-reference me, as shown in method name is resolved at runtime, as in Listing 4.49. Listing 4.50. CALL METHOD modify->(method_name) METHOD log_exception. EXPORTING CHECK exception_instance IS BOUND. node = my_bo_c=>node-item me->log_exception_header( exception_instance ). key = item->key me->log_exception_body( exception_instance ). data = item me->log_previous_exception( exception_instance->previous ). changed_fields = changed_fields. ENDMETHOD. Listing 4.49 CALL METHOD for Dynamic Method Calls Listing 4.50 Using the Self-Reference me to Call Instance Methods However, we recommend you design your application around interfaces and avoid using dynamic method calls whenever possible. Omit the Self-Reference When Not Needed You should omit the self-reference me when calling instance methods or accessing 4.4.4 Optional Parameter Name instance members of the containing class. Using me is redundant and doesn’t add any When a method has a single non-optional input parameter or a PREFERRED PARAMETER, clarity to the code. the caller can provide a single unnamed argument for that parameter. This call style, However, if a parameter or a variable name shadows a class instance member, then when using a properly named variable or constant, can make the calling code more you’re forced to use me to disambiguate, for example, in the step_fan constructor concise and still clean and readable, as in the following code: shown in Listing 4.51.

DATA(lines) = split_text_into_lines( text ). METHOD constructor. super->constructor( ). Naming the parameter in this case, as in the following code, is unnecessarily verbose validate_step( step ). and redundant: me->step = step. ENDMETHOD. DATA(lines) = split_text_into_lines( text = text ). Listing 4.51 Using me to Assign to an Instance Member of the Class At times, however, a method name alone fails to help the reader understand what the Only use me when you need to reference a shadowed class instance member. Other- supplied argument means. In this case, adding the parameter name increases readabil- wise, the self-reference is redundant and only adds clutter to your code. ity, as in the following code: car->drive( speed = 50 ).

128 129 4Methods 4.5 Summary

4.5 Summary ½ Omit the RECEIVING keyword. ½ Reserve CALL METHOD for dynamic method calls. In this chapter, we covered some important guidelines on how to think about, design, ½ Use the optional parameter name if it adds clarity. and use methods in clean ABAP code. Let’s recap the clean ABAP rules for methods we ½ covered. Omit the self-reference when not needed. 4 We started with some guidance on object-oriented design, including the following rec- In the next chapter, we’ll look at the crucial topic of naming, and you’ll learn the impor- ommendations: tance of good names and how they help improve your ABAP code. ½ Consider using instance methods by default. ½ Don’t call static methods through instance variables. ½ Public instance methods should be part of an interface. ½ Be careful when redefining methods.

Then, we took you on a grand tour of how parameters work and how to design them, while exploring the following recommendations: ½ Aim for as few input parameters as possible. ½ Split the behavior instead of adding optional parameters. ½ Use a preferred parameter sparingly. ½ Create separate methods instead of using Boolean parameters. ½ Minimize the number of EXPORTING parameters. ½ Prefer RETURNING to EXPORTING. ½ Consider using result as the name of RETURNING parameters. ½ Use CHANGING parameters sparingly. ½ Avoid using more than one kind of output parameter. ½ Do not reassign IMPORTING parameters passed by value. ½ Mind the semantics of EXPORTING parameters, prefer pass-by-value. ½ Pass-by-value CHANGING parameters don’t make sense.

In Section 4.3, we delved into some important considerations when designing the body within methods: ½ A method should do one thing, and only one thing. ½ Descend one level of abstraction. ½ Keep methods small. ½ Fail fast. ½ Focus on the happy path or error handling.

Finally, we ended this chapter with a discussion of several clean ABAP aphorisms related to invoking methods: ½ Omit the optional EXPORTING keyword.

130 131 Contents

Foreword ...... 21 SAP S/4HANA: A New ERP Platform ...... 23

PART I Foundation

1 Architecture Challenges of a Modern ERP Solution 29

1.1 Characteristics of a Modern ERP System ...... 30 1.1.1 Even Higher Performance and Scalability ...... 30 1.1.2 Consumer-Grade User Experience ...... 32 1.1.3 Extensible Architecture ...... 33 1.1.4 Intelligent ERP Processes ...... 33 1.1.5 Simplified and Standardized Implementation ...... 34 1.1.6 Cloud and On-Premise Deployment Models ...... 35 1.1.7 Security, Privacy, Compliance, and Data Isolation ...... 36 1.2 SAP S/4HANA Architecture Principles ...... 37 1.2.1 Stable but Flexible Digital Core ...... 37 1.2.2 Simplification with the Principle of One ...... 37 1.2.3 Open for Innovations through Service Orientation ...... 39 1.2.4 Modularization into (Hybrid) Integration Scenarios ...... 40 1.2.5 Cloud First, but Not Cloud Only ...... 40 1.2.6 Semantic Compatibility to Support Evolution with the Least Possible Disruption ...... 41 1.3 Evolving a Cloud ERP System from the Best Possible Origins ...... 42 1.4 Summary ...... 42

2 Technical Architecture Foundation 43

2.1 The Virtual Data Model ...... 43 2.1.1 Core Data Services ...... 44 2.1.2 Naming Conventions ...... 44 2.1.3 Structure of the Virtual Data Model ...... 45 2.1.4 Consumption Scenarios ...... 47

7 Contents Contents

2.2 ABAP RESTful Application Programming Model ...... 49 4.3.5 Use Case Examples ...... 109 2.2.1 Defining and Developing Business Objects ...... 49 4.3.6 Intelligent Situation Automation ...... 110 2.2.2 Defining Business Services ...... 56 4.3.7 Message-Based Situation Handling ...... 111 2.2.3 Runtime Architecture ...... 59 4.4 Summary ...... 111 2.3 Summary ...... 66

5 Extensibility 113 3 Simplified Experience 67 5.1 Key User Extensibility ...... 113 3.1 User Experience ...... 67 5.1.1 Stability Criteria for Extensibility ...... 114 3.1.1 SAP Fiori ...... 67 5.1.2 Principles of In-App Key User Extensibility ...... 116 3.1.2 User Experience Adoption Strategy ...... 68 5.1.3 Field Extensibility ...... 117 3.1.3 SAP Fiori Launchpad ...... 69 5.1.4 Integration Extensibility ...... 119 3.1.4 SAP Fiori Apps ...... 72 5.1.5 Custom Business Logic ...... 119 3.1.5 SAP Fiori Elements Apps ...... 74 5.1.6 Custom Business Objects ...... 121 5.1.7 Custom CDS views ...... 122 3.2 Search ...... 77 5.1.8 Lifecycle Management ...... 122 3.2.1 Search Architecture ...... 77 3.2.2 Enterprise Search Extensibility ...... 80 5.2 Side-by-Side Extensions ...... 123 5.2.1 Introduction to Cloud-Native Applications ...... 124 3.3 Summary ...... 82 5.2.2 SAP Cloud Platform and Programming Models ...... 128 5.2.3 Cloud Foundry Environment ...... 128 5.2.4 Kyma Runtime ...... 128 4 Intelligence and Analytics 83 5.2.5 Integrating with SAP S/4HANA Using the SAP Cloud SDK ...... 129 5.3 Summary ...... 134 4.1 Analytics ...... 83 4.1.1 SAP S/4HANA Embedded Analytics Architecture Overview ...... 84 4.1.2 Embedded Analytical Applications ...... 87 4.1.3 Modeling Analytical Artifacts ...... 88 6Integration 137 4.1.4 Analytics Extensibility ...... 89 4.1.5 Enterprise Analytics Applications ...... 91 6.1 SAP S/4HANA Integration Interface Technologies ...... 137 6.1.1 OData Services ...... 137 4.2 Machine Learning ...... 92 6.1.2 SOAP Services ...... 138 4.2.1 Machine Learning Architecture ...... 93 6.1.3 Remote Function Call ...... 138 4.2.2 Embedded Machine Learning ...... 94 6.1.4 BAPIs ...... 138 4.2.3 Side-By-Side Machine Learning Architecture ...... 96 6.1.5 IDoc ...... 138 4.2.4 Machine Learning in SAP S/4HANA Applications ...... 97 6.1.6 SAP S/4HANA API Strategy ...... 139 4.3 Intelligent Situation Handling ...... 100 6.2 SAP API Business Hub ...... 139 4.3.1 Example: Contract is Ready as Source of Supply ...... 101 4.3.2 Technological Background ...... 102 6.3 Interface Monitoring and Error Handling with SAP Application 4.3.3 Intelligent Situation Handling Concept ...... 104 Interface Framework ...... 140 4.3.4 User Experience ...... 105

8 9 Contents Contents

6.4 Communication Management in SAP S/4HANA Cloud ...... 142 8.1.2 Product Hierarchy ...... 180 6.4.1 Communication Scenario ...... 144 8.1.3 Data Migration ...... 182 6.4.2 Communication User ...... 144 8.1.4 Product SOAP Service API ...... 183 6.4.3 Communication System ...... 145 8.1.5 Product Master Extensibility ...... 183 6.4.4 Communication Arrangement ...... 145 8.1.6 Self-Service Configuration ...... 184 6.4.5 Calling Inbound Services with User Propagation ...... 145 8.2 Bill of Materials, Characteristics, and Configurations ...... 185 6.5 Cloud Connector ...... 146 8.2.1 Bill of Materials (BOM) ...... 185 6.5.1 Cloud Connector Principles ...... 146 8.2.2 Classification System ...... 187 6.5.2 RFC Communication with SAP S/4HANA Cloud ...... 148 8.2.3 Variant Configuration ...... 188 8.2.4 Variant Classes ...... 190 6.6 Integration Middleware ...... 148 8.2.5 Super BOM ...... 190 6.7 Event-Based Integration ...... 150 8.2.6 BOM with Class Items ...... 191 6.7.1 SAP Cloud Platform Enterprise Messaging ...... 151 8.2.7 Variant Configuration Profiles ...... 191 6.7.2 Business Events Architecture in SAP S/4HANA ...... 152 8.2.8 Object Dependencies in Variant Configuration ...... 191 6.7.3 Business Events in SAP S/4HANA ...... 153 8.2.9 User Interface and Grouping ...... 192 6.7.4 Event Channels and Topic Filters ...... 154 8.2.10 Extensibility ...... 192 6.8 Data Integration ...... 154 8.2.11 High-Level and Low-Level Configuration ...... 192 6.8.1 CDS-Based Data Extraction ...... 155 8.2.12 Embedded Analytics for Classification and Configuration Data ...... 193 6.8.2 Data Replication Framework ...... 157 8.3 Business Partner ...... 195 6.8.3 Master Data Integration Services ...... 158 8.3.1 Architecture of Business Partner Master Data ...... 196 6.9 Summary ...... 159 8.3.2 SAP S/4HANA System Conversion Scenarios ...... 201 8.3.3 Data Protection and Policy ...... 203 8.3.4 Extensibility ...... 203 8.3.5 Business Partner APIs ...... 204 7 Data Protection and Privacy 161 8.4 Summary ...... 205

7.1 Compliance Base Line ...... 162 7.2 Definitions and Principles ...... 162 7.2.1 Basics in SAP S/4HANA ...... 164 9Sales 207 7.2.2 Data Subject Rights ...... 165 7.2.3 Technical and Organizational Measures ...... 167 9.1 Architecture Overview ...... 207 7.3 Summary ...... 169 9.2 Sales Documents Structure ...... 209 9.3 Authorizations ...... 210 9.4 Sales Inquiries and Sales Quotations ...... 211 PART II Application Architecture 9.5 Sales Order Processing ...... 212 9.6 Sales Contracts ...... 213 8 Master Data 175 9.7 Sales Scheduling Agreements ...... 214

8.1 Product Master ...... 175 9.8 Claims, Returns, and Refund Management ...... 215 8.1.1 Product Master Data Model ...... 176

10 11 Contents Contents

9.9 Billing ...... 216 11 Sourcing and Procurement 239 9.10 Sales Monitoring and Analytics ...... 217 9.11 Pricing ...... 220 11.1 Architecture Overview ...... 240 9.12 Integration ...... 221 11.2 Procurement Processes ...... 242 11.2.1 Direct Procurement ...... 243 9.13 Summary ...... 222 11.2.2 Indirect Procurement ...... 244 11.3 Architecture of a Business Object in Procurement ...... 244 11.4 Central Procurement ...... 245 10 Service Operations 225 11.4.1 Backend Integration ...... 248 11.5 APIs and Integration ...... 249 10.1 Architecture Overview ...... 225 11.5.1 SAP S/4HANA Procurement Integration with SAP Ariba and ...... 226 10.2 Business Objects and Processes in Service Operations SAP Fieldglass ...... 249 10.2.1 Field Service ...... 227 11.6 Analytics ...... 253 10.2.2 In-House Repair ...... 228 10.2.3 Service Contracts ...... 228 11.7 Innovation and Intelligent Procurement ...... 254 10.2.4 Solution Business ...... 229 11.8 Summary ...... 256 10.2.5 Interaction Center ...... 229 10.3 Master Data and Organizational Model ...... 229 10.3.1 Business Partner ...... 229 12 Logistics and Manufacturing 257 10.3.2 Service Products ...... 230 10.3.3 Organizational Units ...... 230 10.3.4 Service Teams ...... 230 12.1 Architecture Overview ...... 258 10.3.5 Technical Objects ...... 230 12.2 Organizational Units ...... 260 10.4 Data Model and Business Transactions Framework ...... 231 12.3 Master Data Objects ...... 261 10.4.1 Business Transactions Framework ...... 231 12.4 Transactional Business Objects ...... 262 10.4.2 Data Model ...... 231 10.4.3 Transaction Type and Item Category ...... 233 12.5 Calculated Business Objects, Engines, and Process Control ...... 265 10.4.4 Common Functions for Service Transactions ...... 233 12.5.1 Inventory ...... 265 10.4.5 Virtual Data Model ...... 234 12.5.2 Available-to-Promise ...... 267 10.4.6 Public APIs ...... 235 12.5.3 Material Requirements Planning ...... 271 12.5.4 Demand-Driven Material Requirements Planning ...... 273 10.5 Integration ...... 235 12.5.5 Kanban ...... 274 10.5.1 Data Exchange Manager ...... 235 12.5.6 Just-In-Time Processing ...... 275 10.5.2 Backward Integration ...... 236 12.5.7 Predictive Material and Resource Planning ...... 278 10.5.3 Integration with SAP Field Service Management ...... 237 12.5.8 Capacity Planning ...... 280 10.5.4 User Interface Technology ...... 237 12.5.9 Production Planning and Detailed Scheduling ...... 281 10.6 Summary ...... 238 12.6 Cross Functions in Logistics and Manufacturing ...... 281 12.6.1 Batch Management ...... 282 12.6.2 Quality Management ...... 282 12.6.3 Handling Unit Management ...... 285

12 13 Contents

12.6.4 Serial Number Management ...... 286 14.5 Financial Planning and Analysis ...... 330 12.6.5 Inter-/Intracompany Stock Transport ...... 287 14.5.1 Budgetary Accounting ...... 330 12.7 Logistics Integration Scenarios ...... 287 14.5.2 Predictive Accounting ...... 332 12.7.1 Warehouse Management ...... 287 14.5.3 Financial Planning ...... 336 12.7.2 Manufacturing Execution Systems ...... 288 14.5.4 Margin Analysis ...... 340 14.5.5 Overhead Cost ...... 342 12.8 Summary ...... 288 14.5.6 Production Cost ...... 344 14.6 Payables Management ...... 347 14.6.1 Supplier Invoicing ...... 347 13 Extended Warehouse Management 289 14.6.2 Open Payables Management ...... 348 14.6.3 Automatic Payment Processing ...... 348 13.1 Architecture Overview ...... 289 14.7 Receivables Management ...... 349 13.2 Organizational Structure ...... 291 14.7.1 Open Receivables Management ...... 350 14.7.2 Credit Evaluation and Management ...... 354 13.3 Master Data ...... 292 14.7.3 Customer Invoicing ...... 357 13.4 Stock Management ...... 292 14.7.4 Dispute Resolution ...... 358 13.5 Application Components ...... 294 14.7.5 Collection Management ...... 360 14.7.6 Convergent Invoicing ...... 361 13.6 Monitoring and Reporting ...... 297 14.7.7 Contract Accounting ...... 365 13.7 Process Automation ...... 297 14.8 Treasury Management ...... 369 13.8 User Interface ...... 298 14.8.1 Advanced Payment Management ...... 370 13.9 Technical Frameworks ...... 299 14.8.2 Bank Integration Using SAP Multi-Bank Connectivity ...... 372 14.8.3 Connectivity to Payment Service Providers and Payment Gateways ... 374 13.10 Warehouse Automation ...... 300 14.8.4 Cash Management ...... 375 13.11 Summary ...... 300 14.8.5 Treasury and Risk Management ...... 378 14.9 Central Finance ...... 382 14.9.1 Replication ...... 384 14 Finance, Governance, Risk, and Compliance 303 14.9.2 Mapping ...... 386 14.9.3 Accounting Views of Logistics Information ...... 387 14.1 Finance Architecture Overview ...... 305 14.9.4 Central Payment ...... 390 14.9.5 Cross-System Process Control ...... 390 14.2 Accounting ...... 306 14.2.1 General Ledger ...... 309 14.10 Finance Extensibility ...... 394 14.2.2 Fixed Asset Accounting ...... 309 14.11 SAP Governance, Risk, and Compliance ...... 394 14.2.3 Inventory Accounting ...... 311 14.11.1 Overview of SAP GRC Solutions ...... 395 14.2.4 Lease Accounting ...... 313 14.11.2 SAP GRC Solutions and SAP S/4HANA Integration ...... 397 14.2.5 Service and Sales Accounting ...... 314 14.11.3 SAP S/4HANA Integration with Enterprise Risk and Compliance ...... 397 14.2.6 Group Reporting ...... 318 14.11.4 SAP S/4HANA Integration with International Trade Management ...... 398 14.2.7 Financial Closing ...... 324 14.11.5 SAP S/4HANA Integration with Access Governance ...... 399 14.3 Tax and Legal Management ...... 326 14.11.6 SAP S/4HANA Integration with SAP Privacy Governance ...... 400 14.4 Enterprise Contract Management and Assembly ...... 328 14.12 Summary ...... 401

15 Contents Contents

15 Localization in SAP S/4HANA 403 17.2 Managing Users, Roles, and Catalogs ...... 432 17.2.1 Communication Arrangements ...... 433 17.2.2 User Types ...... 433 15.1 Advanced Compliance Reporting ...... 403 17.2.3 SAP PFCG Roles and Business Catalogs ...... 434 15.2 Document Compliance ...... 406 17.2.4 Management of Users, Roles, and Catalogs by Customers ...... 436 15.2.1 Motivation ...... 406 17.2.5 Auditors ...... 438 15.2.2 Architecture Overview ...... 407 17.3 Summary ...... 440 15.2.3 Recent Developments and Future Outlook ...... 409 15.3 Localization Toolkit for SAPS/4HANA Cloud ...... 409 15.3.1 Components of the Toolkit ...... 409 15.3.2 Extensibility Scenario Guides and the Community ...... 410 18 Output Management 441 15.4 Summary ...... 411 18.1 Architecture Overview ...... 441 18.2 Printing ...... 442 PART III SAP S/4HANA Cloud-Specific Architecture 18.3 Email ...... 444 and Operations 18.4 Electronic Data Interchange ...... 445 18.5 Form Templates ...... 446 16 Scoping and Configuration 415 18.6 Output Control ...... 447 18.7 Summary ...... 449 16.1 Configure Your Solution: Scoping and Configuration Today ...... 417 16.1.1 Content Model of SAP Solution Builder Tool ...... 417 16.1.2 Scoping and Deployment ...... 419 16.2 Outlook: SAP Central Business Configuration ...... 419 19 Cloud Operations 451 16.2.1 The Business Adaptation Catalog ...... 420 16.2.2 The Ten Business Adaptation Catalog Commandments ...... 422 19.1 SAP S/4HANA Cloud Landscape ...... 451 16.2.3 Business Processes ...... 423 19.2 Data Centers ...... 453 16.2.4 Constraints ...... 424 19.3 Multitenancy ...... 454 16.2.5 From Scoping to Deployment ...... 424 19.3.1 The System Architecture of SAP S/4HANA ...... 455 16.3 Summary ...... 424 19.3.2 Sharing the SAP HANA Database System ...... 456 19.3.3 Sharing of ABAP System Resources ...... 457 19.3.4 The Table Sharing Architecture in Detail ...... 458 17 Identity and Access Management 425 19.4 Software Maintenance ...... 461 19.4.1 Maintenance Events ...... 461 17.1 Architecture Concepts of Identity and Access Management ...... 425 19.4.2 Blue-Green Deployment ...... 462 17.1.1 ABAP Authorization Concept ...... 426 19.5 Built-in Support ...... 463 17.1.2 Authentication ...... 426 19.5.1 Support Journey without Built-in Support ...... 464 17.1.3 Identity and Access Entities and Their Relationships ...... 427 19.5.2 Built-in Support Architecture ...... 466 17.1.4 Identity and Access Management Tools ...... 430 19.6 Summary ...... 468 17.1.5 SAP Fiori Pages and Spaces ...... 431

16 17 Contents Contents

20 Sizing and Performance in the Cloud 471 22 Outlook 493

20.1 Performance-Optimized Programming ...... 471 20.1.1 Minimal Number of Network Round Trips and Transferred Data Volume ...... 472 The Authors ...... 495 20.1.2 Content Delivery Networks ...... 474 Index ...... 513 20.1.3 Buffers and Caches ...... 474 20.1.4 Nonerratic Performance ...... 475 20.2 Sizing ...... 475 20.2.1 Example for Greenfield Sizing ...... 476 20.2.2 Brownfield Sizing ...... 478 20.3 Elasticity and Fair Resource Sharing ...... 478 20.3.1 Dynamic Capacity Management ...... 479 20.4 Sustainability ...... 481 20.5 Summary ...... 483

21 Cloud Security and Compliance 485

21.1 Network and Data Security Architecture ...... 485 21.1.1 Access Levels ...... 486 21.1.2 Resource and Data Separation ...... 487 21.1.3 Resource Sharing ...... 487 21.1.4 Data Security and Data Residency ...... 488 21.1.5 Business Continuity and Disaster Recovery ...... 488 21.2 Security Processes ...... 488 21.2.1 Security Configuration Compliance Monitoring ...... 488 21.2.2 Security Event Management and Incident Response ...... 489 21.2.3 Infrastructure Vulnerability Scanning ...... 489 21.2.4 Malware Management ...... 489 21.2.5 Security Patch Management ...... 489 21.2.6 User Management ...... 490 21.2.7 Hacking Simulation ...... 490 21.3 Certification and Compliance ...... 490 21.3.1 SAP Operations ...... 490 21.3.2 SAP Software Development ...... 491 21.4 Summary ...... 491

18 19 Index

A Actions ...... 57 Affixes ...... 140–141 ABAP ...... 23, 33 Aliases ...... 81 comments ...... 212 Alignment ...... 221 exceptions ...... 233, 236 assignment statements ...... 221 messages ...... 229 ragged ...... 226 object orientation ...... 41 variable declarations ...... 222 packages ...... 299 vertical ...... 226 programming paradigm ...... 37 Annotations ...... 255 test tools ...... 288 Append statement ...... 174 ABAP Authority Check Test Helper API ...... 289 Application hierarchies ...... 305 ABAP CDS Test Double Framework ...... 288 Arguments ...... 224 ABAP Data Dictionary ...... 51, 53, 64 Array-like tables ...... 172 ABAP Development Tools (ADT) ...... 77, 118, ASSERT statements ...... 251 138, 217, 219, 239, 246, 254, 260, 310 Assertions ...... 255, 269 ABAP Docs ...... 212, 258, 268 constraints ...... 277 ABAP Objects ...... 51–52, 95 custom ...... 275 implementation inheritance ...... 65 expected exceptions ...... 272 ABAP Programming Guidelines ...... 30 failure ...... 269, 271, 274 ABAP Runtime Type Services (RTTS) ...... 86 methods ...... 269, 277 ABAP SQL Test Double Framework ...... 288 writing ...... 270 ABAP Test Cockpit ...... 28, 243, 325 Assignment operators ...... 221 ABAP Test Double Framework ...... 284 Assignment statements ...... 221 configure calls ...... 287 Automated executions ...... 312 when to use ...... 288 Automated testing ...... 253, 292, 333 ABAP Unit ...... 253, 256, 262 Avoidable errors ...... 247 call sequence ...... 262 ABAP Workbench ...... 308 B abap_bool type ...... 162 abap_false ...... 162–163 Backlog items ...... 27 abap_true ...... 162 Base classes ...... 59 abap_undefined ...... 162 Black grade ...... 322 abapGit ...... 29 Blank lines ...... 220 abaplint ...... 29 Blank spaces ...... 220 ABAP-Managed Database Procedures Block operations ...... 182 (AMDPs) ...... 35 Block processing ...... 181 abapOpenChecks ...... 29 Booleans ...... 161, 163 Abbreviations ...... 136 conditions ...... 191 Abstract classes ...... 59, 63 naming ...... 137 rules ...... 61 parameters ...... 106 Abstract factory ...... 91 Bottlenecks ...... 320 Abstract final ...... 155 Boy Scout Rule ...... 27, 201, 212 Abstract types ...... 53 Branch coverage ...... 294, 326 Abstraction ...... 24, 52, 55, 81, 270 Branches ...... 148 levels ...... 117 IF statements ...... 188 Accessor methods ...... 82 nesting depth ...... 190 Accidental architecture ...... 316 Broken window effect ...... 323 Accounts ...... 53 examples ...... 324

341 Index Index

Builder class ...... 89 Classes (Cont.) Code rewrite ...... 324 Constructors (Cont.) Builder pattern ...... 89 dependencies ...... 85 Code steward ...... 321 dependencies ...... 86 Built-in object class ...... 66 enumeration ...... 154 Code under test ...... 266 error handling ...... 123 friendship ...... 81 isolate ...... 279 injection ...... 280 C global ...... 76 Cohesion ...... 297, 299 scope and visibility ...... 83 immutable ...... 82 Collecting parameters ...... 111 specialized ...... 97 CALL FUNCTION statement ...... 231 inheritance ...... 39, 59, 65 Collective code ownership ...... 320 static ...... 49, 90 Call method ...... 127, 189 instance ...... 96 steps ...... 320 CONTINUE statement ...... 201 camelCase ...... 140 local ...... 77 Command ...... 56 Control flow ...... 185, 193, 203, 273 Capitalization ...... 217 messages ...... 230 Commented code ...... 211 pseudo loops ...... 200 CASE blocks ...... 198 naming ...... 136 Comments ...... 205 Converting expressions ...... 195 CASE keyword ...... 185 production ...... 254 IF branches ...... 210 Copy-on-write optimization ...... 113 CASE statements ...... 196 small ...... 36 instructive ...... 211 Core data services (CDS) views ...... 51, 288 hide ...... 199 stateful ...... 75 issues ...... 205 naming ...... 140 reusing ...... 199 static ...... 61 method names ...... 268 Coupling ...... 297 versus IFs ...... 197 stub ...... 281 placement ...... 208 undesired ...... 309 CATCH blocks ...... 202, 249 test ...... 254 pseudo ...... 213 Coverage report ...... 260, 294 CATCH keyword ...... 249 test helper ...... 259 remove ...... 210 CREATE OBJECT ...... 93 Catching exceptions ...... 248 utility ...... 61, 97 special ...... 212 Creational patterns ...... 89 visibility ...... 81 cleanup ...... 250 what to avoid ...... 208 Credit score service class ...... 106 wrap with functions ...... 43 Chaining ...... 150, 166 when to use ...... 207 Cross-functional teams ...... 334–335 Classic exceptions ...... 234–235 IFs ...... 200 Common understanding ...... 319, 321 Currency conversion ...... 290 convert ...... 241 Changing parameters ...... 111 Communication style ...... 328 service ...... 53 Clean ABAP ...... 23, 29, 33, 35–37 pass by value ...... 115 Communities of practice ...... 336 Custom assertions ...... 270, 275 back story ...... 25 Character limits ...... 219 Community engagement ...... 30 constraints ...... 277 community engagement ...... 30 CHECK keyword ...... 186 Compatible reference variable ...... 91 parameters ...... 276 get started ...... 26 CHECK statements ...... 124, 186, 200, 203 Complex conditions ...... 195 Custom stubs ...... 284 repository ...... 31 Checks ...... 148, 164–165, 189, 200 Composing object ...... 74 CX_DYNAMIC_CHECK ...... 244 rules ...... 26 automatic ...... 28 Composition ...... 70 CX_NO_CHECK ...... 243 Clean ABAP open-source style guide ...... 327 basic ...... 165 constraints ...... 279 superclass ...... 246 Clean code ...... 23, 185, 205, 249, 319 packages ...... 308 versus inheritance ...... 73 CX_STATIC_CHECK ...... 242, 247 messages ...... 232 result ...... 109 COND statements ...... 187 Cyclic dependency ...... 309 Clean code advisor ...... 330 suppress ...... 213 Condensing ...... 220 Cyclomatic complexity metric ...... 190, 325 Clean Code Developer Initiative ...... 322 Conditions ...... 186, 190, 195 Child classes ...... 66, 69 Clean islands ...... 28 Circular dependency ...... 309 Clean test properties ...... 292 complex ...... 195 D CL_OSQL_REPLACE statement ...... 288 Cleanup ...... 251 deconstruct ...... 196 Class declaration statement ...... 83 CLEANUP keyword ...... 250 enhance ...... 192 Data keyword ...... 146 Class instances ...... 59 Client code ...... 81, 91, 107 inline ...... 195 chaining ...... 150 Class interfaces ...... 266 Client packages ...... 300 positive formulation ...... 190 Database tables ...... 173 Class member visibility ...... 81 Closing brackets ...... 223 raising exceptions ...... 248 Decision trees ...... 190 Class under test ...... 266 Code base ...... 35 reusing ...... 193 Declaration ...... 145–146 naming ...... 268 Code coverage ...... 325–326 Consistency ...... 137, 216 alignment ...... 222 Class-based exceptions ...... 233, 235–237, Code editor ...... 219 Constant pattern ...... 155 anonymous ...... 147 242, 245 Code Inspector ...... 28, 37 Constants ...... 152, 159 chaining ...... 149 raising ...... 247 Code optimization ...... 115 grouping ...... 159 inline ...... 44, 146, 227 Classes ...... 51, 57 Code retreat ...... 330–331 handling ...... 154 scope ...... 149 abstract ...... 59 Code review ...... 25, 326 Constraints ...... 277 strings ...... 160–161 builder ...... 89 feedback culture ...... 327 classes ...... 278 up front ...... 149 composition ...... 70 managers ...... 329 Constructors ...... 61, 63, 83, 87 Declarative programs ...... 38 constants ...... 154 prefix ...... 326 ADT ...... 239 Deconstruction ...... 196 constraint ...... 278 rules ...... 328 declare multiple ...... 86 Default constructor ...... 84 definition ...... 59 visibility ...... 327 default ...... 84 Default fail method ...... 56, 88

342 343 Index Index

Default ignore methods ...... 56 Error handling (Cont.) Failure modes ...... 75 Hash operator ...... 147 Default keys ...... 174 exceptions ...... 236 Feature code ...... 229 Hashed tables ...... 173 Default parameter values ...... 104 messages ...... 229 Feedback culture ...... 327, 329 append ...... 175 Depended-on components (DOC) ...... 279 package checks ...... 313 Fellowship ...... 332 Higher level tests ...... 257 Dependencies ...... 158, 250, 279 raising and catching ...... 245 Field-symbol ...... 152, 188 Hungarian notation ...... 138, 142, 267 circular ...... 315 relocating ...... 249 Filter keyword ...... 148 implement ...... 281 return codes ...... 232 Fixed row data ...... 171 I return code ...... 234 Error messages ...... 229 FIXME prefix ...... 212 test classes ...... 256 Exceptions ...... 116, 124, 181, 186, 202, Flaky tests ...... 325 IF blocks ...... 187, 190, 197, 200 Dependency injection ...... 85, 280, 293 233, 235–236, 272 FOR TESTING annotation ...... 259 IF branches ...... 186 Dependency inversion principle ...... 99, 280 catching ...... 248 Foreign code ...... 218 comments ...... 210 DESCRIBE TABLE statement ...... 182 class-based ...... 233, 237 Foreign tests ...... 258, 260 IF keyword ...... 185 Descriptive names ...... 133 classes ...... 99 Formatting ...... 215 where to put ...... 189 Design patterns ...... 48, 138 CX_DYNAMIC_CHECK ...... 244 Friendship ...... 81, 266 IF statements ...... 179, 188 mixing patterns ...... 49 CX_NO_CHECK ...... 243 Function groups ...... 38 versus CASE ...... 196 Development objects ...... 300 CX_STATIC_CHECK ...... 242 no inheritance ...... 39 IF_T100_DYN_MSG interface ...... 241 Development packages ...... 300 dependencies ...... 250 no instantiation ...... 38 Immutability ...... 64–65, 75 Direct assignments ...... 147 details ...... 118 no interfaces ...... 40 Implicit knowledge ...... 195 DO 1 TIMES statement ...... 200, 202 dynamically checked ...... 244 no method encapsulation ...... 41 Indentation ...... 217, 225 Dojo ...... 330–331 expected ...... 272 no method namespaces ...... 39 inline declarations ...... 227 Domain fixed values ...... 154 fail fast ...... 122 weak substitution ...... 40 keywords ...... 227 Domain terms ...... 134 handling ...... 36 weak variable encapsulation ...... 41 Indexes ...... 172, 175, 177 Don’t-repeat-yourself principle ... 165, 193, 199 messages ...... 247 Function modules ...... 95, 209, 233, 235, 290 Individual code ownership ...... 320 Double negations ...... 191–192 OTHERS ...... 233 exceptions ...... 233 Individual learning ...... 323 Drivers ...... 331, 333 raise ...... 247, 273 wrapping ...... 236 Infixes ...... 140 Dumps ...... 251 request ...... 315 Functional language constructs ...... 44 Information messages ...... 230 Duplicate entries ...... 175 static ...... 274 examples ...... 45 Inheritance ...... 39, 52, 65, 69, 95 Duration ...... 255, 260 superclass ...... 245 Functional programs ...... 38 design ...... 70 Dynamic dispatch ...... 69, 95 text IDs ...... 239 exceptions ...... 245 Dynamic method calls ...... 128 types ...... 238 G hierarchies ...... 69 Dynamic programming ...... 88 unchecked ...... 243 method redefinitions ...... 102 Dynamically checked exceptions ...... 244, unexpected ...... 274 Gang-of-four (GoF) design patterns ...... 37 test classes ...... 257 246–247, 249 Exit messages ...... 230 Generalists ...... 335 test fixture methods ...... 262 Explicit constructor ...... 61 get_messages method ...... 146 tree ...... 65 E Explicit false values ...... 162 GitHub ...... 25 utility classes ...... 63 Exporting keyword ...... 126 Given sections ...... 265, 267, 284 versus composition ...... 73 ELSE branches ...... 148, 186 Exporting parameters ...... 108 Given-then-when style ...... 265 Inline assignments ...... 187, 198 Empty key ...... 174 capturing ...... 127 Global classes ...... 77 Inline conditions ...... 195 Encapsulation ...... 41, 52, 76, 300 pass by value ...... 115 constructors ...... 84 Inline declarations ...... 34, 44, 146, 148, 151 Endifs ...... 210 pass by value versus pass by reference .... 114 Global container classes ...... 257 indent ...... 227 Enum keyword ...... 155 quantity ...... 108 Global field catalog convention ...... 140 reduce ...... 167 Enumeration classes ...... 99, 154 versus returning ...... 110 Global namespace ...... 76 string literals ...... 160 conditions ...... 193 Extended program check ...... 29 Global scope ...... 76 Inlining ...... 36 messages ...... 232 External interfaces ...... 213 Global unit test classes ...... 257 Input parameters ...... 44, 102, 111 patterns ...... 155 Extract method refactoring ...... 118 Grades ...... 322 Boolean ...... 106 Enumerations ...... 155 Green grade ...... 322 business partner ...... 108 CASE statements ...... 197 F optional ...... 42, 103 SWITCH operators ...... 199 H pass by value versus pass by reference ... 113 Error cases ...... 236 Factories ...... 91 passing ...... 125 Error handling ...... 36, 123, 229, 231 Factory method ...... 55, 70, 89, 199 Habits ...... 330, 333 preferred ...... 105 assertions ...... 271 Fail fast ...... 122 Harmonization ...... 34 quantity ...... 103 dumps ...... 251 Failure handling ...... 234 Has-a relationships ...... 70 reassignment ...... 113

344 345 Index Index

Input-output parameters ...... 102 Layer-based hierarchies ...... 306 Meta-quality ...... 272 Naming conventions (Cont.) Insert statement ...... 175 Layers ...... 135, 305 Methods ...... 26, 34, 95, 188, 223 descriptive ...... 133 Instance methods ...... 96, 111 Leadership styles ...... 321 abstraction levels ...... 117 domain terms ...... 134 self reference me ...... 129 Learning techniques ...... 330 assertion ...... 269, 277 Hungarian notation ...... 138 Instantiation ...... 38, 91 Legacy code ...... 26, 33, 120, 218, 292, 319 body ...... 115, 123 layers ...... 135 Integration tests ...... 265, 289 declarations ...... 149 Boolean parameters ...... 107 legacy code ...... 142 Interface segregation principle ...... 54–55 inheritance ...... 70 calling ...... 125 noise words ...... 137 Interfaces ...... 40, 51–52, 58–59 learning techniques ...... 333 CASE statements ...... 197 packages ...... 308 account ...... 52 naming ...... 142, 269 CHECK statements ...... 187 plural or singular ...... 135 calling ...... 125 test seams ...... 290 check versus return ...... 124 reduce operations ...... 167 constants ...... 154 Line breaks ...... 220, 224 closing brackets ...... 223 term consistency ...... 137 exceptions ...... 241 Line lengths ...... 219 define outputs ...... 108 unit testing ...... 267 factory ...... 91 LINE_EXISTS function ...... 177 do one thing ...... 115 Navigators ...... 331, 333 global ...... 76 Lines ...... 183 exceptions ...... 238, 242 Neat code ...... 215 members ...... 55 Liskov substitution principle ...... 55, 69, 102 funtion module wrapping ...... 236 Negative conditions ...... 191–192 method takeover ...... 42 Literals ...... 153 IF statements ...... 189 Nested IF statement ...... 178–179 naming ...... 136 string ...... 160 inheritance ...... 102 Nested types ...... 159 option methods ...... 56 Local area ...... 77 line breaks ...... 226 Nesting depth ...... 188, 190 public ...... 293 Local classes ...... 77, 79 namespaces ...... 39 levels ...... 190 public instance methods ...... 99 constructors ...... 85 naming ...... 110, 137 NEW operator ...... 92 static creation methods ...... 87 Local friends ...... 266 nesting ...... 45 No-check exceptions ...... 243 visibility ...... 81 LOOP AT statement ...... 176, 178–180 object-oriented programming ...... 95 Noise words ...... 65, 137 Internal package interfaces ...... 302 Looping variables ...... 149, 151 overloading ...... 86, 103 Non-object-oriented code ...... 43 Internal tables ...... 148, 171 Loops ...... 125, 149, 151, 176, 178 parameters ...... 102 Normalized hierarchy ...... 102 append ...... 174 pseudo ...... 185, 200 parameters formatting ...... 223 NOT IS statements ...... 193 categories ...... 171 undefined signature ...... 203 redefinition ...... 100 NOT keyword ...... 193–194 declaring ...... 173 refactoring ...... 202 Nouns ...... 136 default keys ...... 173 M remove comments ...... 206 Number of statements ...... 218 insert ...... 175 size ...... 120 looping variables ...... 151 Magic numbers ...... 153 small ...... 36 O number of rows ...... 182 assertion ...... 271 split the behaviors ...... 104 populating ...... 46 Main packages ...... 299 takeover by interfaces ...... 42 Object orientation ...... 37, 41 retrieve contents ...... 176–177 Maintenance ...... 196, 216 test ...... 255, 259, 262 Object pattern ...... 157–158 unnecessary table reads ...... 180 Managers ...... 329 test fixture ...... 262 Object references ...... 111 Invariants ...... 75 Meaningful names ...... 133 Metrics ...... 325 Object-oriented programming ...... 38, 51, 58 Invoking methods ...... 102 Measurements ...... 37 Mob programming ...... 330, 333 characteristics ...... 51 Irrelevant constructs ...... 34 MESSAGE statements ...... 229, 231 Mocks ...... 285 methods ...... 95 IS INITIAL statements ...... 193 Messages ...... 160, 202, 229, 237 instances ...... 98 naming ...... 136 IS NOT INITIAL keyword ...... 165 add to exceptions ...... 247 when to use ...... 288 Objects ...... 58 IS NOT statements ...... 193 ADT ...... 239 Multiple parameter calls ...... 224 allowed ...... 310 Is-a relationships ...... 69 classes ...... 230, 241 Mutation testing ...... 333 bundle ...... 303 I-shaped profile ...... 335 clean code ...... 232 expose ...... 314 Iterations ...... 167 comments ...... 211 N mock ...... 285 Iterator pattern ...... 78 containers ...... 112 naming ...... 136 error ...... 271 Name collisions ...... 139 regrouping ...... 297 K handling ...... 229 prefixes ...... 140 Obsolete language constructs ...... 48 ID ...... 230 Naming conventions ...... 133 Obsolete language elements ...... 46 Kata ...... 330 map to exceptions ...... 238 ABAP ...... 138 Open communication ...... 143 number ...... 230 abbreviations ...... 136 Open SQL ...... 51, 288 L raising ...... 161 affixes ...... 140 Open-closed principle ...... 55 types ...... 229 classes and methods ...... 136 Optimization ...... 216 Latest constructs ...... 34 variables ...... 231 collisions ...... 139 Optional methods ...... 56

346 347 Index Index

Optional parameter names ...... 128 Partial implementations ...... 59 Q Rows (Cont.) Orange grade ...... 322 Pass-by-reference parameters ...... 113 discern number ...... 182 OTHERS exceptions ...... 233 exporting ...... 114 Quick fixes ...... 246 find ...... 46 Output parameters ...... 102, 109, 112 input ...... 113 insert ...... 175 capturing ...... 126 Pass-by-value parameters ...... 112 read ...... 177 Overloading ...... 41 changing ...... 115 Runtime ...... 207 exporting ...... 114 Ragged alignments ...... 226 test ...... 256 P input ...... 113 RAISE EXCEPTION keyword ...... 247 Performance ...... 35, 207 RAISE SHORTDUMP statements ...... 252 S Package checks ...... 308, 310 Pipe operator ...... 161 RAISING cx_root clause ...... 275 automated execution ...... 312 Plugin architecture ...... 55 Raising exceptions ...... 247 SAP assurance and compliance software ...... 36 best practices ...... 315 Plugins ...... 245 conditions ...... 248 SAP GUI ...... 138, 229, 231, 310 errors ...... 313 Plural or singular forms ...... 135 with messages ...... 247 SAP HANA ...... 36 manual execution ...... 310 Polymorphism ...... 52, 69, 199 READ TABLE statement ...... 176, 178 Scenarios ...... 265 Package hierarchies ...... 297, 304 Positive conditions ...... 191 Readability ...... 23, 47, 215–216, 220 Scope ...... 149 by applications ...... 305 Pragmas ...... 213 Read-only attributes ...... 82 conditions ...... 191 layer-based ...... 306 Precise code ...... 205 Receiving keyword ...... 127 package interfaces ...... 301 translation relevance ...... 306 Predefined variables ...... 146 Red grade ...... 322 test classes ...... 257 Package interfaces ...... 301, 309 Preferred parameters ...... 105, 128 Redefined methods ...... 102 Self-reference me ...... 129 expose objects ...... 314 Prefixes ...... 138, 140 Reduce operations ...... 166 omit ...... 129 scope ...... 302 code review ...... 326 concerns ...... 168 Server packages ...... 300 Packages ...... 52, 297 comments ...... 211 naming ...... 167 Setter injections ...... 280 best practices ...... 303 examples ...... 140 Refactoring ...... 27, 71–72, 118, 123, Setup methods ...... 262, 264–265 breakdown ...... 308 packages ...... 308 143, 168, 201, 207, 211, 324 Severity ...... 159 cohesion ...... 299 test classes ...... 267 loops ...... 28 Short text ...... 230 design ...... 304 Pretty printer ...... 217 remove comments ...... 206, 210–211 Side effects ...... 44 encapsulated ...... 300 Primary code checks ...... 28 References ...... 152 Single Level of Abstraction Principle errors ...... 313 Primary keys ...... 172 Regrouping ...... 297–298 (SLAP) ...... 118 naming ...... 308 Print margins ...... 219 Regular expressions ...... 145, 164–165 Single parameter calls ...... 224 no strategy ...... 316 Private constructors ...... 266 complex ...... 166 Single row operations ...... 182 reuse levels ...... 298 Private methods ...... 122 simple ...... 164 Single-responsibility principle ...... 55, 75, 201 roles ...... 300 Private visibility ...... 81 Remote function calls (RFCs) ...... 43 Singleton ...... 48, 89 trigger checks ...... 310 Procedural language constructs ...... 43 Renaming ...... 143 Small tables ...... 172 types ...... 299 Procedural programs ...... 38 Restricted package interface ...... 302, 315 snake_case ...... 140 use cases ...... 298 Procedure coverage ...... 294 Resumability ...... 243, 248 Software breakdown ...... 304 Pair programming ...... 330, 332 Process methods ...... 57 Return codes ...... 232 SOLID principles ...... 55 different roles ...... 333 Production classes ...... 254 errors ...... 234 Sorted access ...... 172 Parameters ...... 102, 223 Programs ...... 95 failure handling ...... 234 Sorted tables ...... 172 Boolean ...... 106 Propagation ...... 242 RETURN statement ...... 124 append ...... 175 changing ...... 111 Property ...... 82 Returning parameters ...... 109, 126 Split-up expressions ...... 166 exporting ...... 108 Protected constructor ...... 61 capturing ...... 126 Standard tables ...... 172 indent ...... 225 Protected members ...... 61 naming ...... 110 append ...... 175 input ...... 103 Proxies ...... 73 Returning tables ...... 37 State ...... 75 optional ...... 42 Pseudo comments ...... 213 Reuse levels ...... 298 Stateful classes ...... 75 optional names ...... 128 Pseudo loops ...... 185, 200 Revisions ...... 35 Statement coverage ...... 294, 326 pass by reference ...... 113 Public constants ...... 238 Risk level ...... 256, 260 Statement Coverage report ...... 261 pass by value ...... 112 Public instance methods ...... 98–99 Roles ...... 59 Static classes ...... 61 placement ...... 224 Public interface ...... 81 Rollback work ...... 256 Static code check ...... 325 returning ...... 109 test ...... 293 Root exception class ...... 237 issues ...... 324 vertical alignment ...... 226 Public package interface ...... 302, 315 Rows ...... 171 Static constructor ...... 49, 90 Parent classes ...... 65, 69 Public reuse ...... 298 append ...... 174 Static creation methods ...... 49, 86, 89, 97 Pareto principle ...... 310 block processing ...... 181 interfaces ...... 87

348 349 Index Index

Static exceptions ...... 274 Technical debt ...... 316, 324 Transparent tables ...... 136 Value operator ...... 147 forward ...... 275 Technical packages ...... 305 T-shaped profile ...... 334–335 Value semantics ...... 63 multiple ...... 275 Template method ...... 61 Type keyword ...... 150 Variables ...... 145 Static methods ...... 55, 63, 95 design pattern ...... 70 Type safety ...... 155, 157, 162 alignment ...... 222 call ...... 98 Termination ...... 251 assignment ...... 45 Status messages ...... 230 Test classes ...... 254 U Boolean ...... 163 Strings ...... 160 executing ...... 260 branches and scope ...... 148 building ...... 161 given/when ...... 267 Ubiquitous language ...... 135 comments ...... 206 literals ...... 160 global ...... 257 Unavailable constructs ...... 34 control flow ...... 193 static ...... 160 higher level tests ...... 257 Unchecked exceptions ...... 243, 246, 251 declaring ...... 146 Structure packages ...... 299 isolate ...... 293 Understandable code ...... 24, 188, 195, 207 helper ...... 167 Stubs ...... 281–282 local ...... 254, 257–258 Uniformity ...... 217 looping ...... 151 custom ...... 284 resetting ...... 265 Unit testing ...... 147, 188, 253, 257, 289 messages ...... 231 when to use ...... 288 scope ...... 257 assertions ...... 269 strings ...... 161 Style guide ...... 327, 329 Test code ...... 292 class under test ...... 266 Verbs ...... 137 Subclasses ...... 100 Test coverage ...... 294 classes ...... 254 Vertical alignment ...... 226 Sub-methods ...... 190 Test doubles ...... 279–280, 282, 293 coverage ...... 260 Vertically dense code ...... 220 Subpackages ...... 307–308 ABAP Test Double Framework ...... 287 enumeration ...... 154, 156 Visibility ...... 81 Subroutines ...... 95 mock object ...... 287 executing ...... 260 constructors ...... 83 test tools ...... 288 Substitution ...... 40, 69 messages ...... 231 Test execution ...... 255 Suffixes ...... 65, 140 methods ...... 262 Test fixture methods ...... 262 W packages ...... 308 naming ...... 267 Test helper classes ...... 259, 276 Superclass ...... 61, 65, 68–69 principles ...... 291 Warnings ...... 213 Test injections ...... 290 exceptions ...... 237, 245 test doubles ...... 279 messages ...... 230 Test methods ...... 255, 259, 262 test ...... 259 test seams ...... 289 WHEN block ...... 197 executing ...... 262 Superfluous statements ...... 180 Units ...... 253 When sections ...... 265, 267, 284 isolation ...... 263, 293 SWITCH operations ...... 198 Unnamed arguments ...... 128 Where-used list ...... 232 naming ...... 268 reusing ...... 199 Unstructured programs ...... 37 White grade ...... 322 scenarios ...... 265 Synonyms ...... 137 Unsuitable names ...... 134 Whitespaces ...... 220 static exceptions ...... 275 Syntax ...... 193 Upfront declaration ...... 149 Wrapping ...... 236 Test relations ...... 258, 288 warnings ...... 242–244, 246 Use access ...... 309, 313–314 classes with functions ...... 43 Test seams ...... 289 System administrators ...... 307 Utility classes ...... 61, 63, 97, 259, 267 Test superclass ...... 259 sy-subrc ...... 231, 233–234 rules ...... 63 Test-driven development (TDD) ...... 250, X field ...... 191 271, 291 Utility functions ...... 63 Testing subclasses ...... 291 Utility methods ...... 97 XSDBOOL method ...... 163 T TEST-SEAM block ...... 290 XXX prefix ...... 212 Text IDs ...... 239 V T100 exception ...... 238, 242 The Stepdown Rule ...... 118 Y T100 messages ...... 238, 241 Then sections ...... 265, 267, 269, 284 Validation messages ...... 124 Tab key ...... 227 Thermal protector ...... 99 Value copies ...... 113 Yellow grade ...... 322 Table GTADIR ...... 141 Thermal switch ...... 71, 99, 280 Value objects ...... 63, 78, 99 Tables ...... 148 Timely tests ...... 291 attributes ...... 65 categories ...... 172 TODO prefix ...... 212 naming ...... 65 hashed ...... 173 Transaction naming ...... 168 CHECKMAN ...... 29 read ...... 176 SAUNIT_CLIENT_SETUP ...... 255 sorted ...... 172 SE11 ...... 141 Target currency ...... 53 SE24 ...... 217 Teams ...... 321 SE80 ...... 138, 217, 312 learning ...... 323 SE91 ...... 142 members ...... 334 Translation relevance ...... 306 Teardown methods ...... 262, 265 options ...... 307

350 351 First-hand knowledge.

Klaus Haeuptle is a developer, trainer, and product owner for engineering topics. During his career at SAP, he has worked as a developer on several products based on various technologies.

Florian Hoffmann is a software architect for governance, risk, and compliance applications at SAP. As an agile driver, he is cons- tantly trying to make writing code more efficient.

Rodrigo Jordão is a development architect at SAP currently working on integrated business planning (IBP) with a focus on SAP Supply Chain Control Tower.

Michel Martin is a development architect at SAP. He has played various roles during his SAP career, including leading trainings, managing projects, and coaching teams on ASE, lean principles, and scrum.

Anagha Ravinarayan is a developer at SAP working on SAP S/4HANA Cloud and on-premise applications in capacity planning and demand-driven replenishment product areas using ABAP, SAP HANA, and SAPUI5.

Kai Westerholz is a senior developer working in the SAP S/4HA- NA quote-to-cash area. In this role, he focuses on creating APIs like the Sales Order Simulation API or the Sales Order Bulk Processing API. Klaus Haeuptle, Florian Hoffmann, Rodrigo Jordão, Michel Martin, Anagha Ravinarayan, Kai Westerholz Clean ABAP: A Style Guide for Developers 351 Pages, 2021, $79.95 We hope you have enjoyed this reading sample. You may recommend ISBN 978-1-4932-2026-7 or pass it on to others, but only in its entirety, including all pages. This reading sample and all its parts are protected by copyright law. All usa- www.sap-press.com/5190 ge and exploitation rights are reserved by the author and the publisher.