Envisioning a New Language: A Conversation With Sun Microsystems' Victoria Livschitz

   
By Janice J. Heiss, December 2005  

Articles Index

In January of 2003, we published an interview with virtual reality pioneer Jaron Lanier, who argued that, given the near impossibility of writing large bug-free programs, a new programming paradigm was needed. In February of 2004, Sun Microsystems principal architect Victoria Livschitz responded with her own views on the crisis in software, focusing on problems related to the counterintuitiveness of modern programming paradigms. She suggested ways in which the complexity of software development can be addressed in next-generation programming languages. Since then, she has filled in some details about what such a language, which she calls Metaphors, might look like.

Livschitz grew up in the Ukraine and Lithuania, two former republics of the USSR, where she competed in chess and mathematical Olympiads at the national level. She studied applied mathematics at Kharkov University in the Ukraine before coming to the United States, where she subsequently received a degree in computer science from Case Western Reserve University. After a four-year stint at the Ford Motor company, she came to Sun in 1997, where she has served as principal architect on several high-profile projects for major financial and automotive companies. She currently serves as a principal architect at Sun and as an adjunct staff member at Sun Microsystems Research Labs.

We caught up with her to get her most recent thoughts on complexity, intuitiveness, her new Metaphors language, and the future of software.

question Before we discuss your new Metaphors language, give us a brief assessment of the state of programming today. Not everyone agrees that things are as bad as you claim.

answer Most software leaders will not speak publicly about the deepening software crisis. But in private conversations, many will admit that the problems of cost, complexity, and quality of software development are daunting.

The overall scale and complexity of software systems is increasing. Individual projects can't develop entire solutions themselves, so the pieces must come from different places. Enter design by contract, a powerful idea taken for granted in our industry. Components, loose coupling, and standardization of interfaces become the basis of software development ecology.

"The ratio of dollars spent on new features to dollars spent on certification and support goes down fast as the number of standard interfaces goes up."
 
 
Victoria Livschitz
Principal Architect
Sun Microsystems
 
 

But what if the energy to develop and support these contracts is overwhelming? A system that consists of just five standard components, each available in four commercial implementations, produces up to 1024 configurations to test, certify, and support. How does this scale out? According to a distinguished engineer from IBM, a recent internal study revealed that only about one in three dollars that IBM spends on software product development goes toward new features. The other two-thirds are spent on non-value-added integration costs.

IBM is no less efficient in software development than the rest of the industry. Mathematics is hard to argue with. The ratio of dollars spent on new features to dollars spent on certification and support goes down fast as the number of standard interfaces goes up. Two-thirds of non-value-added costs is already hard to swallow. What if that becomes four-fifths or nine-tenths?

A number of senior software people know that we are in deep trouble and that we don't have a get-well plan, but it's not profitable to talk too much about it -- except as a sell point for the new miracle product of the day.

question Do you see a way out of this through a new programming language?

answer Historically, advances in software engineering have tracked advances in programming languages. FORTRAN, C, C++, and the Java language, for example, all took software engineering to a new level and absorbed another order of magnitude of scale and complexity into software development projects. So investing one's energy in search of better programming languages to fix software development challenges seems like a reasonable starting point to me.

The problem is that modern software development is no longer mostly about programming. My wild guess is that something like 90 percent of software development happens outside of programming languages. Dozens of nonprogramming disciplines, from information security to release engineering to program management, define modern software development. Each discipline employs different principles, methods, and tools. Each requires specialized skills and educational backgrounds.

A specialist uses a microscope to zoom in on one aspect of the system. Microscopes don't show cracks and gaps in the structural design of the overall system or hidden dependencies between subsystems. Where are our binoculars? Who provides the aerial surveillance of the systemic concerns of the systems we build?

Consider a typical web service-based application running in a datacenter of a Fortune 500 company. When a failure occurs at runtime, is it the web service, the application server, the cluster, the service provisioning software, the monitoring tool, or the operating system that must react to the situation?

In most cases, the response must be carefully coordinated across all layers, with each technology doing no more and no less than necessary. Which means that either (a) there is an overall system designer who assures the perfect separation of concerns between the layers, or (b) application developers and systems administrators must each thoroughly understand the application and its hosting environment and be able to reason about complex interactions between them. Neither is true in practice or even theoretically possible in the large-scale open-systems world.

Now back to the question of the role of programming languages. As Alan Perlis put it, "A good programming language is a conceptual universe for thinking about programming." What we need is not just another programming language but a conceptual universe for thinking about software development, embodied in a kind of language that is new to computer science -- a language that will bridge the gap between programming and software development at large.

The Metaphors Language -- A Way out of the Crisis

question How does the Metaphors language that you envision differ from the Java language?

 
"Imagine a virtual machine and distributed runtime environment that in principle subsume the functionality of the application containers and middleware."
 
 
Victoria Livschitz
Principal Architect
Sun Microsystems
 

answer Metaphors finds its inspiration in the careful synthesis of ideas that have been proved to work and scale out well elsewhere. Some ideas come from previous computing frameworks, while others come from what some people call biologically inspired computing.

Let me pick the runtime characteristics first. Here, Metaphors borrows many ideas from the Java language, Java Platform, Enterprise Edition (Java EE) architecture, Jini technology, and the JXTA project. I assume that local runtime environments for programs would be provided by a virtual machine (VM). However, I'd like to go much further down the path of giving the local virtual machine (LVM) the ability to act as a container for managed application code.

Imagine a virtual machine and distributed runtime environment that in principle subsume the functionality of the application containers and middleware. Distributed properties of applications will emerge through the collaboration between many LVMs that host parts of the same distributed application. Conceptually speaking, the execution of distributed applications is the responsibility of the distributed runtime core (DRC) that comprises a peer-to-peer network of LVMs.

Let's say a developer will specify in a program that a car has four wheels. At runtime, the executable for each wheel may be loaded into any available LVM at the discretion of the DRC. The interactions between the wheels and the rest of the car will be brokered appropriately by the DRC and LVMs without explicit control by the developer or network administrator. The exact location of each wheel at any point in time is not deterministic but emergent from a combination of factors, including dynamic workload on LVMs, security and management policy of DRC, or configuration of devices that are hosting LVMs.

Eliminating Middleware?

question Could your approach eliminate middleware altogether?

answer I hope so, to a large extent. Middleware will still play a role from an interoperability standpoint. But some basic needs of distributed applications, such as load balancing, failover, remote communications, mobility of services and their containers, quality of service, and service-level management, can all be embedded into a runtime environment for the language.

Collapsing LVM with containers and middleware should make the development of distributed applications a much simpler process. In one way, I see Metaphors not so much as a successor to the Java language but rather as a successor to complicated, disjointed, and proprietary middleware stacks.

Principal Features of Metaphors

question What are some other principal aspects of Metaphors?

answer Metaphors attempts to address four topics essential to software development that are traditionally handled outside of the programming language. The first is support for distributed runtime environment, which I just talked about. The other three are (a) support for contextual programming, (b) support for autonomous executable entities, and (c) support for software evolution and reuse.

"Some basic needs of distributed applications, such as load balancing, failover, remote communications, mobility of services and their containers, quality of service, and service-level agreements, can all be embedded into a runtime environment for the language."
 
 
Victoria Livschitz
Principal Architect
Sun Microsystems
 
 

Let's talk about contextual and computational programming -- and why it's important to create a formal framework to distinguish them.

A functional behavior of the application cannot be expressed without a contextual model for the application domain. For example, in order to codify a simple business rule, say, "Transfer X amount of dollars from Y account to Z account," there has to be a formal definition of the concepts of account, transfer, dollars, and amount. Once the context is set, one can write down the proper algorithm for fund-transfer function. The context, on the other hand, cannot be defined in isolation from the intended functionality of the application.

As you can see, two sharply distinct intellectual activities are competing for the developer's attention. One aims to define a context for the application's functionality, and the other codifies the functional rules of the application's behavior within a given context. I refer to these as contextual programming and computational programming.

Traditional computer science has always been consumed with computational programming, while contextual programming has been largely ignored until the advent of object-oriented programming (OOP). OOP established the separation of the analysis and design stages of the project (mostly concerned with contextual programming) from the implementation stage (mostly concerned with computational programming). OOP also introduced several convenient built-in context-building facilities such as classes, interfaces, and abstract data types.

However, the explicit difference between contextual and computational programming is not supported in object-oriented languages. Instead, OOP relies on methodologies, external tools, and special-purpose languages -- most notably UML -- to address contextual programming outside of the programming language. Subsequently, the separation of context from computation in modern software development is based on the timing of the project's life cycle. This is a good idea wrongly framed. Software development is a continuous, iterative, and evolutionary activity. Neither context nor computation comes before the other. Both are organically related and belong to the same code base.

Overcoming Counterintuitiveness

question Last time we talked, you argued that there is a connection between the counterintuitiveness of modern computing paradigms and software quality. How are your ideas on making programming more intuitive playing out in the Metaphors language?

answer I coined the term contextual programming specifically to deal with that question. Imagine a team of developers involved in a complex software project. All team members, old-timers and newcomers alike, must have a shared understanding of the application context. Collectively, they evolve that context over time, adapt to changing business requirements, and absorb contextual ideas from other projects.

These developers are engaged in the process of analyzing and designing complex adaptive systems, in all their splendor and complexity. Certain questions will arise: What are the elements of this system? How are these elements organized? What kind of relationships exist between the elements? How do elements communicate? What rules are governing the behavior of each element? How does the system change over time? What processes are governing that change? How does this system interact with other systems? And so on. The developers need formal yet intuitive tools to describe general-purpose systems.

I envision a set of core system-level constructs built into the language, designed to make the task of the formal codification of systems a far more intuitive process, as compared to programming in object-oriented languages. A partial list of good candidates for core constructs includes entity, process, organizational principle, condition, relationship, event, and rule.

Several such constructs will be supported directly in the programming language as "primitive" metaphors. User-defined metaphors can be created incrementally from primitive metaphors using a formal extensibility framework supported by the language.

The Executable Entity

question What is an executable entity, and what problems does it solve?

answer I can observe that contextual programming constructs serve to formally define an application's abstractions and codify a programmer's thought process, not to do any "real work." That real work is the prerogative of computational constructs. Contextual programming statements therefore create logical -- not executable -- entities. They are of practical use to application designers who need to fix, extend, or reuse the context now or later. However, at runtime, some statements must be executed for a program to be of practical use to end customers.

It seems important to introduce a concept of executable entity, decoupled from the metaphorical constructs of contextual programming. Of course, executable entities may need to be generated from the contextual constructs. Something similar is going on in OOP, where executable entities (object instances) are generated from logical entities (classes). My executable entities, though, are going to be very different from conventional object instances that are sitting on a heap or a stack.

The world around us that we attempt to simulate, automate, and control via software is profoundly autonomous and asynchronous. When an apple falls from the tree and hits the ground, the phenomenon can be observed as a sequential process, but it cannot be understood as such. The sequence of events is accidental, an emergent property of the system tree-apple-ground. An apple falls autonomously when the force of gravity overcomes the force of the apple's attachment to the tree branch. The tree and the ground respond to the force applied to them by the falling apple with counterforce, also autonomously.

Unfortunately, modern programming is profoundly passive and sequential. Execution starts with some bootstrapping mechanism, like main(), that induces a chain of sequential, passive request-response invocations. Things like events and messages are special-purpose mechanisms that have been devised to allow for some illusion of autonomous behavior. True concurrency requires complicated multithreading machinery and a special-purpose programming model that is not only notoriously difficult to master but also inherently dangerous because of the unpredictability of deadlocks and race conditions.

Building concurrency on top of a sequential automaton is a bit like trying to explain quantum physics as an extension of Newton's laws. Both are probably better done the other way around.

I'd rather assume that everything is autonomous and asynchronous. Application runtime consists of autonomous executable entities, or agents, as some would call them. These agents interact with their environment and each other asynchronously, respond to external stimuli, and initiate actions out of "free will." They may exert a force or be subjected to a force field, which basically means that their ability to choose their actions will be constrained by the circumstances.

One interesting technical challenge is to devise a program execution model that will be able to efficiently support thousands -- if not millions -- of autonomous executable entities that are active at all times, even though truly interesting events happen to them only once every millionth or billionth cycle.

Formal Extensibility Framework

question What do you mean by the formal extensibility framework that you mentioned earlier?

answer I'd like to build a rich set of reuse mechanisms directly into the language. Aside from inheritance, reuse today happens outside of the programming language. Unmanaged "copy and paste" is probably by far the leading code-reuse technique. The best-known form of design reuse is the design pattern, which is usually conveyed by a picture and words. The success of reuse depends squarely on the discipline and skill of the developer. Yet the formal rigor of the programming language's grammar and type system can be very effective in the facilitation, validation, and enforcement of reuse.

Classic inheritance works that way, and it proved to be quite useful for reuse, both on the interface and implementation side of things. Why not go further? For example, consider reverse inheritance -- the ability to define a new entity as a generalization of an existing one. A Class Vehicle abstracts class Car kind of statement may be extremely useful in a variety of scenarios.

In principle, I see three general-purpose reuse mechanisms that can be formally supported by the grammar of the language. The first is derivation, which specifies the rules of creation of a new metaphor by changing properties of the existing metaphor. The second is composition, which specifies the rules for creation of a new metaphor as an aggregate of several existing ones -- or the direct opposite of that, the decomposition of an existing metaphor into several metaphors. The third is adaptation, which specifies the rules of lightweight "morphing" protocol that can be used to adapt a metaphor developed for one domain to the needs of another domain, if the two are properly isomorphic -- by which I mean that they are either identical or similar in form, shape, or structure.

The Process Metaphor
 
"If programmers naturally think in terms of metaphors and recursively build higher-level metaphors from lower-level ones, then that should be the model for the software creation process supported by the programming language."
 
 
Victoria Livschitz
Principal Architect
Sun Microsystems
 

question Walk us through one of your favorite metaphors.

answer Process is an interesting one. Nature is full of repeatable processes, and so is human life -- for example, the change of seasons, a daily exercise routine, an engine start-up sequence, a loan application approval process, evacuation procedures, and so on.

I'd like to make process one of the core contextual abstractions, thus allowing for abstract declaration and definition of processes, gradual refinement of process definition over time via the extensibility framework, and concrete implementation of process logic in an executable entity. In a way, predefined process is the opposite of emergent behavior. Processes themselves can be the products of emergent behavior, of course. The point is that the "process" abstraction can be used to bring algorithmic sequencing into the world of autonomous and asynchronous executable entities.

Let me illustrate one aspect of what the Metaphors language should be able to offer developers using the process metaphor. Let's say a designer of a next-generation file system creates a metaphor to capture a process flow for reading or writing to a file, codified into a three-step algorithm:

{open_file -> [perform_action]* -close_file}
 

Imagine also another three-step process metaphor used by a designer of a virtual machine for management of short-lived, transient objects, codified as

{create_object -> [perform_method]* -> destroy_object}
 

In a certain sense, both algorithms seem isomorphic. It is useful to be able to see that and draw conclusions based on that observation.

Suppose the designers of the file-access algorithm later notice that they have missed one important step in the process. So they derive a new version of the algorithm:

{acquire_file_handle -> open_file -> [perform_action]* -> close_file}
 

How does this discovery affect the designers of the virtual machine? At the very least, it should give them food for thought. Did they make the same mistake, or was the perceived isomorphism misleading? Upon careful consideration, they find that the parallel between the long-lived file handler and the short-lived object reference is not complete. However, they are currently working on the implementation of long-lived persistent objects. There, they indeed can reuse the file-access algorithm through an isomorphic transformation, which results in

{acquire_object_reference -> restore_object -> [perform_method]* -> store_object}
 

Programming languages should facilitate this kind of reasoning.

Why "Metaphors"?

question Why do you call your language Metaphors?

answer Metaphors is a tentative name I chose to define a unit of software because people seem to reason about the unknown in terms of analogies with the known.

Take almost any computer term -- programming language, virtual machine, register, memory cell, stack, queue, tree -- and you'll find a metaphor for some physical entity or process or well-understood previously defined metaphor. If programmers naturally think in terms of metaphors and recursively build higher-level metaphors from lower-level ones, then that should be the model for the software creation process supported by the programming language. Eventually, I hope to facilitate a style of software development in which one can say, in a programming statement, "The contextual model of this application is just like a contextual model of that application, except..." and then define exactly how the two are different.

Addressing the Crisis

question Give us a summary of how all this addresses the software crisis.

answer I guess I'd like to finish with a famous quote from Fred Brooks' classic work, The Mythical Man-Month : "Plan to throw away one prototype. You will, anyhow."

I believe it's time to step back and consider the first 50 years of computing as one gigantic prototype. If we had the courage to start over, we could build a new software creation and execution model to address the software engineering challenges of the 21st century, such as distributed processing, autonomic computing, and software evolution -- natively, within one conceptual universe. The programming language is a great place to start.

Will we be starting from scratch? Well, yes and no. The changes I am talking about require a very deep cut into the programming, execution, memory management, and threading models -- just about everything that makes up a programming language. On the other hand, collectively, we are armed with decades of experience building virtual machines, functional languages, middleware, clusters, service containers, databases, operating systems, communication networks, etc. We also can and should look to Mother Nature for inspiration on how to build human-made, resilient, scalable, evolving systems. There is quite a bit of conceptual capital that exists in this area as well.

See Also

Contact Victoria Livschitz
victoria.livschitz@sun.com

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.