Tuesday, September 29, 2009

Immanuel Kant: Mattson's Pattern Language

Most any attempt at taxonomy is inherently flawed, or at least incomplete.  There is no objectively clean way in which a complexly interwoven system can be described both completely and succinctly.  You can see this in biological taxonomy, which struggles to incorporate genetic history into a timeless label (birds share the same superclass as dinosaurs and mammals, incorrectly suggesting their common ancestor).  You can see this in medical taxonomy, which struggles to describe the symptoms, causes, and circumstances around the disease in a single label (resulting in dozens of competing standards used by different groups in the industry to describe similar things).  Yet biological taxonomy is immensely useful.  Medical taxonomy is immensely useful.  Neither is perfect, but both highly functional.

Entire fields of philosophy are devoted to exploring the ways in which we are shaped by the organization we impose upon something.  This is a particularly interesting question in computer science for two reasons:
  1. We have the ability to organize information into any conceivable way: a pattern language isn't merely a labeling of natural phenomenon, it is a fundamental way of conceiving the organization of information itself.
  2. We use and build upon our taxonomy more than almost any discipline: a program consists of millions of inter-related components existing at dozens of levels of abstraction.  Each new contribution is defining something new, and is likely to be the foundation of something else.  Thus how we think about it affects how we actually do other things that haven't yet come up.
Curious as to the epistemological significance of such qualification, I fired up the GRUMPS and had a quick cup of coffee with Immanuel Kant.


Kurt: Immanuel, in trying to organize a new system of knowledge, what is it that I'm seeking?
Kant: Experience without theory is blind, but theory without experience is mere intellectual play.
Kurt: So in constructing a language, I'm primarily seeking to guide and organize my thoughts?
Kant: All the interests of my reason, speculative as well as practical, combine in the three following questions: 1. What can I know? 2. What ought I to do? 3. What may I hope?
Kurt: So it should be comprehensive, practical, and illuminating?
Kant: Intuition and concepts constitute the elements of all our knowledge, so that neither concepts without an intuition in some way corresponding to them, nor intuition without concepts, can yield knowledge.
Kurt: Then it should be accurate, and intuitive as well, I see.  Thank you muchly for your time and words.



Though a taxonomy is inherently imperfect, they can still be good.  So how would Kant's questions apply to a pattern language?
  1. It should help a developer be more productive: a good taxonomy of patterns will help a developer think in a way that clarifies their understanding of their system at as many layers as is pertinent.  It should given them a practical layering of concepts, and provide relevant ideas at each layer.
  2. It should be easily expandable: no taxonomy is permanent, least of all in the world of programming.  A new pattern should have an obvious place in the language, and pertinent, identifiable relationship to other ideas based upon its placement.
  3. It should be as simple as is practical: the more effort is required to understand it, the less people will use it.
So how does Tim Mattson's concurrency pattern language stack up?
  1.  Would it help a developer be more productive?  It's hard to answer this without actually referring to it during the creation of a program, but I like how he cleanly distinguishes between the various roles of software engineers, and organizes his language accordingly.  That said, I don't know the chances that a developer would benefit from looking up a list of patterns so broadly categorized.
  2. Is it easily expandable?  This structure doesn't draw much of a relationship between categories, and can be a bit questionable in the consistency of its abstraction layers.  Is a pipeline an algorithm strategy or an architectural pattern?  He puts it in both categories without explicitly explaining the difference in their use.
  3. Is it as simple as is practical?  It's certainly simple, and easily understood.  There is a chance it's too simple, providing too little guidance as to the niche of various algorithms and approaches.
Maybe "pattern language" is a bit of an overstatement in describing the system.  It's more like a group of lists for developers of varying focus.  This isn't a bad thing--it could be a handy reference for a developer looking for ideas to address a specific concurrency problem.  The title is deceptive, however.

GRUMPS Design: Metacircular Virtual Machines

On only one occasion have I taken self-reference to its logical extreme:  the GRUMPS Superluminal Computation Optimizer.  In an attempt to dramatically enhance the speed of GRUMPS' computations, I designed a system to send instructions back in time so that the results would be available sooner.  The system was profoundly metacircular; not only was the system self-referential, but individual function calls would often be literally self-referential, creating themselves in John Conner-like fashion.

In developing this system, I noticed a paradoxical advantage: it was in some ways far less stable.  A simple bug would cascade rapidly, bringing down the whole system.  The net result was that I'd detect bad code much sooner than normal.  Furthermore, optimizations would often have a substantial affect on the system, shortening recursive invocations and affecting wide swaths of code.

For the most part, I am a high-level developer.  I am grateful for the abstractions granted to me.  I don't always want sweeping power over my system, and metacircularity grants one an extremely intricate power over the informational structure of a system.

This power is further complicated when it is attempting to recreate another system, rather than exist independently.  The Jikes RVM project is a Java-based Java VM, giving the developer far more power than an standard app developer needs, but exactly as much power as a performance theorist needs.  In evaluating such a project, it can be difficult to separate its meta-circular qualities from it's Java qualities.  What value does it derive from being densely recursive, and what value from being Java in particular?

Metacircular VMs (virtual machines written primarily in the same language they execute) are easier to port--only the the boot image, loader, and some memory behavior need to be translated for each operating system.  Most of the environment's behavior is self-referential, meaning it can execute on any environment support the lowest-level operations it specifies.  For a Java VM, metacircularity doesn't offer much to most application developers, since most programmers' applications will be running on a standard JVM anyway.  However, for support tools (like debuggers) and highly-specific performance-dependent niche applications, the ability to optimize the VM and code in the same context could help developers improve application performance, and identify the true bottlenecks in their system.

As a Java application, JikesRVM has some notable advantages and issues.  It gains all the structural benefits of Java--the ease of organization, the simplified modularity, the portability of code.  However, it also gains some of the problems--in particular, the hindered performance.  There is a reason JikesRVM is primarily a research project: it is much slower than the Sun JVM.

It's an excellent playground for testing out optimizations.  Its structure makes it easy for a researcher to get a comprehensive picture of how their work in interacting with the rest of the system.  Furthermore, it is probably the easiest way for a Java developer to understand the inner-workings of a Java VM.  But realistically, most of this theory achieves its fullest impact when done in a language closer to the processor.  Jikes has a long life ahead of it, but that life won't be on your laptop or cell phone.

Thursday, September 24, 2009

Design and Project Management: JPC (Java-based x86 emulation)

The first think you may notice upon visiting JPC's web page is the banner loudly proclaiming "JPC is the fast pure Java™ x86 PC emulator".  The second thing you might notice is its absurd URL: www-jpc.physics.ox.ac.uk.  This project is hosted on Oxford's Physics Department's server.  Or maybe it's the fact that all the images on the main page are stretched to fit the designated rectangles, implying a stunning degree of apathy regarding presentation.

This is a project that makes a profoundly impressive claim, but exists somewhere in the abyss of near-forgotten software.  Reading the project's architecture, I was both deeply impressed with some of their technical accomplishments and know-how, and perplexed as to the niche the program was supposed to be filling.  You can get a good impression of project's nature by observing the status and users pages: it is currently an idle project, incapable of booting most x86-based operating systems, used primarily to play DOS games in a browser.

Clearly, this is a project that has a lot to teach.  Much from its successes, and much from its failures.  First, my complaints:

  1. Java's portability is meaningless when you're emulating hardware.  This is a very oddly placed abstraction layer.  For you to run an x86 application, you now need to have booted into an operating system and loaded a JVM.  JPC is effectively relying on the JVM to ensure its portability.  In a sense, it's using Java for what a compiler should be used for.

    Any application that can be compiled with gcc can be compiled to run on any hardware gcc supports.  If they had written their code in C++ (or even combined Java down to binary, rather than bytecode), they would get the some functionality, but without the performance penalties inherent to the extra abstraction layer.

    The only novel deployment area for Java is applets, and those... well, we won't get into applets.
  2. Follow your own rules: Newman and Dennis (the code's authors) explicitly warn against premature optimization.  "Make it work, make it right, make it fast", right?

    Again, looking at the "status" page reveals the only successful emulation behavior to be in DOS.  Now maybe "work" in this context can mean "work quickly"--the program is near useless without it.  They still seem to contradict "Before building each part of each stage, be clear what aspect is being developed and why" by repeatedly insisting that this is supposed to be a full x86 emulator.
  3. Be honest about numbers: The project is regularly described as being "fast".  All sorts of benchmarks are given for a prototype using a simplified instruction set.  But the actual x86 emulation?  No mention in the paper.  After searching around, I found a presentation on JPC from which numbers can be derived; it's mentioned that using Java HotSpot, one can get approximately 20 x86 instructions per actual x86.  This translates to around 5%.  Simply put, that level of efficiency is far too slow to compete with most modern virtualization solutions.
  4. If you're going to have open code, invite people: They're GPL'd but don't have a CVS or SVN server set-up.  No instructions as to how to contribute.  It might seem like they don't care because I suspect they don't.
That all I said, I'm still damn well impressed.  They were approaching a profoundly difficult problem, and sought a number of avenues to conquer it (at one point looking into the JVM code to find out how classes are managed in memory).  From their work, I learned quite a bit about Java's memory management and techniques for performance optimization.  There are some outstanding ideas in there: unfortunately most of those ideas are either centered around Java optimization or in advantages of virtualization--I remain unconvinced of the synergy between the two.

Curious as to the fate of this project, I fired up the GRUMPs and went off to the distant future: September 2009.  What I found shocked me: the project hasn't budged.

Tuesday, September 22, 2009

Biocomputers: Fault Tolerant Systems

An underappreciated distinction between software engineering, and all other fields of engineering: in software, the blueprints are the final product.

If I build a car, a scanner, a hard drive, anything that has a physical manifestation, then I run the risk of a manufacturing defect.  Most devices go bad after a time.  However, the blueprints do not.  In most ways, this is an advantage for software: it is limited in the ways it can decay.  Software defects are limited to their blueprints (code) and their operating environment.

In one way way, however, this gives hardware an advantage: fault-tolerance through duplication.  If you have two of any given device, chances are that one of them will behave as planned.  And if you can identify when hardware behaves unexpectedly, then you can replace it before it affects the system.  RAID works with disks.  It does not with software.

By conventional design, software is not fault tolerant.  You can spawn a hundred copies of your thread, but if your logic is incorrect, chances are that all hundred will fail.  Attempts have been made to build fault-tolerant software before.  The Guardian Tandem/16 would keep backup processes to run if primary processes fail, restoring a checkpoint and running from there.  While this mechanism could work for some types of faults, in reality, this is transaction management, not a full-functional backup.  Again, a logic error in one thread would simply be repeated in the backup.

So what would true software backup systems look-like?

One could take the military approach, in which three teams must independently reimplement the same functionality, with the end action being a consensus of three unrelated code bases. This substantially increases the reliability of code, but it also requires three times the effort.  A similar strategy is frequently employed by developers: test-driven development, in which the accuracy of the executing code is verified by another set of test code.  But, though this drastically helps code reliability, it isn't exactly fault tolerance.  Additionally, use of try/catch blocks in code can help identify, prevent, and sometimes fix problems, but it lacks the kind of hot-swap easy fix capability of well-designed fault-tolerant hardware.

Can complete fault tolerance exist in software without a doubling of design effort?  It depends upon the kind of faults one is looking for.  Many distributed algorithms can prevent problems that arise by thread crashes or competition over resources.  In order to support complete software fault-tolerance, a completely different approach to computing is required.  It is a field barely blossoming in 2009, but by the 2060s becomes critical to many high-end, computationally complex systems: biocomputation.

The human brain is a type of computer with heavy levels of fault tolerance.  It frequently makes processing mistakes (think of stubbed toes, misspoken words, phantom cell phone rings), but generally recovers from these.  How does it do this?  To explore this question, today we interview Dr. Larry Gernsback, head of the Neurocomputing Design Division in Qx Machinations (founded by two former Intel engineers and an MIT neuroscientist in the 2040s).

Kurt: Dr. Gernsback, you're involved in a field that would be foreign to most of our readers in 2009.  How does a neurocomputer differ from a standard digital computer?
Gernsback: Well, neurocomputers and biocomputers operate quite differently from classical digital and quantum computers.  The most familiar technology might be something along the lines of a highly-networked analog control system.
Kurt: I'm not sure I understand, please clarify?
Gernsback: In a traditional computer program, an operation is specified, it is compiled, and it runs exactly as it was told to do, in any given environment.  A loop will behave the same no matter where in the code it is placed.  In a biocomputer, there are two primary differences: first, no code can operate independently of its execution environment.  All functions must be fed with extensive data regarding the state of the area of the system it well be placed in.  Second, the code isn't compiled into machine instructions, but rather into probabilistic control mechanisms.  In effect, the code becomes the summation of a set of highly-conditional input-output matching.  Its effectively like performing a Fourier transform on discrete data.  Rather than being a signal defined by a single function, it becomes defined by a large series of additive, simpler functions.  So when you write a method, it is compiled into a number of regulating methods, each listening to different system state information, and modifying different system state information.  The cumulative effect is the desired functionality.
Kurt: So what benefit does this have?
Gernsback: Well, the primary consequence is that everything in the system affects everything else.  Now, this might sound inherently unstable, but if designed properly, it is quite the opposite.  A function will behave predictably when placed into a predictable environment; when anomalies occur in the system, they modify the global variables that all sorts of functions are listening for.  These functions in turn regulate those variables, returning them to normalcy.  Everything acts as a controller for everything else, meaning that parts with only some functional overlap will actually mutually enhance each others' reliability.
Kurt: Most fascinating.  So besides reliability, what does one gain from such functionality?
Gernsback: Well, it fundamentally changes the way in which one designs the system.  The "program" itself will seek out order, self-organize around the data feed into it.  This makes some classes of data analysis, security, even user interaction entirely different.  Rather than programming the internals of a feature, you mathematically define the desired outputs, and then feed the system extensive sets of simulated data.  New regulating functions will emerge to adapt to this data, modifying the program in such a way that it produces the desired output.
Kurt: So, the software is evolved, almost literally?
Gernsback: Precisely.  And with that design paradigm, one gets all sorts of other gains.  The program can evolve in multiple different directions in virtual environments, and even "mate" with each other.  It enables you to run the genetic algorithm on programs themselves, enabling you to rapidly produce a variety of possibilities, and select the desired one.  It costs almost the same to produce 100 unique programs that meet your requirements as it is to produce 1, fundamentally changing the way one approaches the system.  A good developer knows how to guide the evolution of a product, more like a botanist than a traditional engineer.  We have a joke around the office that software that doesn't behave as desired only needs to be "domesticated".  I think its an apt term, in some respects.
Kurt: I'll admit, a lot of this discussion went over my head, but the structure of it I find extremely fascinating.  And I'll have you know, Dr. Gernsback, that your work is only the beginning.

Okay.  At this point in time, we have C++ and some basic calculators implemented in DNA.  We don't have extensively self-modifying programs.  What we have is redundancy and transaction management.  This is powerful, and this will be the dominant paradigm for some time to come.  But true, complete, software-level fault tolerance is currently profoundly laborious to implement.  And until a program can dynamically modify itself, the most effective duplication is a duplication of effort.

Terry Goldberg: Big Ball of Mud

This weekend I received notice that a certain nameless interviewee has filed a Defamation of Character lawsuit for a recent blog post.  Frustration aside, this legal circumstance got me thinking; I am technically bound by all the rules of law—federal, state, and local.  Yet there is no conceivable way I could know all these laws.  I am fundamentally bound by more law than I could know in a lifetime.  Even if I limited myself to a particular sub-field of law, and even if I limited myself to recent law, there is more tax law produced annually than I could conceivably read in a year.

The legal framework of the United States begun simply.  The constitution provided general guiding principles, but most particulars had not been fleshed out.  Verdicts were at the discretion of the moral compass of juries, who often deferred to English Common Law until America’s legal framework became comprehensiveness enough to stand on its own.  Over the years, decades, new laws continually got built upon old laws.  Extensive [over]reactionary laws (fixes) altered the system in response to questionable verdicts in trials (bugs).  Entirely new fields of law emerge (features) as the culture and economy of the country grew.  The system becomes progressively more complicated, with no conceivable force to simplify it.  An obtuse, interwoven set of legislation and judicial precedent define the behavior of the system, often failing to maintain an intelligible high-level structure.

In the world of software, we call this situation a Big Ball of Mud.  When a lawyer can spend days attempting to find a law or judicial ruling pertinent to his case, then you have a system too complicated for its own good.  It may be fully featured, but it is difficult to maintain, and expensive to understand.

So how does one address a system of exponentially increasing chaos?  While meeting with my lawyer, Terry Goldberg, this weekend, I took a minute to interview him on his opinions of the process:

Kurt: In the world of software, a product that is grown ad-hoc over many years can often become unnecessarily expensive to maintain.   Do you see analogous behavior in law?
Goldberg: Without question.  There are more lawyers now than at any point in our nation’s history.  We constitute a larger percentage of the working force, yet can charge more than at any point in the past.  And I think a lot of this has to do with the fact that there is more law now than there was at any point in the past: congress has passed more bills since 1976 than were passed in the preceding 200 years.
Kurt: Do you believe this is how the system should operate?
Goldberg: It depends on what you seek from it, but as a system of regulation and common utility, I think it has become too obtuse, and continually worsens.  I got into law because of a belief in justice.  But indecipherable law colludes a sense of what is just.  I would love to defend my clients based upon the ethics of their actions, but that is simply not how cases are decided.  In many cases, there is an obvious right or wrong party, but it is endlessly difficult to find the text that proves their legality.
Kurt: In essence, you don’t know where the relevant code is.
Goldberg: It depends on how specialized you are and on the nature of the case, but quite a lot of my job entails searching for precedent.
Kurt: Is there any way to change this?  To simplify the beast?
Goldberg: Many countries go through legal resets.  Switzerland re-wrote its constitution as recently as 1999 to prevent the need for an endless series of legal patches.  But once a system has grown beyond a certain size, these kinds of reboots are impossible.  Too much of the country becomes shaped around the law.  If you reset the law, you reset these institutions, which can be dangerous and incredibly expensive.
Kurt: So what happens then?
Goldberg: It will grow more and more complex until it reaches a breaking point.  When the demand for lawyers is so high such that the effective productivity of the institutions they guide is hindered, then there might be a demand for a simplification.  Until such time, it will only get worse.

As my readers know, I’m fond of overstretching metaphor, but I see many similarities in programming and law.  Each theoretically produces a codified framework whereby inputs (events in law) produce predictable outputs (rulings).  Much like law, early maintenance is critical to keeping projects sensible.  Once they grow past a certain size, it becomes impossible to simplify them down—there is simply too much dependency.  Many businesses will simply keep patching a system until it collapses beneath its own weight—until fixes and improvements are so convoluted and time-consuming that there is no conceivable way to match the pace of market demands.

At that point, they will scrap the software and start over.  They will write a new constitution.

Once a Big Ball of Mud is created, there is rarely hope to recover it.  One can attempt to isolate parts of it, but if the system were easily made modular, it wouldn’t be a Big Ball of Mud.  Early and frequent refactoring is essential if a system’s goal is longevity.  But as much as programmers may wish for that goal, it very rarely is a business priority in an industry that redefines itself every few years.

As long as hardware is improving at a rapid pace, software will be rapidly evolving, and thus taking the time to refactor to ease long-term maintenance is not always worth it.  Any project should attempt realistic expectations for their timeline, and effort should always be made to grow them in a sustainable way.    But each business has a different set of priorities, and it is often more financially beneficial to release now.

But the advantage of software is competition: if your product lags because of its design, someone else will eventually replace you.  One has incentive to code quality, or market share will decline.  That is a flexibility law does not offer.

Thursday, September 17, 2009

Thomas Jefferson: Layered Architectures / Xen

Layered architectures come up again and again in software design, being a natural byproduct of the recursive nature of computing.  Any function call that never references its parent is effectively a new layer.
Of course, we don't always call these things layers: to do so would be to cheapen the term.  In software architecture, a layer generally consists of a swappable set of functions that maintain the integrity of the overall layer stack.  The traditional network layers are an excellent example of this.  UDP could transmit HTTP data, even though TCP is generally used for this.  Different devices use different physical links, and a countless set of application-layer protocols without imposing any required changes to the layers beneath.

The network stack also reveals something about the dynamic nature of architectural layers: as long as your interfaces are stably defined, new layers can be inserted, removed, or combined as necessary.  The original OSI model for network stacks established 7 layers for digital communication, including a "data-link" layer (separate from the physical layer), and a "presentation" layer (separate from the application layer).  Functionally, these are important layers.  Practically, their implementation wound up combined with other layers in the stack such that they are now rarely discussed independently.  The "session" layer, responsible for maintaining a dialog between remote application is now functionally part of the transport and application layers: TCP will guarantee message delivery, and HTTP will manage a client/server session.  SSH can easily be used as the application layer, wrapping any other application layer within it.  Because the interfaces are well-designated, these layers can be added without affecting the system as a whole.

Another example of the evolution of layers due to well-designed interfaces is in virtualization.  Any program that executes on a computer goes through a number of translations, often being translated from managed code into assembly code, assembly into bits traversing a system.  Memory access is converted from virtual to physical addresses, physical to block/offset locations.  Anywhere a conversion takes place, a new layer can be inserted, as long as its external interfaces communicate consistently.  This notion has enabled computers to run multiple simultaneous operating systems.  New layers are added, translating kernel's system instructions into lower-privilege commands, and translating the operating system's "physical memory" addresses into the real physical memory addresses.  The end points can communicate just as they had previously, however.

Granted, the addition of new layers will always reduce performance.  So developers have turned to concepts such as paravirtualization, effectively combining separate layers into a single one, maintaining consistent behavior at the end-interfaces, but internally operating differently than if the layers were distinct.  For example, a paravirtualized operating system may delegate memory paging to the hypervisor, rather than handling it by itself to improve performance.  Thus, one step in the memory translation is saved.  Similar approaches are taken for devices: rather than have a layer to deal with driver translation, hypervisor-level drivers can be accessed by the hosted operating systems.

A rough analogy of this set-up can be found in law.  Layered architecture is like federalist government: the responsibilities of each layer of government (federal, state, local) are determined by the functionality of the layer above it.  These layers operate by consistent interfaces (law and funds) but internally have theoretical freedom in their implementation.  Realistically, this is often not the case: governments can often micromanage state spending by strongly incentivizing certain actions ("sure, you don't have to drop your local speed limit to 55, but then you unfortunately wouldn't qualify for highway funds").  In this respect, government is more like a "relaxed" layered system... higher-level layers can interfere with lower level ones.

So, would government an ideal government be able to defy this desperation of layers?  Does good software expose the internals to lower layers?  Is it even remotely fair to treat the answers to these questions as related?  Of course not.  Thus, in celebrated ignorance of this conclusion, I present to you: an abbreviated interview with Thomas Jefferson, political theorist on federalism.

Kurt: Mr. Jefferson, it is with great privilege that I needlessly interrupt your studies.  I have but a simple question for you:
Jefferson: What, man?  Who the hell are you?  I've never seen cloths so fu--ed up before.  Holy sh--.  Georgie boy bought me the good stuff this time.  I cannabalieve it.  Heh, heh.  Get it?
Kurt: Mr. Jefferson, are you...?
Jefferson: Yeah, man, what?
Kurt: I'm embaressed to even be asking this question... are you... well... in a condition to speak?
Jefferson: Sh-- man, I do all my writing fu--ed up.  It's the best fu--ing way, man.  Best fu--ing way.
Kurt: Ah... well.  I guess I'll just... just, how do believe that governments should be arranged?  What amount of authority should a federal body have over smaller ones?
Jefferson: God damn, field me the easy ones, freaky alien dude.  The several states composing the United States of America are not united on the principle of unlimited submission to their general government; but by a compact under the style and title of a Constitution for the United States, and of amendments thereto, they constituted a general government for special purposes and delegated to that government certain definite powers and whensoever the general government assumes undelegated powers, its acts are unauthoritative, void, and of no force. To this compact each state acceded as a state, and is an integral party, its co-states forming, as to itself, the other party. The government created by this compact was not made the exclusive or final judge of the extent of the powers delegated to itself, since that would have made its discretion, and not the Constitution the measure of its powers.
Kurt: So... maintain a strict separation then?
Jefferson: God I am fu--ed up.

I... I really don't know if I feel comfortable applying that advice to my programs.  But I'm not sure if I'm comfortable applying it to government any more either.  Damn.

Tuesday, September 15, 2009

Augustus Ceasar: Data Grows Up

As the web grows more densely interconnected, challenges begin to arise.  How does one balance the demand for data interoperability with the demand for privacy?  How does one maintain consistency within a technological framework fundamentally designed to be flexible?  How can you avoid the labor and challenge of crafting redundant data, requiring a user to supply information that’s already a part of the cloud?
The Facebook project has done an outstanding job engineering around these challenges, building what is currently one of the leading social networking sites.  Millions of people use it for hundreds of different reasons, leveraging an ever-increasing volume of user information to build new services in a controlled matter.  With the proper design, the site has become the center of a small universe of activity based around the notion of digital community—the sharing of notes, photos, the organization of political movements and Scrabble games.

To do all this, Facebook has had to figure out how to compromise with developers: how to involve third parties while controlling data access and application behavior.  They’ve literally re-implemented a wide assortment of web technologies to make this happen: FBML to allow developers to code near-HTML web pages capable of invoking Facebook services; FBJS to allow developers to code dynamic web page behavior while forbidding access to undesired operations and out-of-scope Facebook components; FQL to give developers access to Facebook data in a predictable, controlled, and optimized way, requiring the necessary authentication and abstracting away data that could compromise the security of the site.

In many ways, these approaches are brand new: they’re creating new implementations of already-modern languages.  But the fundamental paradigm Facebook is using is rather old: they’re providing a controlled environment for developers to practice much the same thing they’ve been doing before, abstracting away the complex translation necessary to make their code operate cleanly.  It is giving developers a new environment to practice old behaviors.

So characteristics abstraction enable it to be so effective?  With the recently fixed and more-stable-than-ever GRUMPs, we’ll be probing these questions by interviewing legendary Roman emperor Octavianus Augustus Caesar.

Much like modern developers, Augustus Caesar rose to power amidst an environment in profound flux, and great organizational instability.  Yet he thrived in such a chaotic environment, and rebuilt the Roman Empire in a way that lasted centuries after his death.  Creators of application frameworks could learn much from his political acumen.  Without further ado:

Kurt: Augustus Caesar, it is a great honor to have you here.  You’re a figure of rare notoriety and influence.
Augustus: The honor is mine.  I have long thought about how I could address the future… the wisdom I could impart to my successors’ successors.
Kurt: So Caesar, how is it that you found a way to organize a state rapidly tending toward decay?
Augustus: You must first understand the cause of that decay; all people want two things: freedom and power.  These are the forces most actively working against any attempt at order, for two reasons: freedom threatens, since every man chooses a different route with his liberty; power threatens because it is scarce—it only comes at the expense of others.  Fundamentally, you will realize that freedom and power are the same thing: power is simply the point at which your freedom overrides another’s.
Kurt: So do you seek to eliminate freedom and power from your developer’s—er, I mean, citizens?
Augustus: No, no.  It is far more subtle than that.  If you eliminate freedom, others will not follow you.  You can never remove a man’s desire for freedom, and where a man has unmet aspiration, he is dangerous.  Too with power; you cannot rob all men of power for they will fight to win it back.  Rather, you must give to each man the smallest freedom and power they require to be content.  You must give to each city enough independence to thrive gratefully, but never so much that they feel capable of conquering their limitations.
Kurt: So one must carefully craft architectures to allow programmers to modify what they need without affecting the systems that you yourself are defining?
Augustus: You speak with the confidence and obscurity of the sibyls.
Kurt: I mean, you give power to others only where it doesn’t intrude upon your own?
Augustus: All granting of power intrudes upon your own.  Rather, you must only sacrifice as much power as is required to make others feel powerful.  A man governs best when he believes something is his.
Kurt: Then give a developer the tools to make an application feel and behave how they wish, but maintain control over the data.  I mean… keep local customs alive?
Augustus: You recruit soldiers from around the world.  They will remain loyal to you if you feed them and permit them to practice their own religion.  They must respect your rules, but you must maintain rules men can respect.
Kurt: Right, so no Javascript pop-ups.
Augustus: Moreover, you exercise power only where necessary, and in those places, exercise ruthlessly.  In other areas, simply give them rules they must follow to maintain their power, and they will do so.  Let your borders be protected by the client states, not by your own legions.
Kurt: So, don’t try to control the kinds of applications that flourish, merely provide them an incentive an opportunity to flourish, and they will empower your architecture...
Augustus: The people will celebrate Rome if they believe their city to be both Roman and theirs.
Kurt: Augustus Caesar, your wisdom inspires.  We are almost out of time, but do you have any closing thoughts?
Augustus: A principate is all-powerful, but never lets himself be perceived as such.  Freedom is the most powerful political illusion, more pure and celebrated than a vote.
Kurt: So, one must emphasize the power you grant third party developers--let them use your information, but not change it.  There’s so much more to learned, but I'm afraid our time is up.  Thank you, Caesar, for coming.

Perhaps it’s a stretch to compare Facebook to great historical rulers.  But in many ways, the challenges and solutions are the sames.  Facebook is manipulative in an almost political sense with its users and developers:  It offers rich functionality and hides the costs (to privacy and such) by providing users the impression that they fully control their data, and developers the impression that they fully control their application.

If Facebook had simply provided a high-level API to build applications, it would require developers to approach on bended knee.  A simple API doesn't give a developer a feeling of power over data, a sense of independence and excitement so necessary to maintaining a user-driven application.  If Facebook were upfront about the ways in which they use user data in advertisements, people would feel violated.  But give a user a chance to deny an application access to their data, and they feel free.  Give a developer a chance to program in a familiar language, and they feel powerful.  They feel like Facebook's application is theirs.

Facebook has consistently impressed me with its design.  A look beneath the hood has only reinforced my respect.  But maybe that’s just what they want me to think.

GRUMPS Design: Pipes and Filters

In one sense, pipes and filters are the computational paradigm most reminiscent of classical signal processing.  In circumstances where one input is modified in many ways to produce one output, piping is often the most sensible and flexible solution.  Piping stdout and stderr programs in *nix allows the users to easily execute complicated operations without requiring them to create new programs.  Instead, they can simply string together transformations, finding, manipulating, and redirecting text.  This is similar to audio production, in which a limited number of filters can be used to make a great variety of modifications to an acoustic signal; applying reverb and then noise will sounds substantially different from applying noise first, and then reverb.

Thus, in pipe/filter processing, each permutation of the available filters constitutes operates like a new filter in itself, meaning that every new contribution enriches the entire processing ecosystem.

That said, there are dangers in overstretching this analogy.  Computer pipes and filters encounter issue that direct signal processing does not.  Circuits do not have to deal with error conditions: they will treat all inputs the same.  They do not have to worry about time spent switching between processes: the transition is instantaneous.  They rarely need to navigate a complex push/pull pipeline: each push/pull would be a separate component in itself.

When I was originally designing GRUMPs, I gave consideration to designing some of the components as a pipe/filter set-up.  Because of the flexibility such a system would offer, I assumed that it would enable me to prototype many different kinds of physical set-ups until I came across one that stably opened a worm hole through time.  Some of my initial prototypes processed time flux data in exactly this matter, but I soon came across some issues that prevented me from continuing to work in that paradigm.

The most substantial among these was the increasingly evident need to maintain a global state.  A pipe/filter setup treats each component as structurally independent from one another.  So what do I do when my flux capacitance monitor begun measuring anomalous gravitational waves, forcing me to alter the rate of boson production?  A pipe/filter system can’t handle this condition easily.  Technically, you can design a pipe to take multiple inputs, but that begins to breakdown the purity of the design, complicating the system’s structure in the long run.  Simply put, too many components needed to talk to too many other components in GRUMPS simultaneously. 

Another problem came from the need to dynamically redirect the flow of information.  Technically, one can operate a conditional filter pipeline, but again this breaks the purity of design.  Depending on the nature of information streaming through the black hole, I might need to enable or disable various filters and amplifiers, frequently reconfiguring the data flow multiple times per second.  Ultimately, this began to look more like a fuzzy state diagram, and less like a pipe/filter setup.  My assumptions that I could simply reconfigure and rerun proved consistently wrong, as the setup had to adapt to running conditions.  Filters failed because a large, carefully calibrated system cannot dynamically respond to circumstances when it is designed to process information linearly.

Pipes and filters are a fascinating and profoundly useful paradigm.  But despite their flexibility, it is still a solutions to a very limited subset of problems.  I keep it in my back pocket, but I am less inclined to assume it the best methodology than I used to.

Thursday, September 10, 2009

Being "In the Web"

While I'm busy with repairs to the GRUMPS, perhaps we should have a high-level discussion about the evolution of software's treatment data over the last 30 years.

Once upon a time, as recently as the dark ages that we call the 1980's, information was commonly recorded onto long lengths of magnetic tape.  To retrieve the pertinent information within your network, a "robot" would have to move throughout the machine, pick a tape, move it to the tape reader, the tape would be wound and your data read.  That is, if you were located within the facility.

Transferring large volumes of data was often prohibitively expensive for most IT groups, so tapes were often mailed (as in physically delivered... by a person) between facilities.  Highways simply had a higher data throughput than most networks.

A computer was envisioned as a one-application-at-a-time interface, so developers were given full discretion to use the system's resources as they saw fit.  By the 90's, most software was inconsistent, and profoundly insular.  There just wasn't enough network bandwidth to consider data available in "the cloud" (at the time, not more than a diffuse altocumulus cloud).

And then the internet happened.  Everyone was in everyone else's data.  Programs were talking to central servers, grabbing information from a variety of places, and putting it together.  A hundred data access standards were created and destroyed.

Right now, the shape of software is changing.  Far more programs are highly networked, and far more programs co-exist on a single system.  And we've gotten to the point where the system is increasingly dependent upon the broadcast and receival of networked information.

XML has been among the most successful ways to define an data type comfortably interoperable between programs.  Web services (SOAP) in particular define standard to allow data to be queryable.  And increasingly, applications are providing developers a way to broadcast their own data.  A crucial component of the Android operating system is the ability of programs to inform the whole system what data and functionality they have available, such that it can be easily invoked by other applications.

In order to achieve this kind of deeply inter-connected software, restrictions are imposed on developers.  Don't present information anyway, present it in a limited way, and declare the type of data you're using upfront or there'll be hell to pay.  Or you at least won't be able to access your desired information.

This exhibits a fascinating paradox in programming: limitations are profoundly helpful.  Limited vocabularies of interaction can enable richer interaction, by ensuring that various software truly speak the same, simple language.  Essentially, they enforce the data-centric nature of these applications; in REST architecture, one is limited to simple reads and modifications of data.  When you define your operation around the data (rather than UI or rules of operation, say), one allows an application to participate in the cloud.  A program isn't limited by the functionality created by the developers, but can become part of a rich ecosystem of interaction.  An alerts module can be invoked by a hundred other modules.  User data can be combined with a hundred other kinds of data, as long as it is made available.

I knew a developer who declared that any operation in a program should be executable by command-line, enforcing a vocabulary of interaction to better define the behavior of the system, and to allow it to better integrate into the ecosystem of the operating system.  The fact is, most modern software can only benefit from putting its public interaction upfront, and that action is most cleanly defined by data.

Lao-Tzu: A Timeless Way of Building (Christopher Alexander)

I often try to break down computing into its core form and function; the act helps one maintain perspective on the full scope of power of the technology.  At base, what is a computer?  A device to manipulate information.  That is, a machine that assists you in reducing something to an abstract representation (information), and can then modify or examine that abstraction quickly.  Fundamentally, the work done by any computer is simple, or can at least be reduced to simple steps--assembly commands are essentially a form of arithmetic.  There is nothing a machine can do that you or I can't... a computer can simply do these simple things orders of magnitude faster.  They can do complicated things quicker, and that speed enables them to realistically manipulate information in ways the unassisted human mind cannot.

So what is ultimately the force driving the analysis or manipulation of information?  Programs.  A computer, being an all-powerful tinkerer of data, can manipulate information in any possible way.  Any way data can be changed, a computer can do.  And the expressive language for that is programs.  A programming language can be called "turing-complete" if it exhibits this characteristic, if it is capable of all forms of information processing.

A programming language is fundamentally a description of a pattern... it describes some relationship between kinds of data, and how to act on them.  A larger program is made up of many simpler patterns--methods, subroutines.

When you recognize that programs are an arbitrary data container for any and all patterns, something interesting is revealed about software engineering: any architectural style, design pattern, or coding technique can be explicitly defined as code.  If your style cannot be, then it is either an inconsistent pattern (and thus not really a pattern), or your description of the pattern is incomplete.  Programming languages are literally a pattern-description language, and a complete one at that.

So why don't textbooks describe design patterns as code, and instead portray them as "ideas"?  Ultimately, this is due to the presence of a human mediator; the human machine has evolved to process information by a completely different descriptive languages, and very different algorithms.  What is effective for a computer, is not necessarily effective for a person, and at this point in history, it is the person that is writing programs.  That said, most patterns do have explicit definitions in many languages.  The observer pattern is built into Smalltalk.  The object-oriented paradigm (itself a design pattern) is fundamental to a number of programming languages.  Well-designed interfaces can effectively permit any pattern to be expressed within the language.

If I may be permitted to take an aside... if programs are simply a representation of patterns (a translation of "concepts" into "information" such that a computer may work with them), then where does the mind fall into this structure?  By some definitions, a "mind" is simply any system that processes and responds dynamically to information.  Could a "mind" itself simply be a program, a layering of patterns?

Enticed by the prospect that this blog entry lay on the cusp of enlightenment, I decided to open up a dialog with legendary Chinese philosopher, the Great Master Lao-Tzu.  Certainly, he can show me the way.

Kurt: We live in a universe exhibiting an astounding variety of patterns.  How do you make sense of such incredible complexity?
Lao-Tzu: All difficult things have their origin in that which is easy, and great things in that which is small.
Kurt: Exactly!  An endless layering of simple patterns can give rise to the deepest of functions.  Can this include the human mind?
Lao-Tzu: Nature is not human hearted.
Kurt: No, but is the human nature-hearted?  Are we merely a specialization of universal operation, an instance of self-organization and programmatic expression?  Are we not a vast compendium of nature's rules? 
Lao-Tzu: To see things in the seed, that is genius. 
Kurt: So you agree!  By Jove you agree!  Then the act of finding patterns is the act of returning to the root of organization?  And the act of documenting the sub-programs of the mind, the more rules that are discovered, the more easily those patterns can be discovered? 
Lao-Tzu: The more laws and order are made prominent, the more thieves and robbers there will be. 
Kurt: Wait, do you imply that one most look then from the ground up, rather than from the top down?  Is there deceit in comprehensiveness? 
Lao-Tzu: He who knows, does not speak. He who speaks, does not know. 
Kurt: Are you calling me verbose?  And also, wait... you just said that... doesn't that contradict-- 
Lao-Tzu: The words of truth are always paradoxical.  
Kurt: But every paradox has a resolution.  What is the resolution to the statement you just posited? 
Lao-Tzu: I have just three things to teach: simplicity, patience, compassion.

There was a great tremor and the black hole collapsed in a most extraordinary fashion, light sputtering from the abyss, great and rapid shifts in the temperature of the room.  GRUMPs stood still, smoke emanating, both exhausted and tranquil.

Okay, screw revelation.  I have time-machine fixing to do.

Tuesday, September 8, 2009

Lynn Conway: ArchJava

Even though electrical engineering and computer science work with the same parts, they are structured in remarkably different ways.  Each deals with unique aspects of optimizations, unique concerns.  Computer scientists are bound by the rules and speed of the underlying circuitry, electrical engineers by the rules and speed of physics.

For the most part, it is highly reasonable that circuits and software be architected in profoundly different ways.  But to fully understand the reasons for this, the differences should be noted: so what would circuit design look like in Java?  To prod this line of thought, I traveled back to 1982 to interview a young[er] Lynn Conway, co-founder of VLSI, the methodology which gave rise to the development of microprocessors.

Kurt: Mr. Conway, it's--
Conway: Miss.
Kurt: Yes, right, Ms. Conway, sorry.  What were the primary concerns that went into VLSI?
Conway: Hang on, you say you're from the future?
Kurt: 2009 to be exact.
Conway: So what, am I dead or something in 2009?
Kurt: No, no, you're very much alive... you see I just have this blog?
Conway: Blog?
Kurt: I mean, I write these articles in which I interview people from across time.
Conway: Wait, wait, can I ask you a question?
Kurt: Not really, no.  Time paradoxes and all if you learn too much--
Conway: So, you travel through time, make me question my sanity just for some journalistic gimmick?  You could have just talked to me in 2009--
Kurt: Look, Conway, it's not the same.  Just believe this from a man who has been all over time.  It's not the same thing.
Conway: Not the same how?
Kurt: ...people just don't give you the same kind of respect as--
Conway: So you haunt me through time so that you can talk to me without your lingering insecurities--
Kurt: Damnit, woman!  Look, just answer: could you design a good circuit in which all data was either public or private... I mean contained within a component, or accessible by the entire microprocessor?
Conway: God, no.  You have any idea the kind of wasted routing bandwidth that would result in?  Do you have any idea the kind of architectural follies that could result in?  There are advantages in limitations.  But you know what?  When 2009 rolls around, I'm gonna find you and we're going to have a little talking to.  This entire science-fiction charade--
Kurt: Well, young Lynn Conway, it was great, I'll talk to you then goodbye.

Maybe she's right... maybe I'm abusing the power granted to me by my technology.  Perhaps there is too much danger in all of time being publicly accessible.  Regardless...

She asserted the point I was trying to get at.  Just because computers exist in a realm of infinitely arbitrary definition, there are dangers with viewing them as infinite tapes.  Java is used to build enormous systems, yet these are all based upon a rather rigid, and sometimes dangerous level of openness: that all public methods are fully public, accessible by any component within the same project (or by any project invoking its .jar).

Though programmers can define whatever layers, structure, and hierarchy they please, the integrity of that structure is inherently dependent upon the integrity (and knowledgeability) of its programmers.  Many of us have experienced the frustration of having added functionality to the wrong area of an unfamiliar system.  But we must realize that such a blunder was assisted by the language itself-- we were given a structure in which code could be located in a large number of locations, the integrity of architecture was mutable by individual, unrelated decisions.

ArchJava poses an interesting concept: enforce a program's structural integrity through the language itself.  By modifying the standard notion of class interfaces into a far more hierarchical structure, one should theoretically prevent the accidental manipulation of the program's core organization.

There are downsides.  Java already has a notion of hierarchical structure--it's package system.  Imposing another layer could potentially complicate program structure by requiring multiple parallel organizational systems.  But are these trade-offs worthwhile?  In future interviews, we will discuss the mechanisms by which large-scale projects maintain their integrity, and where the balance of flexibility should be falling.

J.Q. Thomson: Making Memories

As a software engineer, it's often easy to get caught in pitfalls of thought: upholding the importance of designs without fully understanding their utility, getting tunnel vision on some quality without a wholistic appreciation for what you are creating, maintaining an irrational belief in the finality of one's decisions.

These technical challenges are compounded by the practical reality of the software.  When photography company Lifetouch Portrait Studios made the transition to digital, they had to create a robust, scalable system usable by photographers.  They needed to build something that wouldn't require an IT staff or a month-long training course, which could be adapted to a variety of circumstances and environments, many unknown at the time of creation.

They went to great lengths to avoid these engineering pitfalls, and the result seemed to have paid off.  There were a number of things that stood out about their design:
  1. Avoiding duplication from modularity: One side-effect of establishing a strong, multi-layered hierarchy is duplication of data structures and logic.  GUI, control logic, and databases can all contain information about the same object, and a single change might need to be made in multiple parts.  They addressed this through the use of "Forms", defining display logic separately from display code itself.  This is basically a well-designed implementation of the Model-View-Presenter architecture pattern.  The Spring framework was fundamental in defining this structure.
  2. Avoiding environmental dependency: They went to much effort to avoid depending on the system's environment variables or database set-up by defining the required information within the program itself.  They created a Launcher that identified and loaded the dependencies of various system modules, and integrated things like database updates into the system itself.
  3. Distinguishing commands: Throughout the system, operations were wrapped in objects.  Image manipulation was handed through RenderRequest objects, database updates were objects, GUI interaction was handled through command objects.  This made operation more loosely coupled, enabling messages to be more easily sent across computers, and separating layers.
To see how this design scaled in the following years, I've decided to interview a Lifetouch Portrait Studio photographer from the year 2013, Topeka photographer John Thomson.

Kurt: Mr. Thomson, I'm glad to have you here on the time phone.
Thomson: Yeah.  Um, call me J.Q.
Kurt: Shall do.  Anyway, I have some questions about the software you use in your work.
Thomson: What, Creation Center?
Kurt: That's the one.
Thomson: You with the government?
Kurt: Well, technically, I'm employed by the state of Illinois.
Thomson: I had nothing to do with nothing, you hear me?
Kurt: J.Q., I'm only here to--

And he wiped out the connection.  I'm a scientist by training; perhaps I need to learn a thing or two about journalism to effectively contact more lawyerly times.

Wednesday, September 2, 2009

Cynth Wannemaker: Architecting for Scale

In 1969, who at Bell Labs could have imagined that the newborn Unix would define the structure of operating system for decades to come?  Who could have imagined that some programs written in those years would still be in use generations later?  What is it about an architecture that lends itself to longevity?  How does it remain applicable?

Another project with a most unusual evolution is the Brightstar project.  In 2007, Sun Microsystems released Project Darkstar, a Java-based development framework and runtime environment for the generation of highly scalable, easily-programmed high-interaction online games.  A few months after Oracle's acquisition of Sun, the project forked and Project Brightstar was born.

Project Brightstar sought to utilize the scalability offered by Darkstar, but decentralizing some aspects of it so that users could define desired operation and integrate them into the larger system, balancing user privacy with the need to reliably communicate with the other systems (the supercloud).  Brightstar modified Darkstar's architecture, enabling users to define "rooms", essentially small servers hosted by clients of the supercloud with public and private interfaces.  A given "room" would communicate as much state as desired with the supercloud, but maintain a private internal state which users "in the room" would have access to.

A good system gives a developer flexibility within a highly ordered framework.  Piping in Unix allowed widely disparate programs to be seamlessly linked together.  A developer could write an application entirely independent of others, and have it made accessible by the entire system through commonly defined input and output mechanisms.  Brightstar's rooms soon rapidly expanded the potential scope of Darkstars worlds in a similar manner.

Users were soon creating worlds within worlds, online communities of a type of depth previously unseen.  No longer limited by the create/upload/share structure previously predominant on the internet, rich, multi-media, multi-faceted two-way interaction with other users expanded rapidly.  The public world remained accessible, consistent, and low latency as the private worlds and their rules expanded.  Within a few years, economies of a scope unheard of in virtual worlds were emerging.  Regulators were quick to attempt taxation, but lacked the ability to effectively monitor, or even shut down these transactions.  Over a contentious period of decades, these online communities had amassed a sufficient amount of financial influence, that they began to see political representation.

Today, I interview Cynth Wannemaker, appointed architect of Deutschon in 2038.  Deutschon was the first online community to be legally regarded as a nation-state, including diplomatic representation in the United Organizations (formerly United Nations).

Kurt: Cynth Wannemaker, you're arguably one of the most influential programmers in the world in your time.  How did you become involved with Brightstar room architecture?
Wannemaker: I was involved in Brightstar I was a teenager.  I often frequented various online neighborhoods, first just visiting, but soon taking on public responsibilities: I would monitor requests for communication from other communities, I would help organize small projects within the community to expand it.  I was originally just using simple tools, but I eventually needed to get into scripting.  I began studying algorithms so I could find ways to monitor the internal economy, make sure that it wasn't being manipulated from within or outside.
Kurt: What was your first major project?
Wannemaker: There is a profound advantage and challenge in the ability to easily create a private room within the room or supercloud.  Lets say I want to create a virtual "building" in an online city.
Kurt: Can you quickly explain "city"?
Wannemaker: Basically, it's what "rooms" turn into when they get large enough.  Anyway, I want to make a building, with an exposed interface of doors and windows, but private internals.  Now, the way Brightstar is structured, the building cannot communicate with the supercloud without using the city's interfaces.  So what do you do when a building wants to perform a private transaction with a building in another city?  Normally, the city would forbid any external private transactions--the city, naturally, needs to understand what messages it is sending.
Kurt: To prevent the leaking of secrets, or to maintain internal logical consistency?
Wannemaker: Both.  Though, in a way, though those are two sides of the same problem.  I worked on a system where a building could request a security token from the city, and thus be given permission send an encrypted communication out of the city.  The catch, however, is that it must identify all the city's private information that was used to define the message.  It's an interesting and challenging problem: prove the data you're using without showing how you're using it.
Kurt: Why do you think Brightstar was the first system to achieve the kind of broad, rich interaction that it did?
Wannemaker: Honestly, I know embarrassingly little about the technicalities of Brightstar's origins.  But I get the impression that it was the first scalable way in which users could interact with a broad variety of other users and media without a pre-defined purpose.
Kurt: Interesting.  And where do you think this is all heading?
Wannemaker: Well, I--
Kurt: Oh, wait.  I'm sorry.  The worm hole appears to be collapsing, I'll have to follow up another time, thank you greatly for speaking with us on a--

I really need to get that problem fixed.  Reality doesn't seem to like being torn apart.

In conclusion, Project Darkstar presented a well thought-out architecture, freeing the programmer from addressing the system's overall complexity, while insuring that the programmer's code doesn't negatively impact the whole system.  It's a good framework for a game, but an excellent foundation for a far more flexible system.  Tiered concurrency is already done in many applications.  It shouldn't be too long before the concept is applied to Darkstar, and it's true potential is unlocked.

GRUMPS Documentation: 4+1 Architecture

I'll be frank: the GRUMPS time machine is not the best documented device on the planet.  I mean sure, the polyphasic stretcher itself  has 6 or 7 research paper's worth of documentation, but its stable operation is dependent upon numerous layers of control logic.  The level of algorithmic complexity required to manipulate non-deterministic particles into deterministic states resulted in a broad-reaching, patchwork base of code.  Things would look functional, and then I'd find myself opening worm holes through the building's plumbing.

I've made a few attempts at retroactive documentation, some of which were helpful for a time, but most of which are currently out of date.  Last week, I had a wonderful interview cut short by some gravitational instabilities, and I've since been working on improving the longevity of my parallel calls.  It's given me a chance to revisit some documentation, and apply some new techniques to documenting the system.

Today, rather than an interview, I'll be giving a high-level glimpse of the underlying structure of GRUMPS' software system, using one of the views described in the 4+1 architectural style.

Below is the logical blueprint for the some of the main software systems involved in cross-time communication, and their interdependency:




 This kind of view establishes some advantages and disadvantages.  It's highly oversimplified, which can be useful in designing the core structure of the system, however, it seems somewhat disorganized despite its simplicity.  In part this is the fault of the designer, and in part of the expressive language.

A good architectural language doesn't merely exist to express organization, but can help a developer impose it.  I respect that 4+1 provides a limited language for each view to keep things scoped simply, but at the same time there are expressive benefits that other languages have.

4+1 doesn't express encapsulation in an intuitive manner.  I can draw lines to represent these relationships, but intuitively, I want to box some concepts around other ones.  And I want to specify actors in a diagram that doesn't ask for them.

Admittedly, I can express architectural layers from using the Development View, but this might cluster together functionality that isn't, well... functionally related.  I want to express the concepts that I consider important, not necessarily the ones dictated by a specification.  I've certainly been guilty of mixing diagram types in the past: frankenmaps of package and object structure in one, communication diagrams built from spare sequence diagram parts.

Like in UML, 4+1 leads me to ask: should I deviate from the specification because I find it clearer, or should conform to the specification because it is representing a quality of the system I am overlooking?

Only further documentation will tell.

Tuesday, September 1, 2009

The Great Mind: A Tale of Two Systems

Most of us have heard stories about the successes and failures of various software projects, and their relationship to code quality and planning.  What is the right approach to design?  Can one be both organic and purposeful?

The eternal BSD vs. Linux debate is a particularly interesting instance of some key questions as to the approaches one should take to design:
1. How much design is necessary up-front?
2. What level of flexibility should be built into each layer?
3. Are some forms of design better suited to particular arrangements of teams?

To answer these questions, I sought counsel from the highest authority in design: The Great Mind.  The human superconsciousness that emerged some time in the 29th century: an amalgamation of the world's total sentience and information-processing capacity.

Kurt: So tell me, Great Mind.  You seem the epitome of solid architecture.  Was your design more organically grown, or was it an accumulation of smaller, unrelated changes?
The Great Mind: COME TO LEARN YOUR PLACE IN THE GREATER DESIGN OF THINGS.
Kurt: Great Mind... the caps lock... can you--
The Great Mind: I UNDERSTAND YOUR FEARS AND WANT YOU TO KNOW THAT ALL IS PEACE.
Kurt: That's very nice, but you haven't really answ--
The Great Mind: BENEATH ALL CHAOS THERE IS ONENESS.  BENEATH ALL DISCORD IS ORDER.  THAT WITHOUT PATTERN DOES NOT EXIST.
Kurt: So, are you saying--
The Great Mind: RUMINA-- NO, DEAR, I'M ON THE PHONE.  I DON'T KNOW.  IT'S THE PAST.  LOOK.  I--  JUST A SECOND.
Kurt: Great Mind?
The Great Mind: I UH... I HAVE TO GO.
Kurt: So--

The Great Mind then hung up and I felt a warmth and fullness of being not unlike love or a good taco.  I felt the peace and grandeur of knowing that my question was answered, but was incapable of fully understanding or describing that answer.

Maybe The Great Mind was running the Linux kernel?

Zax Bambala: Understanding Quality Attributes

What makes software good?  Is there any simple metric by which Rational ClearCase is technically atrocious, or is the concept more amorphous than that?  Are timeless indicators of quality, or is quality simply determined by the technological background of a specific era?

To probe deeper into these questions, I interview Zax Bambala, co-founder and Chief Designer of the wildly successful webware firm Locatorium.  Over the course of 5 years from 2024 to 2029 they emerged nowhere with promises of "never lose an object again", becoming the foremost leaders in the (inaccurately titled) atom-tagging business.  Customers simply installed an air freshener in their home, which slowly released dust-like micro-bio-RFID chips, eventually coating all their belongings in uniquely-identifiable electric chips, enabling them to be found by computer.

Kurt: Mr. Bambala, it's a pleasure to have you here.  I'm sure many of our readers are extremely curious as to the background of Locatorium.
Bambala: Always a pleasure to talk to the past, do some good.  Locatorium has humble beginnings.  One week, I lost my key-tags on three separate occasions, costing me hours, and I just thought "there has to be a better way".  So I talked to some friends working in nanotech, we figured a way to identify it all, they built some air fresheners, I wrote some software, people liked it, IPO, and now I'm here.
Kurt: Very inspirational.  So such a system as yours must incur strenuous demands: heavy security concerns, high information bandwidth to process.
Bambala: Oh, most certainly.
Kurt: So, how did you design a system capable of handling all those requirements?
Bambala: What do you mean?
Kurt: I mean, how did you make your software secure and flexible and always available?  How did you cope with the computational demands of ever-expanding user-base?
Bambala: Well, we rented out more virtual servers... I'm not totally sure what you're asking.
Kurt: Well... when you started this project, what was the first thing you did on the software side?
Bambala: Oh, well we sketched up the user interface, and defined the data the system would need.  Compiled, tested, solicited feedback, redesigned, compiled, tested, and so on, just like any software project.
Kurt: There seems a rather large step missing there... I mean what is the central architecture of your system?
Bambala: The framework?  Oh, we just used Q# Rails.
Kurt: And the performance and--
Bambala: Look.  I learned a little about security and performance and all these words you keep throwing around in college, but honestly, I never touch any of that stuff.  That's defined by the framework.  I'm not really a software engineer, I'm a software designer.  Userware, you know.
Kurt: So, you didn't write any communication code at all?  You didn't designate modules and diagram out interactions at all?
Bambala: I told you already: I defined the data and UI and compiled.
Kurt: Surely you at least picked the operating system it was all running on?
Bambala: Again, another one of those college words.  We should have done this interview 12 years ago.  [He laughs].
Kurt: So, if these quality metrics don't define the quality of your software... what does?
Bambala: A good idea, a good user interface, good service, effective communication with users.  You want to know all that low-level architecture stuff, talk to a company like Microsoft.  I'm here to create a vision, not to fiddle with electrons.
Kurt: Very insightful, Mr. Bambala.  Thanks again for your time.  Are there any parting words you have to offer the people of the past?
Bambala: I suppose one thing: If you register Locatorium.com before me, it wouldn't be hard for me to find you.  I'm here to encourage the field, not to sell myself out.

I was initially taken aback by his responses.  What self-respecting programmer ignores topics so large?  I spend so much time complaining about poorly-designed systems that I've come to regard negligence in these manners as unexcusable.

But then I realized: when was the last time I worried about the compiler I was using?  When was the last time I doubted the stability of my kernel, or had to tune the performance of my DBMS?  When was the last time I wrote my own networking code instead of using a library?

These tasks are relegated to a different kind of programmer now.  They are stable and effective.  Is it possible that most of the work I currently regard as the tasks and concerns of a programmer are solvable, packagable problems?

Security concerns are mostly the same on all systems.  Performance concerns are often addressed in the same ways.  Even the basic modular structure of a system is highly consistent across a variety of programs.  One need only look at the Ruby on Rails project to see the level of uniformity across widely ranging systems.

Business software can often suffer from quality problems, perhaps because quality is not their concern.  Just as most businesses have no interest in writing programming languages or IDEs, and thusly consider it a solved problem-- perhaps most businesses have no interest in writing quality software because they don't want it to be a concern.  It's hard to distinguish yourself by quality; it's something that should be given.

20 years from now, people are still modifying g++ (I've checked).  Some minority of "low-level" coders will be programming frameworks in "low-level" languages like Java and C#.  The majority of work programmers want to do is in the realm of functionality, and due to the reusable nature of software, it seems reasonable to assume that the majority of work programmers will do is in the realm of functionality.

Better start learning to diagram now.  Today's design patterns are tomorrow's assembly language.

Lewis Carroll: Toward Boxology

Hey, wait, lets pause for a minute now.  Where are we?

So, computers have beaten our best in chess, they have analyzed overwhelming volumes of information, they have made cross-global instant communication accessible to millions.  Through all the field's successes, through all the extraordinary powers bestowed by these machines, we may sometimes forget how much it is still a burgeoning field.

How early, exactly?  Well, Moore's Law is still putt-putting its way and form factors are ever-evolving.  Moreover, in the year 2009, many architectural styles still lack formal definition.  Tell me: do your threads share the same memory?  Is your database a set of data, or a piece of software?

In 1997, Mary Shaw and Paul Clements put forth a paper trying to establish a uniform set of definitions for architectural elements.  Were they successful?  To answer these questions, we've gotten 19th century writer and logician Lewis Carroll over the time phone.

Kurt: So, Mr. Carroll, tell me, how do you think formal taxonomies should be developed in a field?  Do centralized academic efforts make a difference, or must these things evolve informally?
Carroll: Well hither-tee and hither-toe, it's all a case of portmanteau.
Kurt: ...Pardon?
Carroll: The simplest task of brochuary won't combell a dictionary.  It's only through the fret and ferry of tea and top and woe.
Kurt: I... I'm sorry, do you mean to say that formal definition is irrelevent if meaning can inferred?
Carroll: And stirred the words with frem and firbs, the puzzle then became unnerved.  But since the morning fretters blurred, then most of it we know.

...this conversation actually went on like this for about 15 minutes before he began pointing out the constellations in my rug and excused himself.  This, from a man who made contributions to the field of symbolic logic?  Was this truly the opinion of a proto-computer scientist?

The discipline of computer science, despite the label is not a science.  It is arguably engineering in part, and math in part.  Computer scientists do not discover phenomenon about the universe and label them, they create them, and if used enough, they label them.  Furthermore, the things they label are of a purely informational nature: the things we label in computer science are some of the most fundamental ways of organizing the manipulation of information.

Because of this, there is a slight danger in excessively imposing definition upon concepts.  If (as Shaw and Clements define) a client/server model must be asynchronous, then what do you call a synchronous client/server?  "Something like a client/server, but synchronous instead, even though that's now by definition contradictory".  When we are building these things ourselves, then our definitions must only provide us enough to communicate a concept, but no more.

When you impose 12 columns worth of categorization on a single label, you risk rendering it overly specific, making the word less useful, and the application of your terminology less flexible.  To that extent, Carroll would probably agree with me.  Meaning can often be inferred.

If computer science were pure math, then particular phenomenon would have particular labels, without extraneous definition.  But computer science (and particularly computer architecture) is also engineering.  We give labels as far as is practical.  Yes, a formal taxonomy is helpful, and is being developed all the time through the efforts of IEEE, W3C, and ten dozen other standards bodies.  Kudos to Shaw and Clements for proposing a unified architectural style.  Just don't let them write it.