I guarantee you have used software that is the output of a Software Product Line. If you have got an Android phone, tablet, or audio player; use Linux on your desktop, laptop, set-top box, smart home device, Wi-fi router, server, or cloud computing provider; or you use a web application that is hosted on Linux, then you have used a Linux kernel. Not the Linux kernel, as there are many Linux kernels.
When you build a Linux kernel (or someone builds it for you), an important step is configuring the build. The project uses a domain-specific language called kconfig to define various parameters and feature settings. You (or the person who does it for you) choose what features you want in the kernel, and what values you want for the other parameters, and those define the way that the build system builds a (not the) Linux kernel for you. The kernel build system is a factory, Linux is a software product line, and the specific Linux kernel you build is a product in the product line.
Or, as Don Batory points out in the important, if somewhat idiosyncratically written, “Science of Software Product Lines”, the output of kconfig is the Linux kernel you might build, if you get lucky. 87% of the configurations you can create using kconfig result in a product that does not even compile. Clearly Linus Torvalds needs to read this book.
Much of the time, software designers think about features and about codebases as orthogonal concerns. Yes, “the business” wants me to add a feature to the code, so what I am going to do is to read the code and work out some changes to make that I think integrate the feature into the existing ball of mud architecture. OK, maybe they want me to soft-launch the UI behind a feature flag, so I will find some places where I can put if(featureIsEnabled) into the code so that the feature gets turned on when the flag is set.
Technically, that product with the feature flags in is really a software product line. Each person gets their own version of the product determined at runtime, based on the state of the collection of feature flags defined for that person. But, like the Linux kernel, the creators of that feature-flag-rich app have not read “Science of Software Product Lines”, so they are not getting the full benefit of decades of research in the area.
Those of us with long memories—or who still build venerable GNU projects like Emacs or GCC from source—remember the “fun” to be had with the GNU autotools, specifically GNU autoconf and GNU automake. The concept was simple: you could make your software both portable, and flexible, by defining macros that configure build settings and enable or disable features. In fact, and perhaps surprisingly, it did not work like that at all. What it did was to inspect the target system and the options someone used to run the script, and define a collection of configuration points that instruct the build system to create different products, with distinct feature sets and internal behaviour. Yes, that is right, a GNU autoconf build system defines a software product line, and none of us had read Don’s book, either. How could we? It was published in 2026.
The typical way that autotools projects configure a software product line is to provide C preprocessor macros that the compiler uses to conditionally include or exclude feature code, switch implementations of routines, or set concrete values for abstract ideas, like the size of a memory region. Batory shows us that the C preprocessor (CPP) is one of the most powerful and capable tools available for creating software product lines—and also one of the most dangerous, as its text-substitution approach readily leaves code in an uncompilable state, particularly when features compose in unexpected ways (hence the dice roll every time you try to configure the Linux kernel). This mess is to the compiler what DLL Hell is to the runtime environment.
His book shows the theory behind slicing software by feature, and composing the code fragments that add features, and the second-level code fragments that ensure two features play nicely when they are both selected. He shows that a feature map is the space of all possible software products that a software product line produces, and that it is finite, even if potentially humungous; the Linux kernel SPL has far more possible configurations than the number of particles in the universe (when I worked at Facebook in 2014, so did the set of feature flags in their mobile apps).
He shows practical tools, like the X15 refactoring engine that uses Java annotations to build and transform SPLs in semantically valid ways. He demonstrates how object-oriented modelling can yield flexible designs that are amenable to supporting SPLs; including novel OO capabilities as in the BETA programming language. BETA is similar to the SIMULA language, but inheritance runs in the opposite way than you are used to. A parent class can inherit behaviour from its subclasses, and include instructions in its method definitions that tell the runtime to invoke the subclass’s implementation of the method. It is no surprise that OOP is a great technique for building SPLs from components, given that Brad Cox showed us how to do this with Software ICs, and how to monetise it with Superdistribution.
By far the most interesting chapter is towards the end, where Batory lists open challenges in SPL research with their complexity, reading like the higher-difficulty “exercises” in “The Art of Computer Programming”. These range from the most modern of 2026 challenges (how to work with SPLs in the LLM era) to the most basic and surprising of fundamental knowledge gaps: nobody has ever provided a scientific basis for believing that modularity is beneficial in software design. Even the most worthy of luminaries, Edsger Dijkstra, axiomatically accepts “the separation of concerns” as a good idea, as if its alternative is something that should be considered harmful with no further thought. This, ironically, in a paper called “On the role of scientific thought”!
Cover photo by the author.