For me the most productive programming environments have always exhibited the same pattern. There’s something I think of as kernel space, something else I think of as user space, and most importantly a fluid boundary between them.
For example, my first programming job was writing application software for CD-ROM-based information systems. I wrote that software in a homegrown interpreted language inspired by LISP. The relationship between my software and the engine that powered the interpreter was a two-way street. Sometimes, when I’d find myself repeating a pattern, we’d abstract it and add new primitive constructs to the engine to make the application code cleaner and more efficient. At other times, though, we’d take constructs only available in the engine (kernel space) and export them into the interpreted language (user space). Why? Because user space wasn’t just me acting as a user of the kernel. It was also where the product we were building came into direct contact with its users. We needed to be able to try a lot of different things in user space to find out what would work. Sometimes when we got something working we’d leave it in user space. Other times we’d push it back into the kernel — again, for reasons of clarity and efficiency.
You see the same pattern over and over. In languages like Perl, Python, and Ruby there’s a fluid relationship between the core engines, written in low-level compiled languages, and the libraries written in the dynamic languages supported by the engines.
I realized today that the evolving fluid relationship between web servers and web clients is another example of the pattern. Early on you had to write web software for a server. Now the web client is ascendant and we can do incredible things in JavaScript. But for me, at least, the ascendant client in no way diminishes the server. Now that the two are on a more equal footing I feel more productive than ever.
In my case the server is Windows Azure, and the “kernel” of the system I’m building is written in C# (and a bit of Python). The client is the browser, and “user space” is powered by JavaScript. I’m finding that these two realms are intertwining in delightful ways. For example, one new feature required some additional data structures. Because they’re rebuilt periodically and cached it makes sense to have the server do this work. Initially the server produced a JSON file which the client acquired by means of an AJAX call. When the feature proved out, I decided to streamline things by eliminating that AJAX call. So now the server acquires the JSON and caches it as a C# object in memory. When the page loads the server converts the data back to JSON and makes it directly available to the client.
What about the fact that this arrangement involves two different programming environments? If that bothered me I could be using JavaScript on the server too. But I don’t feel the need. For me, C# is appropriate for kernel space and JavaScript is appropriate for user space. Which language powers which realm isn’t really the point, though. What matters is that the two realms exist and collaborate productively.