Skip to main content

Design Patterns: The Inverse Extension Design Pattern

I wrote an article for Linux Journal called The Inverse Extension Design Pattern.

Comments

jjinux said…
Crazy, it took me a year and nine months to get that article published!
jjinux said…
> Thanks for your reply.

Thanks for your patience as I try to explain what I'm talking about.

> It gives me some idea of what you are getting at. However, on the basis of your reply I wouldn't be able to write down an example of the class of problems that Inverse Extension solves. I'm still puzzled as witnessed by the following questions.
>
> Does the Layout class encapsulate the common look and feel?

Yes, a Layout does encapsulate the common look and feel. By "common look and
feel", I mean that all of our apps look and behave pretty much the same. In my
code, I've used the term Layout pretty much as an interface.

> Do I understand you correctly that the hierarchy is as follows, :- indacting subcalssing, Layout :- Application :- Section :- Page?

Well let me step away from the hypothetical and talk about an actual class
hierarchy (top to bottom). Screens are the main content. Layouts are pretty
much any parent of a screen. I'll start with the layouts, and at the bottom
are the screens.

In Aquarium, which is my open source framework:

Bare -- This class understands content types, HTTP headers (including turning
on or off HTTP caching), etc.

Some subclasses in your app might include a screen that generates an XML
report or a screen that generates a dynamic image containing a graph.

HTML -- This is mostly for people who want to type the HEAD, HTML, BODY,
etc. tags themselves. It knows that it has content type text/html.

CssAndJavaScript -- This class knows about the basic layout of HTML. It has
methods for the title, CSS, JavaScript, etc. that can be overriden. It uses a
bunch of defaults that are defined in a properties file. It's here so that I
don't have to duplicate boilerplate.

Simple screens supclass from CssAndJavaScript when I'm trying to get a
message out without caring about look and feel. Consider the screens that
Apache uses for 404, etc.

Now, from within my common look and feel code, which is used by multiple apps
at my company:

Sparse -- This is the layout used for content where you don't want to show the
tabs.

The login screen, the help screens, the app-specific 404 screen, etc. all
extend from here.

Complete -- This layout contains the complete navigation, including tabs.

Most of the screens in the application extend from this. Most of apps
that use my common look and feel use this as their main layout.

Cluster -- This layout knows about extra navigation needed for clustering
(which we've unfortunately used as a misnomer for centralized management).

Only some of my apps need to worry about clustering. In those apps,
screens use this layout instead of the Complete layout.

Now, for actual screens:

various screens -- At the lowest level are the various screens. The basic idea
is that you start a screen by picking how much you want your parent class to do
for you automatically. You can always override methods defined in your parent
classes that it sets up for you to override, such as getTitle. You usually try
to pick the most specialized layout (e.g. Cluster or Complete depending on
whether or not your app supports clustering), however, certain screens need to
assert more control. For instance, it makes no sense for an XML report to
subclass the Cluster layout.

> Are Screens and Pages synonyms?

Yes, sorry about that. Screen is the actual "interface". I used page as a
synonym although there's nothing actually called page in my code.

> If not, where does Screen fit into this model?
>
> What is a Section ? I.e. what does it represent?

Now that I've laid out a concrete class hierarchy, let's just drop the
hypothetical stuff.

> How do these classes relate?

All those classes above extend from one another.

> What is the behaviour?

Based on inverse extend, each higher level class's __call__ method gets called.
Whenever it's ready, it passes off control to the child class's __call__
method. Hence, the parent classes "wrap" the child classes. This really makes
sense in HTML.

(It's also useful in a couple other contexts. Imagine a parent class that
checks access restrictions beforing allowing access to the child class. Note,
the parent class can prevent the child class's __call__ method from running at
all by simply refusing to call callNext! I have found this to be a useful
technique.)

> I.e. what methods are involved,

Everyone has a __call__ method (which is a Pythonism).

> what do they do and how do they call eachother?

Layouts look like (pseudocode):

class CssAndJavaScript(HTML):

def __call__(self, callNext):
# do stuff, like include the navigation
callNext(*args, **kargs) # Let the subclass do its stuff.
# do more stuff, like include the copyright footer

Screens look like (pseudocode):

class MyScreen(CssAndJavaScript):

def __call__(self):
# Do my main content

> What is its public interface?

In Aquarium, it's easy. Everyone has a __call__ method.

> What is its context?

I have the notion of a context, but I'm pretty sure it doesn't match what
you're asking about. The important thing is that the child class's __call__
method is called by the parent class's __call__ method in order to do its work
at just the right time.

> How does a client use an Layout instance? How is a page ulimatally displayed?

Well, Aquarium uses Cheetah for this. Here's a simple screen:

| #extend aquarium.layout.Cluster
| #implements __call__
|
| Hi! I'm a simple looking screen, but my parent automatically takes care of
| outputing all the common look and feel!

When you load a URL in the browser, Aquarium maps the URL to a particular
screen. Then it calls inverseExtend on that screen's __call__ method. Hence,
the parent class gets to do work, and then it passes control down the
inheritance hierarchy, until finally the screen gets to output its main
content.

> What do the doCommonLookAndFeel, doApp, doSection, doScreen do?

Dropping the hypothetical names.

> Return html?

Yes, actually they do. Hence, the parent class can take that HTML and do
whatever it wants with it.

Popular posts from this blog

Drawing Sierpinski's Triangle in Minecraft Using Python

In his keynote at PyCon, Eben Upton, the Executive Director of the Rasberry Pi Foundation, mentioned that not only has Minecraft been ported to the Rasberry Pi, but you can even control it with Python . Since four of my kids are avid Minecraft fans, I figured this might be a good time to teach them to program using Python. So I started yesterday with the goal of programming something cool for Minecraft and then showing it off at the San Francisco Python Meetup in the evening. The first problem that I faced was that I didn't have a Rasberry Pi. You can't hack Minecraft by just installing the Minecraft client. Speaking of which, I didn't have the Minecraft client installed either ;) My kids always play it on their Nexus 7s. I found an open source Minecraft server called Bukkit that "provides the means to extend the popular Minecraft multiplayer server." Then I found a plugin called RaspberryJuice that implements a subset of the Minecraft Pi modding API for B

Ubuntu 20.04 on a 2015 15" MacBook Pro

I decided to give Ubuntu 20.04 a try on my 2015 15" MacBook Pro. I didn't actually install it; I just live booted from a USB thumb drive which was enough to try out everything I wanted. In summary, it's not perfect, and issues with my camera would prevent me from switching, but given the right hardware, I think it's a really viable option. The first thing I wanted to try was what would happen if I plugged in a non-HiDPI screen given that my laptop has a HiDPI screen. Without sub-pixel scaling, whatever scale rate I picked for one screen would apply to the other. However, once I turned on sub-pixel scaling, I was able to pick different scale rates for the internal and external displays. That looked ok. I tried plugging in and unplugging multiple times, and it didn't crash. I doubt it'd work with my Thunderbolt display at work, but it worked fine for my HDMI displays at home. I even plugged it into my TV, and it stuck to the 100% scaling I picked for the othe

Creating Windows 10 Boot Media for a Lenovo Thinkpad T410 Using Only a Mac and a Linux Machine

TL;DR: Giovanni and I struggled trying to get Windows 10 installed on the Lenovo Thinkpad T410. We struggled a lot trying to create the installation media because we only had a Mac and a Linux machine to work with. Everytime we tried to boot the USB thumb drive, it just showed us a blinking cursor. At the end, we finally realized that Windows 10 wasn't supported on this laptop :-/ I've heard that it took Thomas Edison 100 tries to figure out the right material to use as a lightbulb filament. Well, I'm no Thomas Edison, but I thought it might be noteworthy to document our attempts at getting it to boot off a USB thumb drive: Download the ISO. Attempt 1: Use Etcher. Etcher says it doesn't work for Windows. Attempt 2: Use Boot Camp Assistant. It doesn't have that feature anymore. Attempt 3: Use Disk Utility on a Mac. Erase a USB thumb drive: Format: ExFAT Scheme: GUID Partition Map Mount the ISO. Copy everything from