There are a great number of fun and interesting quotes about programming (and in retrospect there’s also something surprising about them), but one quip by Alan Kay has stuck in my mind:

I invented the term object oriented, and I can tell you that C++ wasn’t what I had in mind.

It’s a snide quip, and those are always fun, but what does it actually mean? If C++ isn’t object-oriented programming, what is? Would Java, C# and ABAP be disqualified on the same grounds as C++ was?

The quote, as it turns out, omits some crucial context about what Kay was referring to. Rewinding thirty seconds gives us the full picture:

It’s interesting to look at what is actually being done out in the world under the name of OOP [Object-Oriented Programming]. I’ve been shown some very, very strange looking pieces of code over the years […] that they have said is OOP code and written in an OOP language. And actually I made up the term object-oriented and I can tell you I did not have C++ in mind.

It turns out that Kay’s issue isn’t solely with C++ (though name-dropping it is certainly intentional), but rather how object-oriented programming had (has? is?) been implemented and embraced. One might even suggest that the quote in its most widely known form represents similar short-sightedness: focus on the minutiae over the principles, ie. quipping about C++ specifically and missing the deeper insight.

I think my personal experience of learning about (object-oriented) programming reflects the same phenomenon.

Erlang

Erlang had been my latest discovery a little before I got my first real job as a programmer. I loved how pattern matching combined with atoms and variable binding to produce an experience unlike anything I had encountered before.

1
{ok, Socket} = gen_tcp:connect("localhost", 8080, [binary]).

Erlang had strong dynamic types and functions as first-class objects. The standard library came with a number of “behaviors” that helped one implement functionality. Message passing between processes was something that I hadn’t encountered before. In a word, it was delightful.

As it turns out, there aren’t that many entry-level positions for Erlang programmers. Instead, my first programming job would be primarily in SAP’s proprietary language, ABAP. If you had asked me back then if knowing (the basics of) Erlang would be of any use in ABAP, which supports object-oriented programming, my answer would probably have been something like the following: “Well, Erlang is a functional language which doesn’t have classes. It has behaviors where you implement what you need using callbacks. It has processes which are somewhat like threads that communicate with one another by sending messages. So there’s not much that’s directly applicable, but I know about class hierarchies and interfaces, so I think I’ll manage.”

Talk about missing the forest for the trees.

ABAP

If you have never heard of ABAP, you’re not alone. As the primary language of SAP ERP, it is of significant importance to companies of all sizes, but outside of that context it is almost unknown. Not to mention that it’s not exactly developer-friendly: having an environment in which to write and execute ABAP requires one to deploy a 100GB virtual machine, though at least that can be done for free.

Before objects were introduced in ABAP, “Function modules” were the solution to reusable code modularization.

1
CALL FUNCTION 'ZHELLO_WORLD'.

Function modules were organized in “Function groups” and all function modules in a group could access shared state. This could be understood as a singleton where all state is private.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
CALL FUNCTION 'ZSET_GREETING'
  EXPORTING
    im_greeting = 'Hello, world!'.

CALL FUNCTION 'ZSAY_GREETING'.

CALL FUNCTION 'ZGET_GREETING'
  IMPORTING
    ex_greeting = lv_greeting.

* These three function call could just as well
* be three static method calls to the same class.
*
* Though in method calls, the fact that the three shared a
* class would be made clear.

However, ABAP has had support for object-oriented programming (SAP’s term is “ABAP Objects”) for over two decades now. The original, distinctly wordy syntax (which was somewhat akin to how function modules were called) has made way for a newer syntax which resembles what one would find in more typical programming languages:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
" Old syntax
DATA lo_old_greeting TYPE REF TO zcl_hello_world.

CREATE OBJECT lo_old_greeting.

CALL METHOD lo_old_greeting->say_it.

CALL METHOD zcl_hello_world=>a_static_method
  EXPORTING
    im_parameter = 'value'.


" New syntax
DATA(lo_new_greeting) = NEW zcl_hello_world( ).

lo_new_greeting->say_it( ).

zcl_hello_world=>a_static_method( im_parameter = 'value' ).

Although the different syntax does not fundamentally change anything, it makes new kinds of expressions possible:

1
2
3
4
" Chaining is allowed in new syntax, which makes 
" fluent programming (see https://www.martinfowler.com/bliki/FluentInterface.html)
" and other styles possible
cl_abap_testdouble=>configure_call( lo_testdouble )->returning( 'mocked value' ).

ABAP includes all the basic building blocks found in other object-oriented languages:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
" Interface
INTERFACE zif_gui_element.

  METHODS draw.

ENDINTERFACE.

" Class implementing the interface
CLASS zcl_gui_button DEFINITION.

  PUBLIC SECTION.
    INTERFACES zif_gui_element.
    METHODS constructor.

ENDCLASS.

" Subclass redefining some of the functionality
CLASS zcl_blinking_gui_button DEFINITION
  INHERITING FROM zcl_gui_button.
  
  PUBLIC SECTION.
    METHODS zif_gui_element~draw REDEFINITION.
  
ENDCLASS.

There are some restrictions (method parameters cannot be overloaded in subclasses and static methods cannot be redefined) but it’s mostly the standard fare when it comes to object-orient programming features.

In case your attention was drawn to class and variable names: all names not beginning with Z or Y or a customer namespace are reserved by SAP (ie. CL_HELLO_WORLD is not allowed, but ZCL_HELLO_WORLD is). Variable naming is an artifact of the bad old days: by convention variable names encode the scope of the variable (G for global, L for local) and its type (O for objects, S for structures, T for tables, V for basic types).

(As an aside, an interesting thing to note is that using static methods instead of function modules for program modularization makes no difference to the program structure: both introduce tight coupling which cannot be affected in accordance to the Open-Closed Principle. In fact, static methods might be worse because they come with static attributes. Function modules within a group can share state, but that state is private. Static class attributes introduce global state which can be accessed by anyone if the visibility permits it and if those attributes are not properly enclosed.)

Starting out

In my daily work I came to find more or less what I was expecting. Classes were created and extended by subclassing. Some interfaces existed but they were considered an unnecessary nuisance because subclassing was enough in most cases, ie. the implementations were not that different and subclassing saved implementation effort (in retrospect, the clumsiness of interfaces was partially due to how some ABAP tooling handles interfaces and partially due to how ALIAS was used in interfaces). Static methods were created for useful SQL queries and other functionality.

Looking back, I’d say that the major emphasis was on modularization and reuse. Classes were created sparingly, mostly for major objects in SAP (production order, delivery, sales order, etc). This was probably partially because of the fact that SAP provides BAPIs (APIs) for operations on certain objects (production order, delivery, sales order) which guides object discovery: often classes were just fairly spartan wrappers for BAPIs. Whenever one would need to create an instance, NEW or new followed by some initialization method was the way to do it.

Speaking of SQL, it has a special place in ABAP. Because a relational database is always part of an ABAP runtime, SQL has been made part of the language:

1
2
3
4
SELECT *
  FROM vbap
  INTO TABLE @DATA(lt_sales_order_item)
 WHERE vbeln = @lv_sales_order.

Any database table is accessible via an ad-hoc query, anywhere in ABAP. Compared to other languages, there isn’t a strong structural reason to modularize data-access layer because data-access is effortlessly possible, anywhere.

I remember that during the first few weeks, the person with the best taste when it comes to programming referred to test-driven development (TDD) as a faddish thing one used to hear about and that it wasn’t anything to pay attention to anymore. I had written some tests with eunit to verify my methods after the fact, but I figured that he knew better so I took it as a fact.

For good or ill, working with others will expose you to feedback. This could be in the form of an ad-hoc, out of nowhere flow of consciousness rant about all the things that happen to annoy someone in your code that day, or it could be a planned ritual like a code review that provides regular feedback. Regardless of how your organization handles feedback, you’ll likely discover some shortcomings about your skills and approach. It is, after all, easier to find issues in code written by others than it is in one’s own.

In my case, the feedback I got motivated me to make a number of fruitful discoveries on Amazon.

Books

If you decide to read Peopleware by DeMarco and Lister, you’ll encounter this finding under the heading of “We Haven’t Got Time to Think about This Job, Only to Do It” (2013, 11):

The statistics about reading are particularly discouraging: The average software developer, for example, doesn’t own a single book on the subject of his or her work, and hasn’t ever read one.

Peopleware was originally published in 1987 and the above quote is from my revised version from 2013. In my experience, the quote still holds: I’ve only ever heard derision when it comes to the topic of books.

Given that books weren’t held in particularly high regard – though I admittedly did not solicit any recommendations –, why did I still turn to them? Didn’t I have colleagues whom I could learn from? Quoting Liker and Meier (2007, Chapter 1):

It is often the “best” worker who is relegated to the training responsibility, but very frequently the best worker is not the best trainer and vice versa.

It’s not at all a given that the person responsible for the training of the new employee is able to impart knowledge effectively, regardless of how skillful they are at the actual work. This could be exasperated if the organization lacks code reviews and other “introspective” rituals: one is unlikely to magically develop the skill to concisely articulate good and bad practices and the distinctions and reasons behind them if one has had no practice in such beforehand. That they’d have to teach both SAP and programming would be an even heavier lift. In my case, I found books to be helpful.

So what is the surprising thing about programming quotes that I hinted at the beginning? It turns out that a few people have quite a number of them to their names: Kent Beck, Martin Fowler and Robert C. Martin, for example.

I had previously thought that books about programming were more like Algorithms, ie. Computer Science books. Books by Beck, Fowler and Martin were different: they were about the practical challenges of programming and tried to articulate how one would go about handling them and why such a solution would be appropriate. Clean Code, for example, was about the everyday problems (naming, method length, comments) whereas Test-Driven Development by Example was about the practical application of TDD. I wish someone had told me about such books much earlier; though admittedly I didn’t get much out of Open-Closed and Dependency Inversion Principles in Clean Architecture.

I found such books practical and satisfying – even though my insistence wasn’t enough to encourage all my fellow programmers to adopt TDD –, but they didn’t fundamentally change how I thought about object-oriented programming. We had class hierarchies and we used objects, that was all it took be object-oriented.

After a fair amount of reading, however, I found this paragraph by Beck (1997, 44):

Simula brilliantly combined these two ideas. Conditional code says “execute this part of the routine or that part.” A subroutine call says “execute that code over there.” A message [a method call] says “execute this routine over here or that routine over there, I don’t really care.”

And this one by Freeman and Pryce – who also quote Alan Kay on the same page – (2010, 13):

An object-oriented system is a web of collaborating objects. A system is built by creating objects and plugging them together so that they can send messages to one another. The behavior of the system is an emergent property of the composition of the objects […]

And then there was this one by van Deursen and Seemann (2019, 85):

The COMPOSITION ROOT composes the object graph, which subsequently performs the actual work of the application.

And this one by Feathers (2005, 31):

A seam is a place where you can alter behavior in your program without editing in that place.

And one in Design Patterns (Gamma et al. 1995, 20):

Nevertheless, our experience is that designers overuse inheritance as a reuse technique, and designs are often made more reusable (and simpler) by depending more on object composition.

All these quotes hinted at a different world than the one I had witnessed. As I thought about it, none of the programs I had written or witnessed up until then could be easily adjusted by jiggling the objects around.

In retrospect, I think that the most important thing that one gets out of reading Design Patterns and those other books is not any of the individual examples. Instead, they broaden one’s imagination about what can be done with objects. For example, Composite is a wonderfully useful pattern, but if most programming is done to specific classes or if interfaces are gargantuan, it’s not possible or convenient to apply it. If one thinks of classes merely as tools for conserving implementation effort (via subclassing, “implementation inheritance”) or that classes should only be created for major SAP objects, much of the power of the object-oriented programming model is lost. The result will be a whole lot of imperative code with (data) objects interspersed here and there.

Loose Coupling and Testing

Perhaps the most consequential misunderstanding that I personally had suffered from when it comes to object-oriented programming was that class hierarchies were somehow the core of the paradigm. I think I can be excused for that: “a dog is an animal, it shares features with all animals and has some that are specific to it only” -type examples of object-oriented programming were and are common enough to fool some people.

I have now seen how focus on subclassing produces terribly mangled designs and does not necessarily save much effort. I think that the focus on class hierarchies is the wrong one: what is more interesting is the indirect transfer of control and dependency inversion. Gang of Four (GoF) goes so far as to suggest “Favor object composition over class inheritance” (Gamma et al. 1995, 20). Fowler (2019, 398) has his own, more moderate version “Favor a judicious mixture of composition and inheritance over either alone”. Regardless, as Robert Martin puts it, object-oriented programming model turns a plugin-style architecture (ie. pluggable behaviors that can be composed together) from a special case into a fundamental pattern of the system. This in turn makes loosely coupled code easier to write and the fact that loosely coupled code is more testable code makes the whole enterprise worth it, in my opinion.

Descriptions “tightly coupled” and “loosely coupled” exist for a reason, however. While object-orientation makes loose coupling easier, it does not make it automatic. Not all programmers will independently discover Test-Driven Development (TDD). And given the quote from Peopleware some paragraphs back, they will also not benefit from the fact that Beck and other programmers discovered it and that tooling for TDD already exists in ABAP and other languages. In fact, if one is to believe what Douglas Crockford tells us, programmers are often actively hostile when it comes to new programming techniques: structured programming, high level languages and objects were all rejected because they were different from what came before. As Crockford puts it:

[it took a decade of debate to move from GoTo to structured programming]. Again, who better should have understood the value of structuring your programs in such a way they could scale better? Only programmers should understand the value of that argument, and programmers were the least able to understand that argument.

In ABAP, as in other languages, it is far too easy to write tightly coupled, cumbersome-to-test code (ie. not object-oriented, in a sense). NEW is the weapon of choice for creating instances of objects and it’s far too tempting to do too much in the constructor method, thought that’s not too different from other object-oriented languages.

What is uniquely bad in ABAP is the ubiquity of SQL. Because an ABAP program always has a database session as its companion, there is no natural limiting force for deterring the use of SQL anywhere and everywhere (excluding cases where SQL is written poorly or when SQL ends up in a tight loop, both cases resulting in performance issues). This means that SQL is everywhere, which means that volatile dependencies are everywhere. This in turn means code is not easily testable, neither automatically or by a programmer. (van Deursen and Seemann 2019, 26)

This, in turn, produces something like the following dynamic:

Diagram of Effects - Automatically testable code

This Diagram of Effects – in the vein of those used by Gerald M. Weinberg in his Quality Software Management series – is to be understood as follows: each arrow means that an increase in the source cloud leads to an increase in the target cloud. And vice versa: a decrease in the source leads to a decrease in the target cloud. (Weinberg 1992)

Put another way, a vicious cycle. If an organization has not previously seen much value in creating code that supports automated testing, it is quite likely that the resulting codebase would require extensive changes to add support for automated testing. It could even be that nobody knows how one would go about writing automatically testable code. Given how high the effort of having a codebase covered with automated tests is perceived to be, the effort is spent elsewhere and the positive effects of automated tests are never recognized and the organization has no motivation to embrace them.

Put yet another way, a virtuous cycle. Quoting Freeman and Pryce (2010, 5):

[…] TDD turns testing into a design activity. We use tests to clarify our ideas about what we want the code to do. […] If we write tests all the way through the development process, we can build a safety net of automated regression tests that give us the confidence to make changes.

TDD just requires developing a new habit, after which the old way of writing code seems positively silly. This also aligns with the diagram of effects: as one sees how writing automatically testable code is beneficial, one is more motivated to do so and will also learn how to better write it. After you realize how much easier and faster TDD makes things, it seems crazy to have to create an IDoc or a production order just to test something.

But since the dynamic is naturally a vicious cycle, change would require conscious intervention. And according to the previous quotes from Peopleware and Douglas Crockford, it’s not at all a given that anyone with authority (be it formal or informal) will recognize the dynamic or what could be done about it. Likewise the fact that tests would decrease the risk of refactoring and thus make design improvements and other good practices easier will not be considered.

There are also old ways of testing that hinder the adoption of TDD-style automated testing. Function Modules, which I mentioned as the old solution for modularization, are all public. Any function module can be called by anyone, whether it makes sense or not (there is a “Released” -attribute intended to signal the stability of a function module interface, but that is a metadata field, not a language-level mechanism). SAP provides a way to test function modules directly:

F8 - Execute Function Module

This simple form allows one to provide inputs and see what outputs are produced. It is really handy when trying to figure out what a function module does.

Methods of a class can also be tested like Function Modules, though only public methods. This leads in some cases to situations where all methods of a class are public so that they can be called via this test form. This eliminates the effectiveness of class member visibility in restricting dependencies and information hiding and also pollutes class interfaces with internal methods, making them harder to understand and use.

Most consequential negative outcome of relying on this form-based method of testing is that it is not automated: ie. all test variations need to be run by hand and the person running the tests needs to know what parameters to use and what to expect in return and needs to recognize errors by eye. Testing all methods of even a small class becomes such an arduous task that it is only done rarely, if at all, and the tests might vary from one run to the next, hiding regressions and other bugs. It provides the veneer of testability while making testing so tiresome that it will be actively avoided.

In contrast, correctly practiced TDD solves all these problems: tests codify what should happen, programmatically verify that it happened as it should have and are quick to run.

I use TDD as an example because I think it’s one of the most concrete and obvious benefits of the loose coupling which is achievable with object-orientation; Open-Closed and Dependency Inversion principles and others are more involved and harder to appreciate.

ABAP, Patterns and xUnit

Although ABAP has some notable shortcomings (no generics, no parameter overloading) when compared to other object-oriented languages, it also has some marks in its favor. For one, ABAP has builtin support for the Observer pattern.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
INTERFACE lif_data_source.

  EVENTS data_changed.

ENDINTERFACE.


CLASS lcl_view DEFINITION.

  PUBLIC SECTION.
    METHODS handle_data_changed FOR EVENT data_changed OF lif_data_source.

ENDCLASS.

Interestingly, events in ABAP are not actually really used for Model-View-Controller (MVC)-architectures: apps with GUIs tend to stick to mixing all three together (with predictable results). Instead, events in ABAP are used like callbacks or event listeners. Typical example can be found in the venerable ALV Grid:

1
2
3
4
5
6
DATA(lo_alv_grid) = NEW cl_gui_alv_grid( ).

SET HANDLER: lo_strategy->handle_toolbar      FOR lo_alv_grid,
             lo_strategy->handle_user_command FOR lo_alv_grid,
             lo_strategy->handle_double_click FOR lo_alv_grid,
             lo_strategy->handle_data_changed FOR lo_alv_grid.

The generic ALV Grid raises a few basic events (some of which have objects and other values as parameters) for which a developer can define a handler (ie. a Strategy) and then the program can react to double clicks as necessary and add custom functions to the toolbar by calling methods on the event paramer object. The same could have been achieved by passing the alv grid an object to which it would delegate events but SAP elected for this approach.

In custom developments the use of events varies. Often they’re not used at all, even in UI-related code. And I think I’ve yet to see an example of events having been used has callbacks/hooks to customize code behavior.

ABAP also has an xUnit implementation with support for mocking: ABAP Unit.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
CLASS ltc_test_class DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.

  PUBLIC SECTION.
    METHODS happy_path FOR TESTING.

  PRIVATE SECTION.
    DATA o_dependency TYPE REF TO if_some_global_interface.
    METHODS setup.

ENDCLASS.

CLASS ltc_test_class IMPLEMENTATION.

  METHOD setup.

    " Per-test setup

    " A Stub for testing. Call to get_name() will return 'foobar'.
    o_dependency ?= cl_abap_testdouble=>create( 'IF_SOME_GLOBAL_INTERFACE' ).
    cl_abap_testdouble=>configure_call( o_dependency )->returning( 'foobar' ).
    o_dependency->get_name( ).

  ENDMETHOD.

  METHOD happy_path.

    cl_abap_unit_assert=>assert_equals( act = o_dependency->get_name( )
                                        exp = 'foobar'
                                        msg = 'Returned value should be foobar' ).

  ENDMETHOD.

ENDCLASS.

Also, probably as an indirect admission that SQL everywhere was a mistake, ABAP has a construct called “Test seams”:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
CLASS cl_helper DEFINITION.

  PUBLIC SECTION.
    CLASS-METHODS get_custom_field
      IMPORTING im_material TYPE matnr
      RETURNING VALUE(r_result) TYPE string.

ENDCLASS.

CLASS cl_helper IMPLEMENTATION.

  METHOD get_custom_field.

    TEST-SEAM get_custom_field_select.

      SELECT SINGLE zcustom_field
        FROM mara
        INTO @r_result
       WHERE matnr = @im_material.

    END-TEST-SEAM.

  ENDMETHOD.

ENDCLASS.

CLASS ltc_test_helper_class DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.

  PUBLIC SECTION.
    METHODS get_custom_field FOR TESTING.

ENDCLASS.

CLASS ltc_test_helper_class IMPLEMENTATION.

  METHOD get_custom_field.

    TEST-INJECTION get_custom_field_select.
      r_result = 'Some value'.
    END-TEST-INJECTION.

  ENDMETHOD.

ENDCLASS.

Test seams allow the developer to substitute some named section of code during testing. While this might seem like a cool feature, it has a number of downsides: because code is inserted directly, the test is tightly coupled to the implementation of the method. Ie. changes in local variable names and types will break the tests. In short, test becomes too interested in the inner workings of the method (implementation details) rather than the results of the method. Also, the test seams need to be configured per test method. Due to their low-level nature (and especially when SQL is involved), it is easy for the clarity of tests to suffer as the big picture gets swamped by the minutiae.

As I said previously: I think test seams are just an admission that a terrifying amount of ABAP code is just about impossible to automatically test without drastic changes to their existing architecture. Test seams are a cludge for making legacy code testable, though not a great one: given how unlucky one is, the number of test seams could be significant if one tries to cover all SQL in a given module. Some Slide Statements refactoring might help, but given that refactorings also ideally require that the code is covered by tests, well… Egg, meet chicken.

SAP has also introduced support for SQL Doubles in later versions. These allow the contents of database tables to be mocked and thus the code can be tested as-is, with Open SQL statements in place. Given that these can transform the volatile database dependencies into statements with deterministic results, they are a significant step towards making traditional ABAP more testable. While SQL Doubles help with the kinds of simple ad-hoc queries that litter ABAP codebases, BAPIs and other complex functions still need be behind seams because trying to figure out which tables exactly are used by a given function module is a significant amount of work and only an implementation detail. Ie. SQL Doubles are not a substitute for creating a testable architecture.

Object-Oriented Programming

As I realized that class hierarchies were not actually the essence of object-oriented programming, I also started to appreciate the ways in which Erlang was not actually that foreign to it (you can see Joe Armstrong and Alan Kay saying something to that effect here). Behaviors like gen_server are an example of Open-Closed Principle: they can be customized with developer-provided strategies (callbacks) without changing the original code. They are also an example of indirect transfer control. Messages sent between Erlang processes are like method calls, although the independent execution of each process means that the traditional transfer of control does not take place.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
% This is somewhat like a method call from one object to another,
% except that there's no static type (interface) and both processes
% continue execution independently.

Ref = make_ref(),
Object ! {self(), Ref, say_something},
receive
  {Object, Ref, Greeting} -> do_something_with_greeting(Greeting)
after
  2000 -> error(no_response)
end.

Had I not been so hung up on the technical details, I might have appreciated the patterns and principles at work in Erlang and OOP. Then again, because I had not yet read the books that made me realize the similarities, I probably would have not recognized them.

I think this relates back to what Peopleware and Crockford were saying: the obstacles and solutions are not mostly technical, but social/mental. Thus bringing the technical support for objects or TDD into ABAP will not magically and substantially increase the quality of the code that is produced. Instead it would require people to change their ways of working and that’s a different type of challenge. Ie. Kay’s issue was not necessarily the design of the C++ language, but how it was used to produce designs that were not actually all that object-oriented (although it could be that the design didn’t do much to help; this isn’t meant to be a snide quip, I honestly don’t know enough about C++ to have an opinion).

Hearing that people who have programmed for a living for over decade have barely read a book about programming might shock you, but I think it makes sense, in a way. Weinberg (1997, 19–54) introduces the Satir Change Model. According to the model, the status quo of a system tends to be stable until a crisis/foreign element disturbs it (this “crisis” could also be a realization that things have been in a poor way for a long time). After the system has been disrupted, it’ll have to transform to find a new status quo or accommodate the foreign element to return to the old status quo. Given that the foreign elements in the SAP consulting business are typically not programming related, there’s usually not a high incentive to adapt programming-related practices. And what new practices are adapted, for example new ABAP syntax, are convenient but don’t really transcend the previously existing paradigm.

As for why programmers more broadly seem to shun reading, I haven’t the foggiest idea. I’d imagine that some problems would be related to programming, but maybe not. Here’s what DeMarco and Lister (2013, 4) have to say:

In fact, that idea [that people-related problems cause most of your trouble] is the underlying thesis of this whole book: The major problems of our work are not so much technological as sociological in nature.

In retrospect, I think it’s fitting that discovering design patterns and TDD made me better appreciate what Kay meant when he was talking out OOP. Both design patterns and TDD were popularized by Smalltalk programmers (I think both Beck and Fowler have background in Smalltalk) and are basically discoveries of imagination in how objects can be used to construct software. Whether they are the result of the structure of the Smalltalk language or the group of people that worked in Smalltalk, I don’t know. For one, Alan Kay and other proselytizers of OOP were more tightly involved with Smalltalk than with other languages. Then again, if you’ve ever had a look at Smalltalk, it looks quite different from ABAP and Java. For example, there’s no special constructor method, only conventions for creating instances. This has the effect of lessening the temptation to create an all-powerful constructor method that both creates new sales orders and reads existing ones and thus allows for a more flexible conception of object creation. Likewise, what are interfaces is ABAP are conventions in Smalltalk: objects either understand the messages they receive or not. Dependency inversion is a natural outcome from this.

Onwards

Back when I interviewed I probably should have asked which programming related book my interviewers found particularly insightful. Not as a gotcha, even “Design Patterns” would imply that they had at least been exposed to somewhat more imaginative ways of using objects and structuring programs. Vice versa, failure to come up with any could signal a Not invented here -type culture, though that’s probably not an absolute truth: in the end, programming is a lot more fun than reading about programming and it might be hard to resists that siren song. Though that’s again a kind of example of “We Haven’t Got Time to Think about This Job, Only to Do It” from Peopleware.

It’s been interesting re-discovering object-oriented programming after Erlang. Or maybe I should say, actually discovering object-oriented programming for the first time. At times it’s been as interesting and fun as when one first writes something in C. The fact that I thought I knew what OOP was about while not really understanding what OOP was about makes one wonder about other gaps in my knowledge.

Sources

  • Beck, K (1997) Smalltalk best practice patterns. Prentice Hall. 978-0-13-476904-2.
  • Beck, K (2003) Test-driven development: by example. Addison-Wesley. 978-0-321-14653-3.
  • DeMarco, T – Lister, T. R. (2013) Peopleware: productive projects and teams. Addison-Wesley. 978-0-321-93411-6.
  • Feathers M. C. (2005) Working effectively with legacy code. Prentice Hall Professional Technical Reference. 978-0-13-117705-5.
  • Fowler, M. (2019) Refactoring: improving the design of existing code. Addison-Wesley. 978-0-13-475759-9.
  • Freeman, S – Pryce, N (2010) Growing object-oriented software, guided by tests. Addison Wesley. 978-0-321-50362-6.
  • Gamma, E. – Helm, E. – Johnson, R. – Vlissides, J. (1995) Design patterns: elements of reusable object-oriented software. Addison-Wesley. 978-0-201-63361-0.
  • Liker, J. K. – Meier, D. (2007) Toyota talent: developing your people the Toyota way. McGraw-Hill. 978-0-07-147745-1.
  • Martin, R. C. (2018) Clean architecture: a craftsman’s guide to software structure and design. Prentice Hall. 978-0-13-449416-6.
  • Martin, R. C. (2009) Clean code: a handbook of agile software craftsmanship. Prentice Hall. 978-0-13-235088-4.
  • van Deursen, S. – Seemann, M. (2019) Dependency Injection: principles, practices, and patterns. Manning Publications. 978-1-61729-473-0.
  • Weinberg, G. M. (1992) Quality software management, Volume 1: Systems Thinking. Dorset House Pub. 978-0-932633-22-4.
  • Weinberg, G. M. (1997) Quality software management, Volume 4: Anticipating Change. Dorset House Pub. 978-0-932633-32-3.