Hacker News new | ask | show | jobs
by seanmceligot 2744 days ago
I once had to write a program for a class didn't have access to a compiler. I wrote it all in notepad and double checked everything more thoroughly than I ever would have done otherwise. When I got the computer lab the compiler found one or two type-o's and the program ran perfectly the first time. The experience changed how I write code. It's worth trying out at least one time.
6 comments

When I was a kid, I learned Pascal from a book. We didn't even have a PC at home (it was the 80s) but my mother was a college professor and had access to the mainframe there. I wrote out a whole program to run Conway's Game of Life on a bunch of notebook paper, and one day when I was off from school I came in and typed the whole thing in at a terminal. I ran the command to compile it, and it spit out hundreds of syntax errors. Then it was time to go home.

It was not an auspicious start to my career in computer science.

That's how I learned C. I bought a copy of K&R, but didn't have access to a Unix system with a C compiler for about a month (when my new job started). I read the book and wrote out all the exercises in a notebook.

When it came time to try my code, I spent a while correcting some basic misconceptions that I had developed but that hadn't been corrected by an actual compiler.

> It was not an auspicious start to my career in computer science.

I'd argue the opposite!

Learning how to "run" code in your head, cover edge cases and invariants, is a great skill to practice. When I was at a hospital after a difficult operation, I used to write down pages and pages of C64 programs in my notebook, too :-)

Even if I never even typed all them out later, I like to think this made me a better programmer. It trains your brain in a way that REPL doesn't.

I sometimes worry that I've become REPL-dependent.
I used to sit in my grade 12 English class working out polygon fill-and-shade routines on graph paper instead of whatever nonsense Shakespeare we were going through at the time.

Worked out really well for me - I'm employed well as a programmer, and I got to come to Shakespeare basically fresh when I was old enough to actually appreciate the work.

How old is that? I'm over 50 and I still can't get into Shakespeare. Watching a performance is OK, though not something I'd choose to do on my own, but reading the plays? Can't get into it at all.
Have you tried an annotated one? Shakespeare is full of, essentially, in-jokes and memes from the 1500s. There is a ton of depth in his writing that you'll totally miss if you don't know all of that context.
Also, lots of bawdy humor that gets glossed over by staid and respectable modern productions. For example: the "bite your thumb" gesture that gets used in a few plays is pretty much the equivalent of somebody from today giving a double middle finger while sticking their tongue out.
Try watching a movie version - I really like Branagh's Hamlet and I never expected to (long though)
Try the "Sonetts" instead of the plays!
Just program.
I originally learned to program in 6502 machine code. Typically I would write code in spiral notebooks while watching the late late late show and hexkeypad it in afterwards. made it a little easier to edit things that way...
To me, this is one way to show evidence of mastery of an engineering discipline: The ability to do it once and have it come out right. If you asked a modern software engineer who's used to fast modern tools, they'd tell you this was impossible. Everyone's pretty much settled into this kind of workflow:

Write -> Compile -> Fix Compile Errors -> Compile -> Fix Compile Errors -> Compile -> Fix Compile Errors -> Compile -> Run -> Fix Runtime Bugs -> Compile -> Run -> Fix Runtime Bugs -> Compile -> Run -> Fix Runtime Bugs -> Compile -> Run -> Fix Runtime Bugs -> Compile -> Run -> Fix Runtime Bugs -> Git Push and Pray

With maybe a few "Write Unit Tests" steps intermixed. Totally different mentality. Is it really a faster or more productive way to work?

Yes. A real feedback loop is better than a mental one in your head. “Turn off your targeting computer and use the force, Luke” only works if you hone a lot of mental power into it (like Knuth), but it would have also discouraged a lot more people without that ability from programming at all.

In the past you had to be Hawkeye to program, now most of us just put on our Ironman suit and get on with it.

Nevertheless, the more complete and accurate your picture of what you are attempting to achieve, and where you are, is (at every level of abstraction), the fewer iterations it will take to get done - or the fewer bugs remaining after a given elapsed time.

It's like situational awareness: https://en.wikipedia.org/wiki/Situation_awareness

The number one thing I try and build up for my teams is a mental picture of the entire system. It is amazing, to me, how much resistance I get to the idea.
The difference is other people.

Yes, if you're writing your -own- code, learning to envision what the system must do in your head first is very, very valuable.

When you're on a team, however, you -have- to compartmentalize. You have to create abstractions, black boxes, functionalities that you -could- dive into, but which you will accept only understanding at a contract (interface) level. The skill of envisioning the system is still useful, of course, but there will be black boxes.

The problem that causes, of course, is that every abstraction is leaky. You didn't know that calling this method also fired off this event, and so you -also- triggered that event. Or whatever. Hence, bugs and iteration. You also have to deal with -bad- interfaces, a bajillion parameters, or a parameter object that isn't intuitively obvious how to initialize, and you start having to iterate.

The problem is not just, or mainly, leaky abstractions - you can't make a system out of a collection of opaque abstractions. An important part of Knuth's genius is seeing deeply and clearly how they have to interact. Leaky abstractions are just one sort of problem that arises when this doesn't happen.
If we want to go there, modern tooling allows you to forget some of the details you used to care about and focus more on other things, the tooling is rarely comprehensive and there will always be more to consider until the entire programming process is automated.
As modern tooling chips away at the accidental difficulties of software development, systems-level situational awareness becomes relatively more central to the process.
Sort of. I've seen these productivity-enhancing tools used by people who have absolutely no clue what those tools are doing on their behalf produce some nightmares that sort of work sometimes. To get geekier with the analogy, a lot of people are like spiderman (the Tom Holland spiderman) who need to learn to use the powers of their suit before they're given access to the more powerful, more dangerous stuff.
Put an untrained person in a bulldozer and there will be a lot of damage.
>In the past you had to be Hawkeye to program, now most of us just put on our Ironman suit and get on with it.

This is an amazing metaphor, thank you for sharing!

It is much more impressive that Knuth came up with and wrote TeX than that it was bug-free or written all in his head.

Computer time is no longer at a premium and bugs can be fixed.

Useful, creative, and clear solutions usually trump perfectly correct ones, except in special cases such as when life is on the line or you're writing programs to fly to the moon where getting it right the first time is of utmost importance.

"Useful, creative, and clear solutions usually trump perfectly correct ones"

Actually I've found that the most useful solutions are those that are creative and clear.

But yeah, it totally depends what one is doing. Usually if the algorithm is mission critical and the component is mission critical you can weasel out enough time to make it right (so you don't have to return it to ever again and you get a reputation as a guy who's code just works).

In some domains it is, for example you won't create fun arcade game without iterating 1000s of times on the basics (control scheme, physics, etc). Often it isn't.

I learnt programming writing small games, so quick iteration is my first instinct, and I can see myself sometimes jumping to write code too quickly.

If Knuth worked on a large code base (e.g. Windows), I'm sure he'd have the exact same workflow.
Do you really encounter compiler errors that frequently? The compiler stopped barking at me for the most part after my first year or two.
During big refactorings, I admit I sometimes find myself relying on compiler errors as a crutch to find (for example) which API layer I haven’t added the parameter to yet.

I’ll also rely heavily on my IDE’s function signature completion, to remind me whether some method I’m calling takes an int or an unsigned int, rather than have it memorized like I used to.

This might be why a lot of people (including me) hate whiteboard-coding interviews: we’ve gotten so spoiled by our tools that we can’t code without them!

> During big refactorings, I admit I sometimes find myself relying on compiler errors as a crutch to find (for example) which API layer I haven’t added the parameter to yet.

That's not a 'crutch' - it's literally what those compiler errors are for! The alternative would be for the compiler to do something non-sensical, which would error out at runtime.

And when it comes to white-board coding, you should arguably be using pseudo-code anyway - your goal is then not to come up with something that will run, but to convince your interviewer that the code is 'morally' correct and that any subsequent fixes are well within your skill level.

My biggest problem with whiteboard coding is writing text in straight lines. You never realize how much of a liability being left handed is until someone asks you to do whiteboard coding (ya, many lefties train for this, but some don’t).

Computers have been a godsend for my penmenship. On the other hand, I guess I relied on them too much as a kid.

I thought lefties learn to read and write backwards and then mirror the final result before submission.
This might be why a lot of people (including me) hate whiteboard-coding interviews: we’ve gotten so spoiled by our tools that we can’t code without them!

Isn't that like someone saying they've gotten so spoiled by training wheels, they can't ride a bike without them? It's not like I'm one to talk 100% of the time. I think I couldn't get my company's project to build, without a few weeks of reading and understanding a lot more of the build system. However, I've also coded on an 8 bit machine by flipping 8 switches and pressing a commit button for each byte.

It's a worthwhile exercise to do some coding with nothing but a text editor and a debugger once in a while. That isn't going 100% to the bare metal, but it's a level that's very worthwhile for working on basic skills. Entire programming education books have been based on this idea.

The difference is that training wheels are intended to be a temporary assistance until you've learned to operate without them, while development tools are meant to be a productivity boost. If you're working with a toolchain and aren't leaning on it, you're not working to your full potential.

Whether being able to work without the chain is also important is an independent issue. (I happen to prefer vim+scripting languages over IDEs+compiled. But I recognize it as a personal preference, and not a question of moral superiority.)

The difference is that training wheels are intended to be a temporary assistance until you've learned to operate without them, while development tools are meant to be a productivity boost.

Right, but pro cyclists don't say they couldn't do it without piece of equipment X. X is just a performance boost. Some coders say they couldn't practically do it at all without X. There would be a big difference in fitness between a commuter being unable to make a certain trip without a motor assist, and a rider who could do the same trip without the motor assist. I think most would look askance at a "pro" in the 1st category.

If you're working with a toolchain and aren't leaning on it, you're not working to your full potential.

Yes, but you need to be wary that you're using the toolchain for its intended purpose. The toolchain is supposed to be saving you typing and lookup time. It's not supposed to be substituting for your actual understanding of the code. The former is a good thing, and you should be good at using the tool for that. The latter is a bad thing, and you shouldn't be doing that. By working out with nothing but an editor sometimes, you can work out in a way that guards against that.

No football player plays actual games running through tires, but the exercise is apparently helpful.

But I recognize it as a personal preference, and not a question of moral superiority.

It's not moral superiority. It's using tools as intended and not substituting for understanding.

It's like a lumberjack so used to cutting down trees with a chainsaw that they'd have trouble to put down a decent tree with an axe. Powerful tools do certain subtasks for you, if you expect to use them all the time (and it's a reasonable expectation in your domain), then it makes all sense that you'd forget these subtasks.

It's like manual memory allocation and proper deallocation - been there, done that, but after 10+ years of working with GC languages, I would definitely have some memory leak bugs if I suddenly had to do that again. It is a basic skill, but just as many other basic skills, it's one that you can ignore in most domains.

It's like a lumberjack so used to cutting down trees with a chainsaw that they'd have trouble to put down a decent tree with an axe.

Bad analogy. It's more like a "lumberjack" who thinks all it takes is pressing the controls on a chainsaw. There's some more, very important things to know, and not knowing them can cost time and money or even get someone badly hurt. The chainsaw has to be maintained, with possibly severe consequences if it isn't. You need to know how to get the tree to fall where it's supposed to. You have to know how to cut so the weight of the tree doesn't clamp the chain.

It's a bad analogy, because the important issue is whether someone is letting the tool substitute for understanding. I guess some rube might think their chainsaw is so powerful, they don't have to worry about how they cut down the tree. It's more like sailors who think they can just lean on GPS instead of having skills. Those are the guys who collide their ships and get people killed. It's more like pilots who weren't great student pilots, and they make critical mistakes and program the autopilot into the side of a mountain or do the wrong thing when the plane is stalling or always depend on the auto-landing system and don't really know how to do a manual landing and wreck the plane. (Those are all things that really happened.)

Just because some big fraction of time being a "professional" is just being an end user doesn't mean there isn't something more beyond that which is very important. I guess it just has to do with what level of "professional" you aspire to be.

It's like manual memory allocation and proper deallocation - been there, done that, but after 10+ years of working with GC languages, I would definitely have some memory leak bugs if I suddenly had to do that again. It is a basic skill, but just as many other basic skills, it's one that you can ignore in most domains.

If you're doing something hard enough, you still have to think about stuff like that in a GC environment. I know, because I worked for a Smalltalk vendor. You can even have memory leaks in a GC environment. There's a lot of stuff you can ignore -- most of the time -- but can come and bite you real hard if you're not prepared for it.

>During big refactorings, I admit I sometimes find myself relying on compiler errors as a crutch to find (for example) which API layer I haven’t added the parameter to yet.

Sure, I do the same. I wouldn't call it a 'crutch' though; it's just using the tools you have available to you.

> Do you really encounter compiler errors that frequently?

He skipped the "ctrl+enter" part of the workflow.

I know you probably exaggerated, but isn't causing so many feedback loops still the sign of a bad programmer?

I wouldn't trust someone to deliver quality software who produces multiple syntax and multiple runtime errors while coding, especially when modern IDE's fix typos on the fly? What about all the runtime errors he didn't test for?

Is that flow really that common?

Sure, I cause errors all the time, but my workflow includes a compile time error maybe once in 2 trys and an obviously fixable runtime error once in maybe 10 times. Sure there are these countless of edgecase errors I don't even know about, but that's not the thing catchable with this workflow and I wonder if someone with that workflow, who misses the obvious, does miss even more edgecases.

Also don't a lot of tech companies require (mostly) correct whiteboard coding exactly because of this for quite some time?

The ability to do it once and have it come out right.

One coworker of mine was the son of one of the engineers of the XC-142 tiltwing aircraft. He started a project to make a functional scale model, and this was before Arduino, so we decided to use a Gumstix Linux board. (Because of its generous number of GPIO outputs.) I wrote a bit-banging implementation of the flight surface control mixing in C. It "just worked." No errors. It just ran the 1st time. It was even flown on a simpler aircraft.

This isn't my usual way, however. Usually, I'm quite iterative. If you're going to write a program that works the 1st time, then it helps if the control flow is relatively simple, there isn't a lot of complexity that can come about with interaction with state, and it does just one thing.

There are individuals out there who possess sufficient cognitive capabilities such that they do not require much in the way of cognitive load mitigation tooling even when working on very complex and technical tasks.

These individuals are uncommon.

I had a similar experience! When I first learned programming, it was through a book I borrowed from a teacher, who would only let me access her computer once a week. So I basically wrote all the programs I wanted to write with pen and paper, and then typed them and ran them once a week. It definitely gave me a much thorough understanding of many algorithms, as I basically have to simulate execution on paper.
I got into this type of thinking/habit by working for a couple startups and programming live on prod...