To oversimplify, there are two primary approaches to software concurrency: lock-based and message-based.
Lock-based concurrency is done primarily to separate out listener threads, and to enhance program performance. Multiple threads can (and generally) do share access to some data, which is protected by locks. Though this mechanism is mathematically reliable, in practice, implementation can be very tricky, and all sorts of bugs can arise out of it.
Message-based concurrency has a different focus: it utilizes parallelism chiefly for program reliability. Each thread exists as independent tasks, sharing no memory and communicating only through asynchronous messages. Though this approach can have performance drawbacks (particularly if much data needs to be passed back and forth), it is a simpler abstraction to work with, and is probably more conducive to generating stable programs, since program errors can be easily encapsulated within a single errant thread. Importantly, a well-organized, hierarchical ordering of task parallelism can scale far more easily; not only can threads easily run distributed across multiple machines, but a hundred-fold increase in thread count requires no extra concurrency organization, simply more processing power.
Joe Armstrong uses the term "Concurrency-Oriented Programming" to describe the design approach centering around large, message-based programs. This methodology involves identifying a program's tasks, outlining their interdependence, defining their message exchange, and then coding a direct translation of this task organization. So, how well does this approach work?
To find these answers, I traveled to 2035, to sneak an interview with AMD Lead Compiler Developer Roto Mitsumi.
Kurt: Mr. Mitsumi, back in 2009, we're still figuring out an idea scheme to parallelize our software. Can you provide us any insight into approaches we should consider?
Mitsumi: It is with great honor that I am to speak to your time. I am most humbled to have the opportunity to discuss my experience on behalf of my benevolent employer, AMD. It is--
Kurt: Mr. Mitsumi. Please, our time is limited.
Mitsumi: My sincerest apologies. If only we could parallelize this interview.
Kurt: Yes, ha. Ha. Very good. Please.
Mitsumi: The first thing one must bear in mind is the reason we want to parallelize programs in the first place. Form must follow function. A program must be a suitable abstraction of its executing hardware. So, as chips become parallelized, so must programs.
Kurt: Yes, that's where we are now.
Mitsumi: But if I am recalling correctly, that's not entirely where you are. Because you have CPUs with multiple identical cores. This does not last for long. The average mid-range AMD CPU released now has over 1000 cores, of many varieties. There are a few dozen dedicated vector cores, a few hundred cellular automata processors, a few hundred x256 cores, and many, many different optimized RISC processors.
Kurt: So, how does this affect design?
Mitsumi: Well, a programmer cannot possibly be aware of the precise system configuration, or even the type of processors available. He must be able to code in a fashion independent of the underlying instructions. To do this, the relationships between threads must be very explicitly defined.
Kurt: Are you describing a message-passing system of concurrency?
Mitsumi: Yes and no. In a traditional message-passing system, the programmer himself must define the communication. The structure emerges from the messages. This can become unmaintainable when one begins spinning off a few hundred threads. Refactoring can be profoundly challenging. Instead, we take a different approach: one still maintains the independence of threads, but instead works with the data, a much simpler abstraction to refactor around.
Kurt: Isn't that the opposite of a message passing system. So where do the messages come in?
Mitsumi: It depends on where you are looking. When the code is compiled, all messages are automatically generated from the data access. When executing, no data is actually directly shared by the threads: it is still passed by messages, but the messages are automatically generated. All a developer must do is hierarchically define a data structure, and evaluate the resulting message structure for deficiencies, performance bottlenecks.
Kurt: So, a developer can still think in objects, even while his code executes as messages?
Mitsumi: Your language is technically incorrect, but the idea is right. Most modern processors try to prioritize interprocessor message passing over shared memory access. The more cores you have, the less efficient it is to access shared memory, and we're at a point where such a system would be an unfathomable bottleneck. Because of this, the vast majority of modern computers distribute memory across the motherboard. Message-passing is how nearly all non-quantum machines will proceed.
Kurt: Interesting. I'll be curious to see this unfold in the next few decades.
There you have it. Message passing does come with its own limitations and complexities, but it is scalable, and the advantage of that cannot be underestimated as our hardware evolves. Any technique that will last in this domain must be able to cope with complexity an order of magnitude higher than most programmers currently address.
Tuesday, October 20, 2009
Thursday, October 15, 2009
GRUMPS Design: Preventing Time Paradoxes with CHESS
An integral part of current GRUMPS design was finding ways to detect and avoid potential time paradoxes. On my first outing, I attempted to assassinate Hitler, setting off a wild cascade of unpredictable events: I postponed the invention of the transistor, changed the country my grandfather settled in, and popularized disco three decades too early. Things progressed so wildly until damn-near the whole universe crashed. Were it not for the last-minute interference of some vastly more experienced time travelers, the end result could have been truly disastrous.
It is of key importance to ensure the operational consistency of a system, particularly in parallel or chaotic domains. Potential race conditions, deadlocks, and death-of-your-grandfather-prior-to-your-birth scenarios may remain unseen for years after a system is deployed. Predicting, identifying, and repeating these unstable scenarios is necessary for system-wide stability.
But how does one test for these kinds of conditions? Optimally, one will explore as many scenarios as possible, emphasizing the ones likely to produce errors. The "small-scope hypothesis" speculates that the majority of problems can be discovered by simple tests--that problems arise from the breadth of possible scenarios, rather than the depth. You could theoretically describe any software as a superbly complex state-machine, with state transitions described not only based on user input, but environmental factors like thread interrupts.
If one could construct such an elaborate tree (even for just a few seconds of potential behavior) then the small-scope hypothesis could be objectively tested by performing Djikstra's algorithm on the starting state, and using that to calculate the average number of state transitions before an error occurs. In all likelihood, most bugs can arise from a simple, but highly-particular thread interweaving.
In the field of Time Travelology, this kind of metric is discussed most frequently in chaos theory: how does a slight perturbation at a moment in time cascade into the future? Because most errors are small-scope (that is, the instability begins soon after the interruption), I have found it imperative to clean up these unstable branches immediately after creation.
For assistance, I use a highly modified version of the CHESS model checker. GRUMPS will create a small bubble of unstable space-time, performing a quantum simulation of a vast array of possible short-term futures. (As a fascinating aside, note that a quantum simulation is, for all practical purposes, an actual progression of reality... quantum simulation is indistinguishable from reality itself). CHESS' interleaving algorithm is utilized to scope these futures, quickly pinpointing unstable ones. Once the stablest one is identified, the quantum superposition collapses, the unstable states are thrown into the universe's dustbin, and I leave as if I had never come, my only disturbances insubstantial on a large scale.
Complex systems are inherently chaotic. We can attempt to control this chaos (say, by stress testing), or we can attempt to manipulate it into its unstablest forms (by controlling thread interleaving). From experience, I'll have you know that the latter tends to be vastly more reliable, having saved my programs and the very consistency of space-time on a number of occasions. Otherwise, you might still be a slave to Xuth!a, the bionic emperor-god who rose to power when I once accidentally spilled the beans about 23rd century biotech to a certain Henry Kissinger.
It is of key importance to ensure the operational consistency of a system, particularly in parallel or chaotic domains. Potential race conditions, deadlocks, and death-of-your-grandfather-prior-to-your-birth scenarios may remain unseen for years after a system is deployed. Predicting, identifying, and repeating these unstable scenarios is necessary for system-wide stability.
But how does one test for these kinds of conditions? Optimally, one will explore as many scenarios as possible, emphasizing the ones likely to produce errors. The "small-scope hypothesis" speculates that the majority of problems can be discovered by simple tests--that problems arise from the breadth of possible scenarios, rather than the depth. You could theoretically describe any software as a superbly complex state-machine, with state transitions described not only based on user input, but environmental factors like thread interrupts.
If one could construct such an elaborate tree (even for just a few seconds of potential behavior) then the small-scope hypothesis could be objectively tested by performing Djikstra's algorithm on the starting state, and using that to calculate the average number of state transitions before an error occurs. In all likelihood, most bugs can arise from a simple, but highly-particular thread interweaving.
In the field of Time Travelology, this kind of metric is discussed most frequently in chaos theory: how does a slight perturbation at a moment in time cascade into the future? Because most errors are small-scope (that is, the instability begins soon after the interruption), I have found it imperative to clean up these unstable branches immediately after creation.
For assistance, I use a highly modified version of the CHESS model checker. GRUMPS will create a small bubble of unstable space-time, performing a quantum simulation of a vast array of possible short-term futures. (As a fascinating aside, note that a quantum simulation is, for all practical purposes, an actual progression of reality... quantum simulation is indistinguishable from reality itself). CHESS' interleaving algorithm is utilized to scope these futures, quickly pinpointing unstable ones. Once the stablest one is identified, the quantum superposition collapses, the unstable states are thrown into the universe's dustbin, and I leave as if I had never come, my only disturbances insubstantial on a large scale.
Complex systems are inherently chaotic. We can attempt to control this chaos (say, by stress testing), or we can attempt to manipulate it into its unstablest forms (by controlling thread interleaving). From experience, I'll have you know that the latter tends to be vastly more reliable, having saved my programs and the very consistency of space-time on a number of occasions. Otherwise, you might still be a slave to Xuth!a, the bionic emperor-god who rose to power when I once accidentally spilled the beans about 23rd century biotech to a certain Henry Kissinger.
Tuesday, October 13, 2009
Lewis Carrol: Refactoring for Reentrancy
For years, functional programmers beg the world to see the glory that is reentrant functions: methods that will execute the same every time they are run. The world ignores them for decades, and only now is finding out that they weren't just crying wolf.
Reentrant programs have a number of advantages: they are easier to test and analyze; automated tools can ensure some types functional correctness, instead of mere syntactic accuracy; but in particular, they are guaranteed not to result in thread conflicts since they only utilize local and passed variables.
Danny Dig's Refactoring for Reentrancy is a program designed to analyze and modify code to bring it back to the functional utopia of reentrance. By converting static variables into local ones and flagging access to global variables or libraries, programmers can more easily ensure the thread-safety of their programs.
The things the Reentrancer can do are interesting, but the things it can't do I find even more interesting. Namely, it has no way to assure the reentrant qualities of library calls, and can only infer it by comparing log files. This reveals an interesting limitation of Java I had not previously considered: you can declare Java methods as static, forcing them to utilize only static variables, but you can't do the opposite; you can't declare Java methods as reentrant, forcing them to utilize only local and passed parameters. The synchronized keyword can simplify the creation of reentrant methods, but it cannot guarantee it. It seems that this would be a useful addition to the Java language, particularly help clarifying certain attributes of library calls.
Functional programmers would argue that its almost nonsensical for a function to behave inconsistently, depending upon a global state. For some insight, I returned to 1890 for a brief conversation with master of logic and nonsense: Lewis Carrol.
Kurt: Mr. Carrol, when do you think it's appropriate for a logical function to return different answers?
Carrol: Well, a close friend of mine once faced this dilemma:
Reentrant programs have a number of advantages: they are easier to test and analyze; automated tools can ensure some types functional correctness, instead of mere syntactic accuracy; but in particular, they are guaranteed not to result in thread conflicts since they only utilize local and passed variables.
Danny Dig's Refactoring for Reentrancy is a program designed to analyze and modify code to bring it back to the functional utopia of reentrance. By converting static variables into local ones and flagging access to global variables or libraries, programmers can more easily ensure the thread-safety of their programs.
The things the Reentrancer can do are interesting, but the things it can't do I find even more interesting. Namely, it has no way to assure the reentrant qualities of library calls, and can only infer it by comparing log files. This reveals an interesting limitation of Java I had not previously considered: you can declare Java methods as static, forcing them to utilize only static variables, but you can't do the opposite; you can't declare Java methods as reentrant, forcing them to utilize only local and passed parameters. The synchronized keyword can simplify the creation of reentrant methods, but it cannot guarantee it. It seems that this would be a useful addition to the Java language, particularly help clarifying certain attributes of library calls.
Functional programmers would argue that its almost nonsensical for a function to behave inconsistently, depending upon a global state. For some insight, I returned to 1890 for a brief conversation with master of logic and nonsense: Lewis Carrol.
Kurt: Mr. Carrol, when do you think it's appropriate for a logical function to return different answers?
Carrol: Well, a close friend of mine once faced this dilemma:
And on mid-summer mornings, she'd slip back in the hole,
To see what the darkness could lend,
But each interaction left her clarity dulled,
Since the liars all claimed they were friends.
And the truth-tellers told her the truth time-to-time,
And at other points offered a joke.
But she never could tell which was which in their rhyme,
Since all of them laughed when they spoke.
Each time they would offer the same foreign names,
And spoke in the same awkward voices.
But it never was clear if their stories were games,
Since each time they would make different choices:
Was it blue he preferred? No, this time it was red,
Though Alice had asked the same question.
She never was sure why the Cheshire said
"You must make your discourse reentrant."
Frank Lloyd Wright: Rereading the Classics
Kurt: Hey, Frank Lloyd Wright?
Wright: Oh no. Not you again.
Kurt: No, no, this is just a courtesy call.
Wright: What kind of courtesy?
Kurt: I'm just letting you know that more people are complaining about Fallingwater.
Wright: What!? How is that courteous?
Kurt: I'm just saying, maybe you should have taken a more modular approach.
Wright: What does that even mean? If I ever live long enough to find you--
Kurt: Oh. You won't.
Man, I love time traveling.
Three, largely unrelated points brought to mind by a recent paper Rereading the Classics, by Panagiotis Louridas:
Why do people consider weak typing an advantage?
Yes, it will save you the laborious effort of declaring a variable type, yes, it will save you the effort of having to declare classes or interfaces for polymorphism. But neither of these are particularly time-consuming or challenging processes. The effort you save by not generating an interface is far overshadowed by the challenge you will have later trying to decipher your code.
What is a function taking? Can I get a list of types I can pass in? With strong typing, you can. With duck typing, you're in trouble. Java got this one right. Interfaces are lightweight, flexible tools to address polymorphism. If you disagree, then I suspect that you don't know how to use interfaces properly.
Why is there a distinction between "classic" languages and "pragmatic" ones?
An interesting distinction is brought up between those uncompromising, yet broadly influencial languages that never take off in industry (Lisp, Smalltalk), and those more-compromising languages that eventually do (Java).
It casts a spotlight on the question: when is compromise acceptable in a language (or architecture)? Consistency and simplicity are generally optimal: they give a developer a clearer understanding of how to work within the environment.
One of my favorite features in Smalltalk is the way in which it sidestepped the performance penalties of a strictly object-oriented framework: even though all operations are defined as smalltalk code, functions may also defer to optimized assembly commands, substantially speeding up things like arithmetic. However, if a developer wished to modify any of these functions, he can still modify the Smalltalk code, ignoring the assembly optimization. This was one of the few structural compromises in the language, and it was a very powerful one.
What made Java more widely adopted than Smalltalk in industry? There's a host of non-technical reasons (the backing of Sun, good timing), and many technical ones (simplified deployment over the web through [much-derided] applets, in-order arithmetic expressions, the ability to implement many interfaces in a single class, support of C-style primitives). The more tools you give developers to work with, the more people will willingly adopt the language. The added flexibility doen't necessarily make a language superior, but it does make it more accessible, and a large development community is the single most powerful attribute a language can have: someone, somewhere will find a way to do what you want to do, and make their suggestion public.
Biocomputers and quantum computers the two most substantial paradigm shifts in 21st computing) will most likely follow a similar pattern. A powerful, inflexible language will be created and be met by all sorts of worship by the academic community, but the technology will only take off once a more familiar language is released incorporating aspects that made the uncompromising language so powerful.
Does form in always follow function in a programming language?
The article gives much focus to the statement that "form always follows function" in nature, and so should it in technology. What does this mean exactly?
Well, one good example is that most languages are structured in a sequential manner, mirroring the capabilities of the underlying hardware paradigm. Single-core execution predominated for decades, and our languages were built with that in mind.
There is a good chance that the increasing adoption of multi-core systems will eventually result in a new style of programming. Not merely synchronization control, or fork/joins, but an altogether new style. If form follows function, perhaps our code will eventually be split into parallel tracks, visually organized as a side-by-side list of streams of code. If the code is executing on multiple cores, it should probably *look* to a developer like it is executing on multiple cores.
Viewing the evolution of programming languages can provide a sense of how the field progresses, and, to some degree, can assist one in anticipating future changes. But perhaps more significantly, it can give one a better understanding of why things are as they are now. You never really understand your own country until you've visited another. You never fully understand your language unless you see the ideas that created it.
Wright: Oh no. Not you again.
Kurt: No, no, this is just a courtesy call.
Wright: What kind of courtesy?
Kurt: I'm just letting you know that more people are complaining about Fallingwater.
Wright: What!? How is that courteous?
Kurt: I'm just saying, maybe you should have taken a more modular approach.
Wright: What does that even mean? If I ever live long enough to find you--
Kurt: Oh. You won't.
Man, I love time traveling.
Three, largely unrelated points brought to mind by a recent paper Rereading the Classics, by Panagiotis Louridas:
Why do people consider weak typing an advantage?
Yes, it will save you the laborious effort of declaring a variable type, yes, it will save you the effort of having to declare classes or interfaces for polymorphism. But neither of these are particularly time-consuming or challenging processes. The effort you save by not generating an interface is far overshadowed by the challenge you will have later trying to decipher your code.
What is a function taking? Can I get a list of types I can pass in? With strong typing, you can. With duck typing, you're in trouble. Java got this one right. Interfaces are lightweight, flexible tools to address polymorphism. If you disagree, then I suspect that you don't know how to use interfaces properly.
Why is there a distinction between "classic" languages and "pragmatic" ones?
An interesting distinction is brought up between those uncompromising, yet broadly influencial languages that never take off in industry (Lisp, Smalltalk), and those more-compromising languages that eventually do (Java).
It casts a spotlight on the question: when is compromise acceptable in a language (or architecture)? Consistency and simplicity are generally optimal: they give a developer a clearer understanding of how to work within the environment.
One of my favorite features in Smalltalk is the way in which it sidestepped the performance penalties of a strictly object-oriented framework: even though all operations are defined as smalltalk code, functions may also defer to optimized assembly commands, substantially speeding up things like arithmetic. However, if a developer wished to modify any of these functions, he can still modify the Smalltalk code, ignoring the assembly optimization. This was one of the few structural compromises in the language, and it was a very powerful one.
What made Java more widely adopted than Smalltalk in industry? There's a host of non-technical reasons (the backing of Sun, good timing), and many technical ones (simplified deployment over the web through [much-derided] applets, in-order arithmetic expressions, the ability to implement many interfaces in a single class, support of C-style primitives). The more tools you give developers to work with, the more people will willingly adopt the language. The added flexibility doen't necessarily make a language superior, but it does make it more accessible, and a large development community is the single most powerful attribute a language can have: someone, somewhere will find a way to do what you want to do, and make their suggestion public.
Biocomputers and quantum computers the two most substantial paradigm shifts in 21st computing) will most likely follow a similar pattern. A powerful, inflexible language will be created and be met by all sorts of worship by the academic community, but the technology will only take off once a more familiar language is released incorporating aspects that made the uncompromising language so powerful.
Does form in always follow function in a programming language?
The article gives much focus to the statement that "form always follows function" in nature, and so should it in technology. What does this mean exactly?
Well, one good example is that most languages are structured in a sequential manner, mirroring the capabilities of the underlying hardware paradigm. Single-core execution predominated for decades, and our languages were built with that in mind.
There is a good chance that the increasing adoption of multi-core systems will eventually result in a new style of programming. Not merely synchronization control, or fork/joins, but an altogether new style. If form follows function, perhaps our code will eventually be split into parallel tracks, visually organized as a side-by-side list of streams of code. If the code is executing on multiple cores, it should probably *look* to a developer like it is executing on multiple cores.
Viewing the evolution of programming languages can provide a sense of how the field progresses, and, to some degree, can assist one in anticipating future changes. But perhaps more significantly, it can give one a better understanding of why things are as they are now. You never really understand your own country until you've visited another. You never fully understand your language unless you see the ideas that created it.
Thursday, October 8, 2009
Functional vs. Object-Oriented Design
Supporters of functional programming are often deeply convinced of their methodology's superiority: its mathematical purity, flexibility, and conciseness. Object-oriented designers frequently consider this approach obtuse, and difficult to organize.
For all the vitriol and dogma surrounding these two approaches to programming, there are only three core I consider genuinely important:
Should one allow functions to modify state information, or merely return a value?
At the heart of this question is the concept of consistency. Should functions be permitted side effects? Arguably, this is the source of most instability in programs: the program enters an unexpected state as a result of functional side-effects and can no longer operate properly.
From a performance perspective, there's a lot of good reason to permit inter-function state modifications: it prevents the creation of an abundance of temporary values that need to be held in memory. From a mathematical perspective, it's just allowing noise into the system. Ultimately, these side-effects are a relic of modern hardware: The Von Neumann bottleneck makes frequent creation of temporary variables incredibly expensive. This is a by-product of the fact the modern architectures separate programs from data. This will change as our approaches to computing change: a well-designed quantum system will require no side-effects, since these intermediary calculations can be processed synchronously and in a highly-optimized fashion (multiple calculations on the same machinery at the same time, something currently impossible); a well-designed biocomputational system will contain densely-linked side effects, such that every function affects all others.
Should one allow functions to access information not directly passed to them?
This is largely a question of syntax, really. Effectively, every function in a standard class has the explicitly-declared parameters sent to it, as well as every member variable. This can reduce verbosity (no need to explicitly pass in the majority of data being used) but can also obfuscate the data being functionally used.
Sophisticated IDEs will eliminate this problem--they can present all the data a function is actually using concisely, and use that information in compilation.
Should functions be explicitly tied to classes, or can they stand alone as occupants in a system?
Strategy pattern. It works. If you don't accept this, you probably work in a terminal and refuse to accept that better development tools exist.
Both of these approaches are Turing-complete. Both can organize in most any way a developer wishes, as long as they can think in the right abstractions. Object-oriented programming is a highly-pragmatic approach to modern programming that trades mathematical purity for organizational clarity.
These paradigms evolve with hardware, however. We will see a return to something more similar to functional programming as our hardware begins to evolve, but that does not necessitate the abolition of useful organizational patterns--it simply requires densely reflective languages, powerful optimizing compilers, and hardware that isn't burdened by the replication of data.
We won't always be using Von Neumann computers. Even Von Neumann knew this.
For all the vitriol and dogma surrounding these two approaches to programming, there are only three core I consider genuinely important:
- Should one allow functions to modify state information, or merely return a value?
- Should one allow functions to access information not directly passed to them?
- Should functions be explicitly tied to classes, or can they stand alone as occupants in a system?
Should one allow functions to modify state information, or merely return a value?
At the heart of this question is the concept of consistency. Should functions be permitted side effects? Arguably, this is the source of most instability in programs: the program enters an unexpected state as a result of functional side-effects and can no longer operate properly.
From a performance perspective, there's a lot of good reason to permit inter-function state modifications: it prevents the creation of an abundance of temporary values that need to be held in memory. From a mathematical perspective, it's just allowing noise into the system. Ultimately, these side-effects are a relic of modern hardware: The Von Neumann bottleneck makes frequent creation of temporary variables incredibly expensive. This is a by-product of the fact the modern architectures separate programs from data. This will change as our approaches to computing change: a well-designed quantum system will require no side-effects, since these intermediary calculations can be processed synchronously and in a highly-optimized fashion (multiple calculations on the same machinery at the same time, something currently impossible); a well-designed biocomputational system will contain densely-linked side effects, such that every function affects all others.
Should one allow functions to access information not directly passed to them?
This is largely a question of syntax, really. Effectively, every function in a standard class has the explicitly-declared parameters sent to it, as well as every member variable. This can reduce verbosity (no need to explicitly pass in the majority of data being used) but can also obfuscate the data being functionally used.
Sophisticated IDEs will eliminate this problem--they can present all the data a function is actually using concisely, and use that information in compilation.
Should functions be explicitly tied to classes, or can they stand alone as occupants in a system?
Strategy pattern. It works. If you don't accept this, you probably work in a terminal and refuse to accept that better development tools exist.
Both of these approaches are Turing-complete. Both can organize in most any way a developer wishes, as long as they can think in the right abstractions. Object-oriented programming is a highly-pragmatic approach to modern programming that trades mathematical purity for organizational clarity.
These paradigms evolve with hardware, however. We will see a return to something more similar to functional programming as our hardware begins to evolve, but that does not necessitate the abolition of useful organizational patterns--it simply requires densely reflective languages, powerful optimizing compilers, and hardware that isn't burdened by the replication of data.
We won't always be using Von Neumann computers. Even Von Neumann knew this.
Publishing Research in Academia (ReLooper)
Like any institution, universities struggle to establish a meritocracy, to offer staff recognition correspondent to their academic success. This challenge takes two forms: how do you reward success, and how do you recognize it? While the former is an interesting institutional question, the latter I am far more concerned with. The criteria they establish for determining staff's contributions became a key focus for the staff itself.
The method you use to evaluate professors determines what they will do. When a university prioritizes the number of publications made, then researchers will adjust their approach to publish a maximum amount of papers. When a university prioritizes impactful contributions, researchers will try to maximize impact.
Each discipline faces its own challenges of publication and reward, but few are as damaging and avoidable as those in computer science. The accusation? Disposable projects. Effort that could easily become something, but don't. Great ideas that go nowhere, because there is no incentive to make them go anywhere. Computer science is still struggling to adapt to its own power, and many inefficient institutional constructs have yet to be replaced by better ones.
In order to help shepherd along this progress, I've decided to bring some ideas back from the not-so-distant future, interviewing Alice Feldman, Public Relations and Research Promotion (PRRP) Officer for the University of Illinois department of Computer Sciences in the late 2010s.
Kurt: It's great to be speaking with you, Alice.
Feldman: It's always great to have an opportunity to be heard.
Kurt: So can you briefly discuss the scope of your position?
Feldman: Certainly. I'm in charge of the PRRP office at the university's CS department. Basically, I help get the work done here at the university out in the open. I keep businesses up-to-date on our research, find collaborators, research online communities, just try to be sure that our efforts propagate as thoroughly and widely as possible.
Kurt: So how old is this position, and when did it come into being?
Feldman: Our office has been open now for 5 years, me being the second officer. The University recognized that Computer Science simply had many opportunities not found in other disciplines, and was being held back by traditional publishing. In science, you spend your hours gathering data, and though others may try to verify your experiment, very rarely does the data itself see a second functional life. But the work our professors do here--their effort, their research, effectively is completely reusable.
Kurt: Your referring to programs, proofs-of-concept?
Feldman: Exactly. So much of the effort done in this discipline can be immediately applied, and built off of. We found that too often, we'd have some fascinating research papers or dissertations that would simply be thrown out once it was finished. Not only were we limiting our ability to impact the discipline, but we were limiting our opportunities to get the University's name out.
Kurt: Any examples?
Feldman: Well, any time someone thinks "Java concurrency" now, they immediately think University of Illinois. Prof. Danny Dig has done some fascinating work in this area. For years, that work was severely impaired in its impact... some ideas made their way into the language or its tools, but most simply faded away, made irrelevant as soon as the platform took a step forward. So we make sure that his work is incorporated into well-known public libraries, and make sure to commit the manpower to maintain that work. We make sure all our faculty's research is as accessible as possible, and consequently, people use it. Professors get their names out, the University gets its name out, the field advances.
Kurt: Computer science has been around for many, many decades now. Why do you think your type of work took so long to take off?
Feldman: Part of that is tradition--it takes time to change the way people think. But, more importantly, it strongly correlated with the growth of the open source community. Researchers needed a platform into which to integrate their work, users to use it, developers to improve upon it, and projects with enough respect to give the effort significance, pride. At this point, there are enough users of this kind of software to make contributing worth the time, to give the University numbers worth bragging about.
Kurt: Numbers?
Feldman: We have hundreds of thousands of developers using hundreds of contributions from our professors, running collectively on billions of dollars of equipment. There's no reason to wait for someone else to implement your idea any more, when its so easy to let them improve it instead.
Kurt: Interesting stuff. We're about out of time, but thank you for taking the time to talk to me.
Feldman: It's my job. And it's technically your job, too, you know?
The method you use to evaluate professors determines what they will do. When a university prioritizes the number of publications made, then researchers will adjust their approach to publish a maximum amount of papers. When a university prioritizes impactful contributions, researchers will try to maximize impact.
Each discipline faces its own challenges of publication and reward, but few are as damaging and avoidable as those in computer science. The accusation? Disposable projects. Effort that could easily become something, but don't. Great ideas that go nowhere, because there is no incentive to make them go anywhere. Computer science is still struggling to adapt to its own power, and many inefficient institutional constructs have yet to be replaced by better ones.
In order to help shepherd along this progress, I've decided to bring some ideas back from the not-so-distant future, interviewing Alice Feldman, Public Relations and Research Promotion (PRRP) Officer for the University of Illinois department of Computer Sciences in the late 2010s.
Kurt: It's great to be speaking with you, Alice.
Feldman: It's always great to have an opportunity to be heard.
Kurt: So can you briefly discuss the scope of your position?
Feldman: Certainly. I'm in charge of the PRRP office at the university's CS department. Basically, I help get the work done here at the university out in the open. I keep businesses up-to-date on our research, find collaborators, research online communities, just try to be sure that our efforts propagate as thoroughly and widely as possible.
Kurt: So how old is this position, and when did it come into being?
Feldman: Our office has been open now for 5 years, me being the second officer. The University recognized that Computer Science simply had many opportunities not found in other disciplines, and was being held back by traditional publishing. In science, you spend your hours gathering data, and though others may try to verify your experiment, very rarely does the data itself see a second functional life. But the work our professors do here--their effort, their research, effectively is completely reusable.
Kurt: Your referring to programs, proofs-of-concept?
Feldman: Exactly. So much of the effort done in this discipline can be immediately applied, and built off of. We found that too often, we'd have some fascinating research papers or dissertations that would simply be thrown out once it was finished. Not only were we limiting our ability to impact the discipline, but we were limiting our opportunities to get the University's name out.
Kurt: Any examples?
Feldman: Well, any time someone thinks "Java concurrency" now, they immediately think University of Illinois. Prof. Danny Dig has done some fascinating work in this area. For years, that work was severely impaired in its impact... some ideas made their way into the language or its tools, but most simply faded away, made irrelevant as soon as the platform took a step forward. So we make sure that his work is incorporated into well-known public libraries, and make sure to commit the manpower to maintain that work. We make sure all our faculty's research is as accessible as possible, and consequently, people use it. Professors get their names out, the University gets its name out, the field advances.
Kurt: Computer science has been around for many, many decades now. Why do you think your type of work took so long to take off?
Feldman: Part of that is tradition--it takes time to change the way people think. But, more importantly, it strongly correlated with the growth of the open source community. Researchers needed a platform into which to integrate their work, users to use it, developers to improve upon it, and projects with enough respect to give the effort significance, pride. At this point, there are enough users of this kind of software to make contributing worth the time, to give the University numbers worth bragging about.
Kurt: Numbers?
Feldman: We have hundreds of thousands of developers using hundreds of contributions from our professors, running collectively on billions of dollars of equipment. There's no reason to wait for someone else to implement your idea any more, when its so easy to let them improve it instead.
Kurt: Interesting stuff. We're about out of time, but thank you for taking the time to talk to me.
Feldman: It's my job. And it's technically your job, too, you know?
Tuesday, October 6, 2009
KDE: When the Bazaar Sets of to Build Cathedrals
First, a piece of dated Linux humor... one man's depiction of the KDE and Gnome development processes, circa 2002:
In many ways, the joke illuminates how far these two environments have come, reflecting the growth of the open source community itself over the past decade. At this point, both Gnome and KDE are sophisticated, fully-featured desktop environments with large, well-organized development communities. Even though the open source movement has been around since the late 80s, it continues to grow, learning (as a whole) to address increasingly complex products in an increasingly coordinated fashion.
The joke was written in the early KDE days, when it could be sustained by just a few dozen developers, and truly was a well-coordinated product. As the complexity of the system increased, its cohesiveness began falling. Throughout the mid-2000s, the system suffered from a glut of features and lack of focus. With time, they've regained their composure, now boasting over 400 active developers:
This is a project currently on par with many enterprise systems in terms of size. As Till Adam and Mirko Boehm discuss in When the Bazaar Sets Out to Build Cathedrals, the primary factor determining the growth an open source system is their ability to bring in active developers; in turn, this ability is proportional to the maintainability of code, encouraging a cleanliness of design rarely found in corporate environments. Entire sections of code can be scrapped to meet the community's needs. Furthermore, extensive effort is consistently made to have the software interact well with other systems (KDE's data access is designedto be accessed by other environments, such as Gnome). Though these decisions are challenging for any development group to make, open projects have more incentive and fewer structural roadblocks.
As software becomes ever more complicated, this development model becomes increasingly important. Incredibly large projects require a coordination and developer community outside the scope of all but a few organizations. For example, though Red Hat only employs a few hundred developers, they can release an operating system containing approximately 60,000 man-years of effort, the equivalent of a $10.8 billion project. Simply put, open source can scale very, very well.
The history of the KDE project reflects a slow, but steady sea change in the way software is developed and organized.
KDEA big room somewhere in Europe with lots of chrome and glass and a great big whiteboard in the front with lots of tiny, neat writing on it. There are about 50 desks, each with headphones and pristine workstations, also with a lot of chrome and glass. The faint sound of classical music permeates the room, accompanying the clicky-click of 50 programmers typing or quietly talking in one of the appropriately assigned meeting areas. (Which of course consist of elegant contemporary white pine coffee tables surrounded by contemporary white pine and fine leather meeting chairs.) Coffee, tea, mineral water and fruit juices are available in the break area.
At the end of the day, everyone checks in their code and the project leader does a "make" just to make sure it all compiles cleanly, but it's mostly only done from tradition anymore since it always compiles cleanly and works flawlessly. When all milestones have been met, and everything has been QA'd, (usually within a day or two of the roadmap that was written up 18 months previous) a new KDE release is packaged up and released to the mirror sites with the appropriate 24-hour delay for distribution before being announced.
KDE developers are generally between the ages of 16 and 25, like art made of lines and squares and the colors white and black. When/if they finally stop taking government subsidies and get around to getting "real jobs," most of their salary will be taken in taxes so the socialist government can subsidize the care and feeding of the next generation of KDE developers, just like it did for them. A high percentage of KDE developers, during their mandatory 5 years of government military service, crack from their years of cultural dullness and flee Europe to become terrorists for the sheer joy to be found in killing random strangers for no discernible reason.
GNOMEAn abandoned warehouse in San Francisco, kitted up as for a rave, electronica playing at 15db louder than "my ears are bleeding and I'm developing an aneurism" volumes and the windows all painted over black so that the strobe and spotlights and lasers can be seen better. Computers, mainly made of whatever stuff has been exchanged for crack or scavenged from dumpsters behind dot-bombs, are scattered around on whatever furniture is available, which also consists of whatever stuff has been exchanged for crack or scavenged from dumpsters behind dot-bombs. There's no break area, but you may be able to bum a beer (or more likely something harder) off of one of the developers hanging around, and they will probably be too jacked up on X, coke, acid, heroin, ether or all of the above to notice that you've taken anything.
Development strategies are generally determined by whatever light show happens to be going on at the moment, when one of the developers will leap up and scream "I WANT IT TO LOOK JUST LIKE THAT" and then straight-arm his laptop against the wall in an hallucinogenic frenzy before vomiting copiously, passing out and falling face-down in the middle of the dance floor. There's no whiteboard, so developers diagram things out in the puddles of spilt beer, urine and vomit on the floor.
At the end of the day - whenever that is since an equal number of programmers will be passed out at any given time - or really whenever someone happens to think of it (which is rarely), someone might type "make" on some machine somewhere, with mixed results. Generally nothing happens, so he/she shrugs his/her shoulders and wanders off to look for someone who might have more pink/black-striped pills. Once in a great while, generally in the unpleasant time between the come-down from the last thing they took and before whatever it was they took just now comes on fully, someone will tar up a bunch of random files and post it on a website someplace it as the next GNOME release, usually with a reference to some kind of monkey.
GNOME developers rarely live past 25 and prefer "alternative" art - generally stuff made of feces that's "too edgy" for most people to "understand" or "like." Core GNOME developers are heavy Ketamine users. The bodies of GNOME developers can often be found in dumpsters or floating face-down in any sufficiently large body of water.
In many ways, the joke illuminates how far these two environments have come, reflecting the growth of the open source community itself over the past decade. At this point, both Gnome and KDE are sophisticated, fully-featured desktop environments with large, well-organized development communities. Even though the open source movement has been around since the late 80s, it continues to grow, learning (as a whole) to address increasingly complex products in an increasingly coordinated fashion.
The joke was written in the early KDE days, when it could be sustained by just a few dozen developers, and truly was a well-coordinated product. As the complexity of the system increased, its cohesiveness began falling. Throughout the mid-2000s, the system suffered from a glut of features and lack of focus. With time, they've regained their composure, now boasting over 400 active developers:
This is a project currently on par with many enterprise systems in terms of size. As Till Adam and Mirko Boehm discuss in When the Bazaar Sets Out to Build Cathedrals, the primary factor determining the growth an open source system is their ability to bring in active developers; in turn, this ability is proportional to the maintainability of code, encouraging a cleanliness of design rarely found in corporate environments. Entire sections of code can be scrapped to meet the community's needs. Furthermore, extensive effort is consistently made to have the software interact well with other systems (KDE's data access is designedto be accessed by other environments, such as Gnome). Though these decisions are challenging for any development group to make, open projects have more incentive and fewer structural roadblocks.
As software becomes ever more complicated, this development model becomes increasingly important. Incredibly large projects require a coordination and developer community outside the scope of all but a few organizations. For example, though Red Hat only employs a few hundred developers, they can release an operating system containing approximately 60,000 man-years of effort, the equivalent of a $10.8 billion project. Simply put, open source can scale very, very well.
The history of the KDE project reflects a slow, but steady sea change in the way software is developed and organized.
Refactoring Sequential Java Code for Concurrency
As programmers, we have an innate understanding of the power of computation. I would estimate that more effort has been made on developer's tools and libraries than any other singular domain. We make programs to help us program. It's a challenge we understand.
From a strictly technical standpoint, any job that a programmer can do, a program can do, given sufficient understanding of the problem. Highly-technical problems in particular lend themselves to automation. The Concurrencer prototype is a recent example of this: an Eclipse-based refactoring tool to automatically multi-thread recursive Java functions.
It seems to do a reasonably good job of performing some code translations, and can catch many issues that a developer might miss. Theoretically, these tools can be very useful going forward.
But I have two major objections with this tool, neither of which are technical in nature:
If researchers are hesitant to take these measures because they are time-consuming, there's no reason not to off-load that work to grad students. Whatever measure, the usefulness of a tool is generally proportional to its community. Why not build a community around your ideas?
From a strictly technical standpoint, any job that a programmer can do, a program can do, given sufficient understanding of the problem. Highly-technical problems in particular lend themselves to automation. The Concurrencer prototype is a recent example of this: an Eclipse-based refactoring tool to automatically multi-thread recursive Java functions.
It seems to do a reasonably good job of performing some code translations, and can catch many issues that a developer might miss. Theoretically, these tools can be very useful going forward.
But I have two major objections with this tool, neither of which are technical in nature:
- If you want your tool to be used, host it somewhere visible: First off, this is an Eclipse plug-in, and should have an update site. Eclipse provies some simple tools to enable this. It's an easy way to get more people to use your program. Also, there have to be better places to host a project than a personal university web page--those are prone to disappearing with IT upgrades.
- If you want your tool to improve, make the source public: I understand this is a research paper, and the authors may want to keep the code private until they publish a paper on it. But once the paper is published, there's no good reason to keep the code private. I can download the .jar and decompile the bytecode anyway, so why add hurdles? Host it on SourceForge. It'll attrack more interest in your work. Hey, it's not even so hard to host an Eclispe update site on SourceForge. The paper discusses an assortment of potential enhancements to the tool that I suspect the authors will not have time to implement themselves. Why not make it easy for others to build off your work?
If researchers are hesitant to take these measures because they are time-consuming, there's no reason not to off-load that work to grad students. Whatever measure, the usefulness of a tool is generally proportional to its community. Why not build a community around your ideas?
Thursday, October 1, 2009
Fork/Join Parallelism
Early programming was highly dependent upon the underlying hardware. Programmers would manipulate data on what was effectively a register-by-register basis, executing [relatively] simple assembly commands to alter the information. With increasing computational power has come higher levels of abstraction, slowly freeing developers from the complexities of hardware, allowing effort to be focused on higher-level concerns.
Working with a modern, managed, programming language, one no longer needs to worry about assembly, about memory allocation or destruction, about paging or class loading, or a host of problems stemming from the operation of lower abstraction layers. This seems an inevitable, and generally beneficial trend. Developers can focus more on the busines problem and less on the technical.
In many ways then, modern parallel programming seems like a step back. Developers are being asked to consider aspects of the hardware they were previously able to ignore (the number of CPUs) and aspects of the data they were previously able to ignore (the relationship betweeen data members necessary for synchronization). Currently, many of our development models are heavy-handed: thread creation and signaling is a comprehensive, though highly error-prone coding style. The predominant abstraction--threading--often entails substantial computational overhead.
An alternate abstraction is a task-based view, often utilized in a fork/join framework. Under this methodology, a developer constructs independent tasks that can be sent to a queue to be processed by a worker thread. The threads themselves represent interfaces to processors and can operate independently of the developer's code.
This has one main advantage and one main disadvantage: on the upside, this method can spawn an optimum number of worker threads for a given system, whereas a traditional thread model entails however many functional threads a developer can identify. Furthermore, since the threads are permanent, there isn't substantial overhead in their creation and destruction. For many concurrent problems, this is an ideal approach, abstracting away the hardware again and simplifying the logical interdependency.
This simplification also reveals its weakness--or perhaps more appropriately, its limitation. For this model to work, each task or work unit must be completely functionally independent. On one hand, this limitation still meets the needs of many (perhaps most) problems requiring heavy parallelism. And unless the computational demands of a program are particularly high, then parallelism shouldn't necessarily be a chief concern. But as I stated, this is a limitation, and there are some types of thread behavior that this prohibits, particularly if multiple threads are dynamically modifying the same data.
Originally, I'd set out to interview Henry Ford, who is in many ways the godfather of modern parallelism: he is the man who optimized the execution of tasks by best mapping it to the available hardware (in this case, manpower). Unfortunately, I only was able to reach his secretary who informed me that "Mr. Ford isn't taking calls from the future. He considers the future too bombastic." Very well. I'd probably spend most of the time whining about Detroit anyway.
Working with a modern, managed, programming language, one no longer needs to worry about assembly, about memory allocation or destruction, about paging or class loading, or a host of problems stemming from the operation of lower abstraction layers. This seems an inevitable, and generally beneficial trend. Developers can focus more on the busines problem and less on the technical.
In many ways then, modern parallel programming seems like a step back. Developers are being asked to consider aspects of the hardware they were previously able to ignore (the number of CPUs) and aspects of the data they were previously able to ignore (the relationship betweeen data members necessary for synchronization). Currently, many of our development models are heavy-handed: thread creation and signaling is a comprehensive, though highly error-prone coding style. The predominant abstraction--threading--often entails substantial computational overhead.
An alternate abstraction is a task-based view, often utilized in a fork/join framework. Under this methodology, a developer constructs independent tasks that can be sent to a queue to be processed by a worker thread. The threads themselves represent interfaces to processors and can operate independently of the developer's code.
This has one main advantage and one main disadvantage: on the upside, this method can spawn an optimum number of worker threads for a given system, whereas a traditional thread model entails however many functional threads a developer can identify. Furthermore, since the threads are permanent, there isn't substantial overhead in their creation and destruction. For many concurrent problems, this is an ideal approach, abstracting away the hardware again and simplifying the logical interdependency.
This simplification also reveals its weakness--or perhaps more appropriately, its limitation. For this model to work, each task or work unit must be completely functionally independent. On one hand, this limitation still meets the needs of many (perhaps most) problems requiring heavy parallelism. And unless the computational demands of a program are particularly high, then parallelism shouldn't necessarily be a chief concern. But as I stated, this is a limitation, and there are some types of thread behavior that this prohibits, particularly if multiple threads are dynamically modifying the same data.
Originally, I'd set out to interview Henry Ford, who is in many ways the godfather of modern parallelism: he is the man who optimized the execution of tasks by best mapping it to the available hardware (in this case, manpower). Unfortunately, I only was able to reach his secretary who informed me that "Mr. Ford isn't taking calls from the future. He considers the future too bombastic." Very well. I'd probably spend most of the time whining about Detroit anyway.
The Future of Emacs
A confession: I have always been a VI man.
A further confession: I have never been a very good one.
The very thing that alienated me from Emacs is perhaps its greatest strength: its boundless flexibility. Emacs is designed in such a way that a feature can be added without a substantial architectural learning curve. Despite the sheer breadth of functionality the program has grown to encompass, at base, it is a relatively simple program: it is a text-editor with plug-in support.
So why VI over Emacs? And will either of these programs be around in 50 years?
When I was originally learning VI, I recognized it as a dated technology. It's a fantastic tool for working in a terminal, but is outshined by a host of editors in a modern, windowed environment. I chose VI over Emacs because I wanted to be able to work in terminals, not because I wanted to learn a sophisticated IDE; simply put, VI is basically the same on any *nix machine, Emacs isn't. VI is a skill that doesn't vary machine-to-machine. Emacs keywords and features vary by release.
VI is useful but losing purpose with time. In the long run, will Emacs' flexibility save it from irrelevancy? To answer these questions, I shot off to 2059, explored the Emacs dev-sphere and had a quick holo-con with 70-year-old project maintainer Jerry "Wildebeest" Gorman.
Kurt: I have to say, it's stunning to see how long the Emacs project has lasted. Could you describe some of the changes to the system in the last 50 years?
Gorman: Oh, it's been incredibly active. We've optimized our algorithms for quantum architecture, we've integrated ASCII-video translation features so video streams can be rendered as stacked layers of colored ASCII text, we've worked on enhanced session concurrency, so a hundred users can share thousands of frames efficiently, we've--
Kurt: Are any of these developments unique to Emacs though?
Gorman: What do you mean?
Kurt: I mean, can Emacs do anything that other IDEs aren't doing right now?
Gorman: Well, it's written in Lisp, which is--
Kurt: So?
Gorman: And it's free as in speech.
Kurt: Plenty of other things are as well.
Gorman: And it has a small memory footprint.
Kurt: Don't you have petabyte QRAM chips now?
Gorman: And it--
Kurt: Can't you just admit that this is all nostalgia and outdated skills?
Gorman: No, it's totally about--
Kurt: What!? Do you still check your e-mail with Pine too?
Gorman: Yeah, what about it?
Kurt: Gah!
To all readers curious as to the future of Emacs, I apologize for hosting such an embarrassing interview. I just often feel like developers deny the real reasons for their habits. Anyway, Emacs does offer some valuable lessons to modern developers, even if the platform itself is old:
A further confession: I have never been a very good one.
The very thing that alienated me from Emacs is perhaps its greatest strength: its boundless flexibility. Emacs is designed in such a way that a feature can be added without a substantial architectural learning curve. Despite the sheer breadth of functionality the program has grown to encompass, at base, it is a relatively simple program: it is a text-editor with plug-in support.
So why VI over Emacs? And will either of these programs be around in 50 years?
When I was originally learning VI, I recognized it as a dated technology. It's a fantastic tool for working in a terminal, but is outshined by a host of editors in a modern, windowed environment. I chose VI over Emacs because I wanted to be able to work in terminals, not because I wanted to learn a sophisticated IDE; simply put, VI is basically the same on any *nix machine, Emacs isn't. VI is a skill that doesn't vary machine-to-machine. Emacs keywords and features vary by release.
VI is useful but losing purpose with time. In the long run, will Emacs' flexibility save it from irrelevancy? To answer these questions, I shot off to 2059, explored the Emacs dev-sphere and had a quick holo-con with 70-year-old project maintainer Jerry "Wildebeest" Gorman.
Kurt: I have to say, it's stunning to see how long the Emacs project has lasted. Could you describe some of the changes to the system in the last 50 years?
Gorman: Oh, it's been incredibly active. We've optimized our algorithms for quantum architecture, we've integrated ASCII-video translation features so video streams can be rendered as stacked layers of colored ASCII text, we've worked on enhanced session concurrency, so a hundred users can share thousands of frames efficiently, we've--
Kurt: Are any of these developments unique to Emacs though?
Gorman: What do you mean?
Kurt: I mean, can Emacs do anything that other IDEs aren't doing right now?
Gorman: Well, it's written in Lisp, which is--
Kurt: So?
Gorman: And it's free as in speech.
Kurt: Plenty of other things are as well.
Gorman: And it has a small memory footprint.
Kurt: Don't you have petabyte QRAM chips now?
Gorman: And it--
Kurt: Can't you just admit that this is all nostalgia and outdated skills?
Gorman: No, it's totally about--
Kurt: What!? Do you still check your e-mail with Pine too?
Gorman: Yeah, what about it?
Kurt: Gah!
To all readers curious as to the future of Emacs, I apologize for hosting such an embarrassing interview. I just often feel like developers deny the real reasons for their habits. Anyway, Emacs does offer some valuable lessons to modern developers, even if the platform itself is old:
- Keeping the system open and easily flexible can grant it a long, rich life: A program need not be open-source to maintain an active development community, but should grant developers access to anything they could want to change. Winamp is an outstanding example of a closed-source program that maintained a very active development community. It gave users the ability to modify its appearance, its inputs, outputs, and to create new windows and features. The end result was a product that was heavily used for years. Though Winamp offers a cautionary lesson: by remaining closed source, you increase the chances of a product dying a slow death, since its longevity (and legal ownership) depend on the whims of someone other than the developer--in Winamp's case, AOL.
- Simple interfaces can encourage complex development: Keeping the bar to entry low can keep people interested. Emacs was easy to add-on to, and so many people learned to add to it. This can either be done by defining well-structured, simple interfaces, or (more dangerously) by keeping most of the program's data flatly structured. Firefox takes something of a hybrid approach, defining interfaces for various layout information, but keeping the data itself (including settings and page trees) "flat" and global.
- Maintain a good way to publicize user's contributions: In the case of Emacs, maintained packages are kept in the program itself. Because these features are most often accessible by keystroke combinations, they don't cloud up screen space and because Emacs is a terminal program, they're not very large. Many modern projects maintain web pages dedicated to their add-ons. Winamp and the Mozilla projects are particularly good about this. Eclipse offers a well-centralized update utility, but lacks a good central resource. Consequently, fewer minor changes get published, which potentially are slowing down the growth of the platform. There are many outstanding, large contributions, but minor 3rd party enhancements are rare in the Eclipse ecosystem.
Subscribe to:
Posts (Atom)
