Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
A Double Handful of Programming Quotes (hackification.com)
27 points by joel_liu on Dec 26, 2008 | hide | past | favorite | 19 comments


"Measuring programming progress by lines of code is like measuring aircraft building progress by weight.”

    - Bill Gates
Every once in a while, I come across something new that surprises and impresses me about Bill Gates. If luck had fallen differently and Bill had become merely a millionaire, I think geeks would find him much, much cooler.


When I had a chance to meet the guy, these were the things that struck me, in order:

He looks really old, way older than he does in photos. Must be all the stress.

He's very, very good at thinking on his feet.

He's actually quite pleasant to interact with and has milder views than you might think. People who know him have told me that the aggressive, brash behavior was merely a persona that he deliberately cultivated as part of his management style.

(Incidentally, I've also interacted with RMS; he immediately came across as as a jerk. I can't help feeling that this has something to do with his project not reaching the heights that many feel it should have.)


RMS should by all rights be pretty happy: GNU replaced Unix on servers, and has made more progress on the desktop than Unix ever did.

I guess he never predicted that something that wasn't Unix would be the dominant OS. In essence, he chose the wrong enemy.

Can you imagine what the world would be like if RMS had created 'GNU's Not DOS' instead?


You mean 'GND's Not DOS' :)


I sure do. In fact I'd written GND in my mind. But much like trying to write 'Linus' and not 'Linux', you have to really concentrate not to follow capital g, capital n, with capital u. :^)


I think a lot of people agree with that sentiment. But why should he be hated for his business acumen?

If he was dirt poor would he be much, much, much cooler?


No, he'd be the same cool, but it wouldn't be occluded by the gargantuan thing that Microsoft has become. Like the Woz, we'd be able to hear more about Bill the engineer than Bill the billionaire.


That's why my Debian is fast, Bill: source code is on the server.


"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it."

But if you implement a DSL and associated debugging tools and other niceties you can write your code as cleverly as possible AND be smart enough to debug it because it's so easy. But beware of that phase where you have a nice language but very leaky without supporting tools because it hurts!


This is a tangent, but since I know you're a Lisp guy, I'd like to hear about how you go about debugging. Currently working in emacs/slime/sbcl, it's my one real complaint. Really all I want is a normal single-stepping debugger with the ability to view local state. That doesn't seem like such an inordinate desire, but I haven't seen any setup that comes close to it, which is annoying. My email address is in my profile if you'd care to compare notes about this.


I'm sorry, I don't really have any insightful perspective on debugging. But maybe I can elaborate a bit on what goes wrong if you make a new DSL without keeping in mind debugging considerations.

- You'll want to maintain a separate stack for your embedded DSL. It's really, really hard to debug when Lisp's stack and your DSL's get intertwined in a complex way in your stack trace. When I just had my straightforward HTML and CSS "closure-compilers" this wasn't such a big deal but when you make a language with more funky semantics where the order of evaluation is less obvious it's a real problem.

- When you compile something (say, your semantic representation of HTML into optimized closures), you should always keep the more semantic representation of what you're compiling around. As an example of this, at first I made a macro to directly generate Lisp code that generates HTML source code. That was bad because the only thing I could do with my HTML is output it.

But it turns out there are many things you can do if instead you make a macro that generates Lisp code that will build a semantic representation of HTML as Lisp objects: you can interpret it directly or optimize it or compile it directly or make a single-stepping debugger... The possibilities are limitless!

Also, to preserve semantics as much as possible I think a rewriting strategy is great. You start with your super abstract representation, and then you rewrite in successive steps to an ever more concrete and low-level representation until you're done. For example, in an HTML system you'd have a login-box object that rewrites to HTML lisp objects that rewrites to HTML source code. It would be great to have a way of linking the various pieces at the different semantics level. For example, having some feature Explain that when you point to a certain character in the HTML source, it could tell: "This character was generated as part of the value of the text attribute of a img node that was generated in that page because it's part of the sidebar that's in the template of this part of the site"... Anyway, what I mean is that sometimes you want to focus on the high-level semantics and other times on the low-level, and you should be able to switch contexts at will.

PS: I'm not even sure what exactly I was talking about anymore. Maybe I should start a blog...


That's very plausible, and your thoughts on intermediate representations are quite interesting. Now I'm going to change the subject back to my tangent. :)

Maybe it wouldn't be so "really, really hard to debug when Lisp's stack and your DSL's get intertwined in a complex way in your stack trace" if Lisp stack traces weren't so hard to debug in the first place. At least, they are for me. If anyone has any hints, please chime in. I'm getting tired of BREAK-and-FORMAT-driven-debugging. When Visual Studio does anything better than a Lisp environment, that's a goddamn emergency.

In the meantime, I think I'm going to try Clozure-with-a-Z and see if life is better.

p.s. If you do write a blog about this stuff, post it here. I'll read it.


You can debug Clojure-with-a-J code using JSwat. http://clojure.org/getting_started#toc5


Heh. That comes from the old Kids in the Hall characters Cathy-with-a-C and Kathy-with-a-K.

I'm probably not going to use Clojure any time soon, though am following it at a distance.


All problems in computer science can be solved by another level of indirection http://www.dmst.aueb.gr/dds/pubs/inbook/beautiful_code/html/...


I used to use debuggers, but never really liked them, and on languages with complex data structures they always seemed cumbersome to me. The last straw came when I had a C++ program with a memory leak -- which went away whenever i ran the program inside the debugger.

After that I stopped using a debugger. Here's what I do instead, in the hope that it may be helpful to you and others (I don't use Lisp, but most of this is relevant to all languages)...

What I use now instead of debuggers are unit tests. For every module, write a unit test. Ideally, write the test before the code. If you have modules or classes that're tightly coupled, write other tests that test how they work together. Then write one big test that runs all the other tests, starting first with modules that don't depend on other modules, then progressing to more complex functionality. In this way you can run the entire test suite easily.

Code your big test so that it writes a log of what it's doing to stdout, and also so it stops on the first error it encounters. (This is because you don't want to be burdened by thinking about more than one error at a time.)

You should endeavour that as you write your code, it passes 100% of the test suite all the time. (If you have to rework a whole section of code, you may have to comment out a series of tests for a time to do this.)

As you write the code, run the unit test after you add any functionality to the module. If the code affects other modules, run the entire test suite every time instead of the unit test. That way if your new code breaks some complex dependencies somewhere, you'll know instantly.

This means that your entire test suite should complex quickly -- at most a few tens of seconds -- or you'll be deterred from using it often enough. Obviously if your code is doing something very processor-intensive, you might not be able to do this.

The other thing I do is have a debug flag in each module which when set outputs debugging statements, typically when a function starts running, e.g:

   debug = true
   ...
   def foo(a, b):
      if debug: printf "called foo(a=%r,b=%r)" %(a, b) 
Finally, the golden rule is: never, EVER, make your code more complicated or harder to understand than it needs to be. Every time you break this rule, you cause more trouble for yourself later.


It's times like this when I am glad that I can read comments here instead of being stuck with the comments on the actual blog.


Not that this has much to do with the article, but I don't like "double handful." It's very awkward. How about . . . metric dozen! Because it's close to a dozen and works with metric's 10-ness.


Or, y'know, "ten".




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: