Scribus Exploration III: Composition Over Inheritance
Sunday, June 9, 2019 at 4:33pm
One principle of good software design is to "prefer composition over inheritance." For the non-software engineers reading this blog, allow me to explain.
Early in a software engineer's career, they will be exposed to inheritance as a concept. This is essentially a means of avoiding writing the same code multiple times. For example, say you have an RPG monster system, and the first task is to implement goblins, ogres, and bats. All of them need to attack, they all need hit points, and they all need a defense rating. Instead of writing those features three times, once for each monster, the engineer instead creates an "abstract" monster, and then makes the goblin, ogre, and bat "inherit" all the properties and abilities of a "monster." Now, if, say, the engineer needs to define the magical abilities of monsters, they can write the code once instead of three times. And, if the designer wants a change to the algorithm that determines how much damage negation the monsters' defense rating provides, the engineer can code it in one place instead of three.
But inheritance comes with a nasty downside. Let's say the team expands the monster system. The designers add venom bats and hawks, and they want flying monsters to have special properties that other monsters don't. Well, okay. The engineer can create another abstract "flying monster" that inherits from abstract "monster" and make the bats, venom bats, and hawks inherit from it. Meanwhile, the designer has added cobras, blobs, demon fish, eels, and sharks to his list. The engineer decides to create an abstract "aquatic monster" for demon fish, eels, and sharks, and everything seems fine, until they discover the designer's next feature. The designer wants venom bats, cobras, and eels to inflict a status on their attack targets called "poison."
With inheritance as a solution, there is no good way out of this bind. The engineer could put "poison" on the abstract "monster" and then, essentially "turn it off" on all the monsters that don't need it. The technical name for this coding mistake is "refused bequest." What eventually happens is that someone who doesn't know the system will add a new monster and not know that they have to turn off the poison property. The end result is a bug in which a monster will start spewing poison that's not supposed to.
If this seems like minor annoyance, imagine what happens when a bundle of abstract code becomes an enormous dumping ground of features that need to be individually modified, toggled off, hidden, or overridden whenever a new concrete implementation is added to the system.
The better solution is to avoid inheritance altogether in this case, saving it solely for situations where all of the inheritors are using the abstract functionality exactly as it is, with no exceptions. Instances where inheritors implement variations on a theme should be handled with "composition." Here's how that would work in our example. The engineer would define a "status effect afflictor" property for all monsters. The engineer then creates a "poison status afflictor" and a "nothing status afflictor." The engineer gives the venom bat, cobra, and eel the poison status afflictor and all the other monsters the nothing status afflictor. Now, all of the monsters have an afflictor, so they are all legitimately abstract monsters. Whenever someone creates a new monster, they must explicitly choose to give it the poison afflictor, the nothing afflictor, or to make a new afflictor. If they don't, their code will refuse to compile. This is much better than discovering a bug after the fact.
I realized, after writing yesterday's blog post, that InDesign and Scribus master pages are essentially a kind of layout "inheritance." When using InDesign, if individual pages need slight adjustments to master elements, the workflow supported by the tool is to break that element out of the master page and make individual modifications. This is the book layout equivalent of a refused bequest.
In Scribus, your master page elements are all locked. Individual pages cannot alter the master pages elements they inherit in any way. The tool Scribus provides in order to affect minor differentiation against similar-ish page elements is the scrapbook, a piece of functionality utterly absent in InDesign.
It doesn't look like much, but this is an extraordinarily powerful and time-saving feature. My master pages for Shipwright are now minimalist, containing only the few elements that do not vary at all throughout the document, and the guides for placing others.
Notice that I've removed any story-specific master pages. Those elements are now in my scrapbook. The scrapbook lets me quickly place unlinked instances of a template, make small modifications, and reuse those across of swath of pages, but not necessarily all of them. In other words, Scribus's scrapbook taught me to design books in a way similar to how I use composition when programming. InDesign teaches you to rely on using inheritance poorly.
Now, if this seems like an esoteric or philosophical grievance merely, allow me to relate the practical effect of Scribus's design decision. When laying out the most recent story in The Shipwright, I was able to create a number of pages, then quickly go through and apply the scrapbook object for that story to each spread (this requires only clicking on the page to be affected and then double-clicking the scrapbook object), then quickly linking the text through the document with the n key binding that I mentioned in yesterday's post. This workflow represents a large time savings over the same process in InDesign. Over the course of however many novels I will write in the future, the time savings will be enormous.
Also since the last time I wrote, I exported a PDF file from my Scribus, which produced a file of the quality I expect, with the fonts properly embedded. My last major concern with using Scribus as my primary tool has been alleviated.
Bonus Points for Scribus
The scrapbook feature, which allows me to compose my page variances, rather than breaking the forced inheritance of master pages.
I've noticed some weird things happening with my text. In one case, some italic formatting disappeared inexplicably. It's possible I've just not learned the quirks of the story editor. I'm relatively certain I just need to figure out what I did to cause this.
This will be my last post in this series. I set out to determine whether a Scribus workflow could replace the InDesign workflow I was accustomed to. It has done one better than that. Scribus has taught me a better workflow for print layout and design.