About Abstract

Introduction
Philosophy
Design Goals






Introduction

There's just got to be a better way.”

Abstract lets you maintain a single source code tree of a typical GUI application and easily build it for different platforms (namely Win32, OS X and Linux). It offers a platform-agnostic API that can be treated as being “the platform”.

One must settle for the lowest common denominator of what all operating systems provide. However, the common denominator has evolved to a good point.

People familiar with various systems (Mac, Windows, Be, NextSTEP, MFC, etc.) may see familiar design patterns. This is entirely normal -- a lot of good ideas already exist and it would be foolish to ignore them or think that all of my ideas were somehow best.



Philosophy

Most frameworks try to offer all the things that operating systems do. This is wrong, because at a higher level of abstraction, the typical developer is interested in fewer features.

Abstract's approach is to focus on the things that a typical application needs most of the time, and then provide ways to do those things with the least amount of effort and without coupling tightly to the OS.

The typical modern OS has somewhere in the neighbourhood of 5,000 API functions. The typical application might use 500 of them. An OS must be rich because it must be all things to all people. An application is itself an abstraction, because it presents only a hundred commands or so to its users, and offers only a subset of the potential problem-solving ability of the entire OS. But it is exactly this narrowing down that makes applications valuable. They don't do everything, but they automate considerably the things that they do handle.

Here's an example. Want a splitter bar between two windowpanes? Well, normally you would explicitly code for that functionality. But if the panes in question are resizable, and you've placed them next to each other in a parent window, the bar can be automatic. There's no need to provide any more information, because the attributes of the windowpanes themselves are indicative enough of how the interface should behave. If you don't want the splitter bar, you don't think “remove the bar”. Instead, you think “make the panes fixed in size so that there is no logical need for resizing them.” At this level, the entire concept of splitter bar has moved from your solution domain down to the system. It's a feature that falls out as a simple logical consequence of the things you do have to mind (like viewpanes), and it's one less thing to worry about. Or to put it another way:

Nobody wants splitter bars.
What they want is for users to be able to resize windows.


Here's another example. Consider a window showing a subset of some datum. Traditionally, one adds scrollbars to the window and then writes a bunch of code to allow panning and maybe zooming. But the truth is:

We should be able to just indicate the datum's size.
The system already knows how large the window is.
And while we're at it, mouse positions should be reported in datum coordinates.


Now this is what an application framework is for. Not to be too high-level (like providing scenegraphs, of which there are many kinds), but by automating the tasks immediately above the OS, like relating datum space to window space.

One more example. Let's say you need to display a dialog box to get a set of information from the user, like his age, weight, and height. So you design the box and add various widgets to it. But in reality:

I just want to ask the user his age, weight, and height.
Given the types of each item, their order, their allowable ranges and descriptions,
the system should be able to produce the dialog box on its own.


Traditional frameworks tend to closely mimic the OS APIs they replace. Dialog boxes, GUI widgets, windows and the like don't go away; they just take on different names and different APIs. There's no real fundamental change in the abstraction model. By more properly describing intentions, more UI issues can just “fall out” as a logical consequence.

In Abstract, there's much less code regarding details. In Abstract, you don't think of menus, windows, dialog boxes and scrollbars. You think of commands, datum renditions, user questioning and datum space.

You get to focus on:



Developing in Abstract can be initially difficult, because it requires continual, conscious effort to keep design and implementation separate. This is hard not because people resist or dislike doing so, but rather because it is difficult to always know what exactly constitutes design vs. implementation -- the line separating them is fuzzy.

Engineers are also notorious for imagining the solution to a problem while imagining the problem. Instead, you need to sit back, relax, and focus on how the solution exists independantly of any particular implementation. Or better still, focus on what you want to accomplish and keep it seperate from how it is to be accomplished.

For example, your program may offer several commands. Think of the commands solely on their own terms, instead of worrying about what names they have, in which menus they belong, what their keyboard shortcuts will be, etc. Those things are all implementation details. Focus instead on what the commands actually do, and what data they need in order to be treated as persistant objects (so that you can implement full Undo/Redo for free).



Design Goals

Abstract is intended to achieve the following:





Rollout Plans

My initial need for Abstract was to port my products to Mac and Linux (in that order). However, the likely rollout phases are:



Some of these steps will overlap since they are not strictly dependant on each other. Abstract requires Unicode services so there is no guarantee that it will work on Windows 9x. The improved stability of Windows 2000 and Windows XP, however, are making them the platforms of choice for most Windows users. With a little extra work, however, a non-Unicode version of Abstract capable of running on Windows 9x is possible.

The nature of the test application is undecided. Leveller has a set of heightfield rendering features that should be moved to a standalone rendering program, so that is one possibility.

There are obstacles to abstraction. Either an assumption is unwarranted (poor design), or more commonly, an implementation is insufficient and must be worked around (poor implementation). Java is a textbook case of the latter: the promise of “write once, run anywhere” devolved into “write once, debug everywhere”. Since Abstract is not fully implemented, we have the opportunity to get it right in the design phase. Since Daylon has no commercial interest in Abstract, there is no market pressure to rush and compromise.



Drowning in Metadata

A main impediment to abstraction is that datasources need to be described so that runtime engines can take on more of the presentation burden. This means using -- ugh -- metadata, which means that developers can't just “hop to it” when they code; they have to stop and describe what their programs are storing. This is particularly true for more novice developers who haven't worked on larger systems where abstraction protocols are desirable. As a result, Abstract is admittedly not good for small programs.

Two things are clear: metadata is unavoidable; without it, the framework would have to be an AI in order to accomplish its tasks. But metadata must also not be required solely for its own sake; a proper framework should not pester developers to overdescribe elements ad nauseum.



Seeking Balance - A Philosophical Detour

The challenge of abstraction (or intentional programming) is related to the problem of dualism: in a real sense, resolving the infinite with the finite. When one conceives of an abstract process, it becomes a timeless solution, and is thus temporally infinite. In the real world, however, computers are physical devices that must implement their behavior in real, specific ways, with finite limits. Numbers cannot span any arbitrary range and have infinite precision; memory storage is not infinite; execution speed is limited, etc. So whatever we conceive of in the abstract must somehow be mapped to the physical; and it is precisely this mapping that we wish to automate. The problem can be considered essentially a language translation issue, and like language translation, has proven vexingly resistant to straightforward resolution.

Programming in general is a mix of declarative and procedural approaches. In early systems, the computer offered very raw services (like memory, a video framebuffer, etc.) and the program not only had full access to everything but was expected to abstract these services to the user all by itself. Often times there simply wasn't enough memory to host anything like a modern operating system or even something as compact as DOS. So procedural methods dominated -- if you wanted to do something, you wrote code.

At the other extreme is pure declaration. A normal HTML page is a good example: it states what it wants the text to look like, and code in the browser goes and implements the necessary logic to pull it off. We can think of all data files in a similar manner. They sit there expressing intent, and require some program in order to parse, interpret, and transform that intent into meaningful action and visuals. As a result, a large number of programs are viewers, editors, and translators.

Then there's the gray area in between. An HTML page with embedded JavaScript is not purely declarative anymore. A program that has dialog and menu resources is not purely procedural either. The more declarative a file gets, the more program-side logic is needed to handle the possibilities. This is why today's multimedia formats like QuickTime are gargantuan, because they support declaring sound and video in many ways. The only guaranteed way to reduce all the protocols to one method is to go to the procedural extreme and let programs produce and play the content. But then there's no abstraction at all, and media producers must be programmers. In fact, one hardly needs a media player, since in effect, the programs are their own players.

In the real world, things are both declarative and procedural simultaneously. A paper file with words written on it doesn't need any procedural system to be displayed, because it is inherently visible by simply being a real object. But in a computer, there is no inherent system of physics that performs this automatic magic -- everything that happens must be somewhere programmed to happen. In the real world, the laws of physics act like a premade, single, fixed, reliable, universal protocol that operates on everything everywhere in equal measure. In a computer, protocols are arbitrary, numerous, imperfect, and keep changing. But even in the real world, we layer the basic protocol of reality with our own metarealities such as accounting, scheduling, timekeeping, inventory control, payroll, stock markets, currency exchanges, procurement, command chains, money, power, influence, fame, ownership, relationships, etc. We can think of computer protocols as representing the most extreme of these metarealities, or as meta-metarealities.

So we strive for optimum balance. A system where declarative methods provide maximum benefit but yield to procedural approaches when the benefit becomes more trouble than it's worth. Declarative systems are only as useful as the code interpreting and implementing their intent. Using them requires a willingness to sacrifice perfect representation some (or even all) of the time. Results are best when the differences between implementations are differences that no one cares about, like how GUI widgets actually look (as long as they all look tasteful and consistent).






Copyright 2003-2004 Daylon Graphics Ltd.
Abstract is a trademark of Daylon Graphics Ltd.
Author(s): Ray Gardener (rayg@daylongraphics.com)
Location: http://www.daylongraphics.com/other/abstract/intro.htm
Last updated: February 26, 2004