Sunday, December 9, 2007

1, 2, n

It's the 1, 2, n rule in software development.

You do something once. You do something twice. And the next time you do it, you generalize it for all times henceforth.

Waiting longer to generalize is painful at best. In the worst case, it leads to maintenance nightmares as when the same thing is done 14 times in 14 different places, each time slightly different than the rest.

Generalizing too soon however leads to other problems. Everyone's done this at one point in their coding career or another. Hey, this is a great idea! Why hasn't someone else done it before? I'll code it completely general the first time around so that it'll be done right, from the start. And then a few weeks of coding go by, you start to actually use it, and you find out the hard way that either it was a really bad idea or the API is so terrible that you have to re-write it. Because basically, you didn't iterate your design.

Code is all about design. And good design is re-design.

This is a big part of the reason why programming languages are so far behind. The amount of work that it currently takes to create (a compiler for) a programming language is so high, that the time it takes for a language designer to get feedback on his design is years. But by that time (if he was lucky enough to actually get users), he's already invested so much into it that he is unlikely to throw it away and start from scratch — something a good designer must do. On top of that, even if he wanted to start from scratch, it would take many months to de-program his mind from thinking in the previous language. (Like the first time a Java programmer learns Haskell and tries to write a loop!)

An IDE is part of a language. Error messages are part of a language. Interacting with other systems, written in other languages, is part of a language. They're all part of the interface of the language. And the interface is everything.

It's a chicken-vs.-egg problem though. Because to get all these tools made, based on history, requires that a language be popular. But how do you get people to use a language if it doesn't have the most basic tools like a debugger?

JavaScript is doing it right now. JavaScript tools — which make using the language no longer so painful — are cropping up everywhere these days. And the way it did that was by being the only choice if developers want their code to be executed in a browser window. Most languages aren't so lucky. So what is a language designer to do?

As a designer, I can't simply make a command-line compiler for my language. I have a vision of what editing code is like. And it's not with a text-editor. The closest thing I've ever seen to a true code-editor is Eclipse for editing Java code, but Eclipse has been around long enough for us to learn a few lessons. I can already hear the Emacs junkies crying about how Emacs is the ultimate editor. But again, it's still a glorified text-editor.

A true code-editor must absolutely be aware of the semantics of the language you are editing. It is inseparable from the compiler. Because the compiler knows how to interpret your code, but when something is amiss, it must be able to feed back to the programmer.

Writing code is all about design. And a designer needs feedback — as much feedback as possible. The quicker he gets that feedback the better, because he can make any necessary changes to the design only after he's gotten feedback on his current design.

So any code-editor that doesn't give immediate feedback on parse errors and requires that you do a full build is simply crap! How can you possibly work like that?! Ditto for type errors, link errors, and test-assertion errors. People see it as obvious when the old-timers tell stories about how they used to submit compilation jobs to mainframes on punch-cards, only to find out the next day that they forgot a semicolon and had to re-submit the entire job. Yet when it comes to where we are, here and now, people are blind.

Frankly, I'm getting tired of it. I want to see test data flow through my code as I write it and the unit-test results change from red to green as I fix a bug. I want to be able to highlight two blocks of code and have my code-editor factor out a function, replacing the two blocks with applications. I want bottlenecks to be highlighted in-editor based on profiling results. And compilation should be done completely in the background so I don't have to wait after making a change to use it. And this read-eval-print-loop that's all the rage nowadays might actually be useful if I could use it in the context of a particular point of my code.

Is it really that hard? Someone please tell me I'm a visionary because I can't believe that this can't be done. Nothing a little universal substitution and computing power can't solve.


Larry Clapp said...

"And this read-eval-print-loop that's all the rage nowadays might actually be useful if I could use it in the context of a particular point of my code."

Many implementations of Common Lisp and Scheme (and probably other languages, too) allow this. My favorite so far is Lispworks Common Lisp.

As far as some of your other wants, they're hard, because unless your compiler writer also writes your editor (or puts *a lot* of hooks into the compiler where you can get a worm's-eye-view of what's going on), you have to re-implement most of the compiler in the editor so it can find all the errors you want. Not impossible, just lots more work.

BTW, really dislike that white-on-black style you've got going. Thank heaven Opera lets me disable it. :)

Jonathan Allen said...

Heavy-weight IDEs like Visual Studio are going that direction (VB has had a continuous background compiler for ages), but modern computers cannot handle the load.

Visual Studio requires 2 GB of ram to even think about running smoothly and even then the complexity causes it to crash way too often.

I see us getting to that point, but not any time soon.

Anonymous said...

A lot of this is possible, and a lot of this can be realized without a behemoth like Visual Studio. Part of what makes these tasks seem so intractable present day is bad compiler and IDE design, and part of it is bad language design. The biggest hurdle, however, is an entrenched culture of "roughing it" which permeates the disciplines of Computer Science and Software Engineering. But slowly we are seeing the light, and a field whose fruits have revolutionized other industries and fields is allowing itself, little by little, to help itself.

Anonymous said...

Also dislike the white on black, very hard to read, I don't think I'll be coming back, you hurt my eyes.

Anonymous said...

Good article but the white on black is too hard to read.

JS said...

Sounds like you want to work in the Smalltalk environment, where changes made provide instantaneous feedback about what is affected...

Watershawl said...

White on black is fine on my eyes. I like it.

Anonymous said...

actually, you can get immediate feedback on parse errors and compile errors in emacs. I don't think it's that useful because I tend to work better if I separate "composing" from "editing".

it's similar to when I'm writing prose. first, get as much of what's in my head written down as I can, keep going without corrections, maybe type with my eyes closed, try to get "flow". later, go back and revise with a critical eye.

instant gratification for testcase errors, I don't think that's been done yet for emacs, but it doesn't feel too hard either. the simple form is basically just adding another rule to your Makefile, and making sure the testcase error messages are parseable. then it fits right into the existing incremental-build machinery.

also, automatically popping up a debugger REPL at test failures is pretty straightforward for most languages.

(most of these remarks apply to eclipse as well as emacs, but I use emacs a lot more.)

javascript.. I haven't quite figured out a fast edit-test cycle yet. firebug helps a lot, but there isn't a simple way to propagate firebug-side changes back to the source code, so it's often faster to just edit at the source.

Anonymous said...

As JS said, what you want is smalltalk. Download squeak, and read "Squeak by Example." Use Damien's developer image, or use squeakmap and install Shout.

You have to run unit tests manually, but I suspect it wouldn't be hard to set them up to run whenever you save a method.


Anonymous said...

check out for some nifty thinking regarding test data flowing through your code

Anonymous said...

Hello. Someone had the same idea before you, but actually when ahead and implemented it. Take a look at this

Jon T said...

Wow! I've seen Subtext before and thought it was great, but I hadn't seen his latest video until just now.

What he demos is just beautiful. I can tell he is a true designer. You can even hear the Model M keyboard in the background. (This guy cares about interfaces!)

I admit, in many ways Subtext is beyond what I had imagined. In other ways, it's still missing a lot of essentials. Understandable though since it's so new.

One thing off the top of my head that I'd like to see which Jonathan Edwards doesn't go into is a keyboard interface for navigating and editing a source tree/graph. (Oh, he answers this question in his FAQs.)

I wish I could download it and play around with it.

Jon T said...

Larry, that is the idea. I think the compiler writer should write the editor as well.

Because the editor for a language is effectively the UI of it. And interface is everything.

Re-implementing the compiler in the editor is just silly, and if you're making "hooks", you're basically talking about an API. And that's great, as long as you treat it like an API. Not the commands for a command-line tool for example.

I have nothing against command-line except for the fact that it was never designed to be interactive. It was not designed for UIs with continuous feedback of the style I'm talking about.

kkl said...

Apple agrees with you. They're ditching GCC for LLVM compiler framework to have realtime parsing, access to syntax trees and be able to implement true refactoring browser.

Larry Clapp said...

@kkl: [citation needed] ;)

Jon T said...

Hacker News


...My first post to make it to the front page on both. I guess that means somebody's reading. :-)

Sean said...

You make some good points. I've reached similar conclusions about the
desirability of structured editing and a REPL that could "run inside a
lexical scope." Things like Subtext and Squeak have some elements of
this vision, but the trouble is that you can't cherry pick the
features you want; if you pick a language for its editing facilities
you're stuck with its object model and vice versa. Maybe the way
forward has to do with factoring programming environments in such a
way that they can be mixed and matched.

Do you have any plans to implement some of your ideas? I'm always
looking for like-minded individuals to bounce ideas off of.

Jon T said...

Sean, I definitely understand your desire to factor out the editing features you want, and not have them tied to the language. That would be ideal in the long-run.

Unfortunately, I don't think we're ready for that yet. I really want to see something innovative. And being practically the first time implementing such things, we should follow the 1, 2, n rule ;-) and not hastily make it as general as we can possibly imagine without trying it out first.

As for implementing something myself, your comment spawned an entire post on this subject.

Pär said...

Background compilation can be done in emacs with flymake

See it in action here:

I think letting the compiler writer do the editor would be disastrous. What's really needed is an extensible editor or framework such as Eclipse or Emacs so you can hook in support for stuff like this.