Make Illegal States Unrepresentable
Contents
On the topic of APIs and Poka-Yoke:
Likewise, design APIs so that they make illegal states unrepresentable. If a state is invalid, it’s best to design the API so that it’s impossible to express it in code. Capture the absence of a capability in the API’s design, so that something that should be impossible doesn’t even compile. A compiler error gives you faster feedback than a runtime exception.
The above quote is from a book by Mark Seemann: Code That Fits Your Head (2021, 159–160). Seemann is also one of the authors of the excellent 2019 book Dependency Injection: principles, practices, and patterns.
At first read, it seems like a sensible though not terribly practical suggestion. After all, plenty of code compiles and still contains bugs. Then I hit upon a good example of how ABAP APIs can organically grow to allow incorrect use.
OPTIONAL parameters
Suppose you have decided to subclass the basic ALV Grid class and have also created a static factory method for creating instances:
|
|
After a while you realize that the container instance (parameter io_container
) is always created the same way, only the container name varies:
|
|
It seems sensible to Move Statements into Function and to Parameterize Function (Fowler 2019), especially since we can still support the case in which the container instance is passed as a parameter:
|
|
Now editor auto-complete suggests the following:
|
|
As far as ABAP can tell, it is syntactically correct to call this method without supplying any parameters, since all parameters have been marked as OPTIONAL
. Yet invoking the function without supplying at least one parameter will crash the program at some point. We could add code to check that at least one parameter has been supplied, but that check too takes place at runtime and ABAP programs that will fail the check are still syntactically correct and will compile. Some poor soul could even supply both parameters and would have no way of knowing (apart from looking at the method implementation) which parameter would take precedence.
This is an example of how the design of ABAP and developer practices organically produce cases where invalid cases are still syntactically correct. The following two ABAP features push APIs towards such design:
- ABAP does not support method overloading and method names are limited to 30 characters. This means that there is a strong incentive to “overload” well named methods with
OPTIONAL
parameters in order to reuse the name in different contexts. Special methods (ie.constructor
) are a special case of this, since it would not even be possible to create an alternative method. - ABAP uses named parameters. Unlike languages in which parameters are supplied as an ordered list (like C and Erlang), there’s little force limiting the number of parameters, especially given that parameters can be optional. Thus it is not uncommon to see ABAP methods with more than five parameters. Adding an optional parameter is also a favored trick for extending and changing the behavior of a method.
In order to make invalid cases syntactically incorrect, the create_grid
factory method would need to be altered somehow:
- Drop support for one of the mutually exclusive cases. Grids can be created using container instances or container names but not both.
- Create separate factory methods for each case.
create_container_and_grid
(container name) andcreate_grid_using_container
(container instance) could work. - Extract conditional code from
constructor
and extend instance creation with a factory method for required cases. Ideally all aconstructor
should do is accept dependencies/data, thus a factory method for extending would be even more welcome.
As we can see, syntactically correct yet still invalid code might lurk closer to you than you might realize.
Sources
- Deursen, S van. – Seemann, M. (2019) Dependency Injection: principles, practices, and patterns. Manning Publications. 978-1-61729-473-0.
- Fowler, M. (2019) Refactoring: improving the design of existing code. Addison-Wesley. 978-0-13-475759-9.
- Seemann, M. (2021) Code That Fits in Your Head: Heuristics for Software Engineering. Addison-Wesley. 978-0-13-746440-1.